Skip to content

Commit b3f4c31

Browse files
committed
Auto merge of #99165 - matthiaskrgr:rollup-rqpelfa, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #97210 (Support `-A`, `-W`, `-D` and `-F` when running `./x.py clippy`) - #99055 (Fix rustdoc help options) - #99075 (Fix duplicated type annotation suggestion) - #99124 (Fix sized check ICE in asm check) - #99142 (fix(doctest): treat fatal parse errors as incomplete attributes) - #99145 (Don't rerun the build script for the compiler each time on non-windows platforms) - #99146 (Do not error during method probe on `Sized` predicates for types that aren't the method receiver) - #99161 (compiletest: trim edition before passing as flag) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 8a33254 + c05e277 commit b3f4c31

31 files changed

+516
-103
lines changed

compiler/rustc/build.rs

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ fn main() {
55
let target_env = env::var("CARGO_CFG_TARGET_ENV");
66
if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() {
77
set_windows_exe_options();
8+
} else {
9+
// Avoid rerunning the build script every time.
10+
println!("cargo:rerun-if-changed=build.rs");
811
}
912
}
1013

compiler/rustc_errors/src/diagnostic.rs

+8
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,14 @@ impl Diagnostic {
614614
self
615615
}
616616

617+
/// Clear any existing suggestions.
618+
pub fn clear_suggestions(&mut self) -> &mut Self {
619+
if let Ok(suggestions) = &mut self.suggestions {
620+
suggestions.clear();
621+
}
622+
self
623+
}
624+
617625
/// Helper for pushing to `self.suggestions`, if available (not disable).
618626
fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
619627
if let Ok(suggestions) = &mut self.suggestions {

compiler/rustc_errors/src/diagnostic_builder.rs

+1
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
461461
forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
462462

463463
forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
464+
forward!(pub fn clear_suggestions(&mut self,) -> &mut Self);
464465

465466
forward!(pub fn multipart_suggestion(
466467
&mut self,

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2094,6 +2094,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
20942094
// |
20952095
// = note: cannot satisfy `_: Tt`
20962096

2097+
// Clear any more general suggestions in favor of our specific one
2098+
err.clear_suggestions();
2099+
20972100
err.span_suggestion_verbose(
20982101
span.shrink_to_hi(),
20992102
&format!(

compiler/rustc_typeck/src/check/intrinsicck.rs

+13-21
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_errors::struct_span_err;
44
use rustc_hir as hir;
55
use rustc_index::vec::Idx;
66
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
7-
use rustc_middle::ty::{self, Article, FloatTy, InferTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
7+
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
88
use rustc_session::lint;
99
use rustc_span::{Span, Symbol, DUMMY_SP};
1010
use rustc_target::abi::{Pointer, VariantIdx};
@@ -99,8 +99,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9999
err.emit();
100100
}
101101

102+
// FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
102103
fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
103-
if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
104+
// Type still may have region variables, but `Sized` does not depend
105+
// on those, so just erase them before querying.
106+
if self.tcx.erase_regions(ty).is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
104107
return true;
105108
}
106109
if let ty::Foreign(..) = ty.kind() {
@@ -128,30 +131,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
128131
64 => InlineAsmType::I64,
129132
_ => unreachable!(),
130133
};
134+
135+
// Expect types to be fully resolved, no const or type variables.
136+
if ty.has_infer_types_or_consts() {
137+
assert!(self.is_tainted_by_errors());
138+
return None;
139+
}
140+
131141
let asm_ty = match *ty.kind() {
132142
// `!` is allowed for input but not for output (issue #87802)
133143
ty::Never if is_input => return None,
134144
ty::Error(_) => return None,
135145
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8),
136146
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16),
137-
// Somewhat of a hack: fallback in the presence of errors does not actually
138-
// fall back to i32, but to ty::Error. For integer inference variables this
139-
// means that they don't get any fallback and stay as `{integer}`.
140-
// Since compilation can't succeed anyway, it's fine to use this to avoid printing
141-
// "cannot use value of type `{integer}`", even though that would absolutely
142-
// work due due i32 fallback if the current function had no other errors.
143-
ty::Infer(InferTy::IntVar(_)) => {
144-
assert!(self.is_tainted_by_errors());
145-
Some(InlineAsmType::I32)
146-
}
147147
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32),
148148
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64),
149149
ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128),
150150
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize),
151-
ty::Infer(InferTy::FloatVar(_)) => {
152-
assert!(self.is_tainted_by_errors());
153-
Some(InlineAsmType::F32)
154-
}
155151
ty::Float(FloatTy::F32) => Some(InlineAsmType::F32),
156152
ty::Float(FloatTy::F64) => Some(InlineAsmType::F64),
157153
ty::FnPtr(_) => Some(asm_ty_isize),
@@ -191,6 +187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
191187
_ => None,
192188
}
193189
}
190+
ty::Infer(_) => unreachable!(),
194191
_ => None,
195192
};
196193
let Some(asm_ty) = asm_ty else {
@@ -204,11 +201,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
204201
return None;
205202
};
206203

207-
if ty.has_infer_types_or_consts() {
208-
assert!(self.is_tainted_by_errors());
209-
return None;
210-
}
211-
212204
// Check that the type implements Copy. The only case where this can
213205
// possibly fail is for SIMD types which don't #[derive(Copy)].
214206
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) {

compiler/rustc_typeck/src/check/method/confirm.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,25 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
8181
let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
8282
let all_substs = self.instantiate_method_substs(&pick, segment, rcvr_substs);
8383

84-
debug!("all_substs={:?}", all_substs);
84+
debug!("rcvr_substs={rcvr_substs:?}, all_substs={all_substs:?}");
8585

8686
// Create the final signature for the method, replacing late-bound regions.
8787
let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs);
8888

89+
// If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that
90+
// something which derefs to `Self` actually implements the trait and the caller
91+
// wanted to make a static dispatch on it but forgot to import the trait.
92+
// See test `src/test/ui/issue-35976.rs`.
93+
//
94+
// In that case, we'll error anyway, but we'll also re-run the search with all traits
95+
// in scope, and if we find another method which can be used, we'll output an
96+
// appropriate hint suggesting to import the trait.
97+
let filler_substs = rcvr_substs
98+
.extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def));
99+
let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
100+
&self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs),
101+
);
102+
89103
// Unify the (adjusted) self type with what the method expects.
90104
//
91105
// SUBTLE: if we want good error messages, because of "guessing" while matching
@@ -106,16 +120,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
106120
// Make sure nobody calls `drop()` explicitly.
107121
self.enforce_illegal_method_limitations(&pick);
108122

109-
// If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that
110-
// something which derefs to `Self` actually implements the trait and the caller
111-
// wanted to make a static dispatch on it but forgot to import the trait.
112-
// See test `src/test/ui/issue-35976.rs`.
113-
//
114-
// In that case, we'll error anyway, but we'll also re-run the search with all traits
115-
// in scope, and if we find another method which can be used, we'll output an
116-
// appropriate hint suggesting to import the trait.
117-
let illegal_sized_bound = self.predicates_require_illegal_sized_bound(&method_predicates);
118-
119123
// Add any trait/regions obligations specified on the method's type parameters.
120124
// We won't add these if we encountered an illegal sized bound, so that we can use
121125
// a custom error in that case.

compiler/rustc_typeck/src/check/method/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use rustc_hir::def_id::DefId;
2020
use rustc_infer::infer::{self, InferOk};
2121
use rustc_middle::ty::subst::Subst;
2222
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
23-
use rustc_middle::ty::GenericParamDefKind;
2423
use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable};
24+
use rustc_middle::ty::{DefIdTree, GenericParamDefKind};
2525
use rustc_span::symbol::Ident;
2626
use rustc_span::Span;
2727
use rustc_trait_selection::traits;
@@ -221,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
221221
}
222222

223223
// We probe again, taking all traits into account (not only those in scope).
224-
let candidates = match self.lookup_probe(
224+
let mut candidates = match self.lookup_probe(
225225
span,
226226
segment.ident,
227227
self_ty,
@@ -243,6 +243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
243243
.collect(),
244244
_ => Vec::new(),
245245
};
246+
candidates.retain(|candidate| *candidate != self.tcx.parent(result.callee.def_id));
246247

247248
return Err(IllegalSizedBound(candidates, needs_mut, span));
248249
}

src/bootstrap/check.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,15 @@ fn args(builder: &Builder<'_>) -> Vec<String> {
2020
arr.iter().copied().map(String::from)
2121
}
2222

23-
if let Subcommand::Clippy { fix, .. } = builder.config.cmd {
23+
if let Subcommand::Clippy {
24+
fix,
25+
clippy_lint_allow,
26+
clippy_lint_deny,
27+
clippy_lint_warn,
28+
clippy_lint_forbid,
29+
..
30+
} = &builder.config.cmd
31+
{
2432
// disable the most spammy clippy lints
2533
let ignored_lints = vec![
2634
"many_single_char_names", // there are a lot in stdarch
@@ -32,7 +40,7 @@ fn args(builder: &Builder<'_>) -> Vec<String> {
3240
"wrong_self_convention",
3341
];
3442
let mut args = vec![];
35-
if fix {
43+
if *fix {
3644
#[rustfmt::skip]
3745
args.extend(strings(&[
3846
"--fix", "-Zunstable-options",
@@ -44,6 +52,12 @@ fn args(builder: &Builder<'_>) -> Vec<String> {
4452
}
4553
args.extend(strings(&["--", "--cap-lints", "warn"]));
4654
args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
55+
let mut clippy_lint_levels: Vec<String> = Vec::new();
56+
clippy_lint_allow.iter().for_each(|v| clippy_lint_levels.push(format!("-A{}", v)));
57+
clippy_lint_deny.iter().for_each(|v| clippy_lint_levels.push(format!("-D{}", v)));
58+
clippy_lint_warn.iter().for_each(|v| clippy_lint_levels.push(format!("-W{}", v)));
59+
clippy_lint_forbid.iter().for_each(|v| clippy_lint_levels.push(format!("-F{}", v)));
60+
args.extend(clippy_lint_levels);
4761
args
4862
} else {
4963
vec![]

src/bootstrap/flags.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ pub enum Subcommand {
9191
Clippy {
9292
fix: bool,
9393
paths: Vec<PathBuf>,
94+
clippy_lint_allow: Vec<String>,
95+
clippy_lint_deny: Vec<String>,
96+
clippy_lint_warn: Vec<String>,
97+
clippy_lint_forbid: Vec<String>,
9498
},
9599
Fix {
96100
paths: Vec<PathBuf>,
@@ -246,6 +250,10 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
246250
opts.optopt("", "rust-profile-use", "use PGO profile for rustc build", "PROFILE");
247251
opts.optflag("", "llvm-profile-generate", "generate PGO profile with llvm built for rustc");
248252
opts.optopt("", "llvm-profile-use", "use PGO profile for llvm build", "PROFILE");
253+
opts.optmulti("A", "", "allow certain clippy lints", "OPT");
254+
opts.optmulti("D", "", "deny certain clippy lints", "OPT");
255+
opts.optmulti("W", "", "warn about certain clippy lints", "OPT");
256+
opts.optmulti("F", "", "forbid certain clippy lints", "OPT");
249257

250258
// We can't use getopt to parse the options until we have completed specifying which
251259
// options are valid, but under the current implementation, some options are conditional on
@@ -544,7 +552,14 @@ Arguments:
544552
}
545553
Subcommand::Check { paths }
546554
}
547-
Kind::Clippy => Subcommand::Clippy { paths, fix: matches.opt_present("fix") },
555+
Kind::Clippy => Subcommand::Clippy {
556+
paths,
557+
fix: matches.opt_present("fix"),
558+
clippy_lint_allow: matches.opt_strs("A"),
559+
clippy_lint_warn: matches.opt_strs("W"),
560+
clippy_lint_deny: matches.opt_strs("D"),
561+
clippy_lint_forbid: matches.opt_strs("F"),
562+
},
548563
Kind::Fix => Subcommand::Fix { paths },
549564
Kind::Test => Subcommand::Test {
550565
paths,

src/librustdoc/config.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,17 @@ impl Options {
329329
return Err(0);
330330
}
331331

332+
let z_flags = matches.opt_strs("Z");
333+
if z_flags.iter().any(|x| *x == "help") {
334+
print_flag_list("-Z", config::DB_OPTIONS);
335+
return Err(0);
336+
}
337+
let c_flags = matches.opt_strs("C");
338+
if c_flags.iter().any(|x| *x == "help") {
339+
print_flag_list("-C", config::CG_OPTIONS);
340+
return Err(0);
341+
}
342+
332343
let color = config::parse_color(matches);
333344
let config::JsonConfig { json_rendered, json_unused_externs, .. } =
334345
config::parse_json(matches);
@@ -343,17 +354,6 @@ impl Options {
343354
// check for deprecated options
344355
check_deprecated_options(matches, &diag);
345356

346-
let z_flags = matches.opt_strs("Z");
347-
if z_flags.iter().any(|x| *x == "help") {
348-
print_flag_list("-Z", config::DB_OPTIONS);
349-
return Err(0);
350-
}
351-
let c_flags = matches.opt_strs("C");
352-
if c_flags.iter().any(|x| *x == "help") {
353-
print_flag_list("-C", config::CG_OPTIONS);
354-
return Err(0);
355-
}
356-
357357
if matches.opt_strs("passes") == ["list"] {
358358
println!("Available passes for running rustdoc:");
359359
for pass in passes::PASSES {

src/librustdoc/doctest.rs

+50-23
Original file line numberDiff line numberDiff line change
@@ -726,31 +726,58 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
726726
// Empty content so nothing to check in here...
727727
return true;
728728
}
729-
rustc_span::create_session_if_not_set_then(edition, |_| {
730-
let filename = FileName::anon_source_code(source);
731-
let sess = ParseSess::with_silent_emitter(None);
732-
let mut parser = match maybe_new_parser_from_source_str(&sess, filename, source.to_owned())
733-
{
734-
Ok(p) => p,
735-
Err(_) => {
736-
debug!("Cannot build a parser to check mod attr so skipping...");
737-
return true;
729+
rustc_driver::catch_fatal_errors(|| {
730+
rustc_span::create_session_if_not_set_then(edition, |_| {
731+
use rustc_errors::emitter::EmitterWriter;
732+
use rustc_errors::Handler;
733+
use rustc_span::source_map::FilePathMapping;
734+
735+
let filename = FileName::anon_source_code(source);
736+
// Any errors in parsing should also appear when the doctest is compiled for real, so just
737+
// send all the errors that librustc_ast emits directly into a `Sink` instead of stderr.
738+
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
739+
let fallback_bundle =
740+
rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
741+
742+
let emitter = EmitterWriter::new(
743+
box io::sink(),
744+
None,
745+
None,
746+
fallback_bundle,
747+
false,
748+
false,
749+
false,
750+
None,
751+
false,
752+
);
753+
754+
let handler = Handler::with_emitter(false, None, box emitter);
755+
let sess = ParseSess::with_span_handler(handler, sm);
756+
let mut parser =
757+
match maybe_new_parser_from_source_str(&sess, filename, source.to_owned()) {
758+
Ok(p) => p,
759+
Err(_) => {
760+
debug!("Cannot build a parser to check mod attr so skipping...");
761+
return true;
762+
}
763+
};
764+
// If a parsing error happened, it's very likely that the attribute is incomplete.
765+
if let Err(e) = parser.parse_attribute(InnerAttrPolicy::Permitted) {
766+
e.cancel();
767+
return false;
738768
}
739-
};
740-
// If a parsing error happened, it's very likely that the attribute is incomplete.
741-
if parser.parse_attribute(InnerAttrPolicy::Permitted).is_err() {
742-
return false;
743-
}
744-
// We now check if there is an unclosed delimiter for the attribute. To do so, we look at
745-
// the `unclosed_delims` and see if the opening square bracket was closed.
746-
parser
747-
.unclosed_delims()
748-
.get(0)
749-
.map(|unclosed| {
750-
unclosed.unclosed_span.map(|s| s.lo()).unwrap_or(BytePos(0)) != BytePos(2)
751-
})
752-
.unwrap_or(true)
769+
// We now check if there is an unclosed delimiter for the attribute. To do so, we look at
770+
// the `unclosed_delims` and see if the opening square bracket was closed.
771+
parser
772+
.unclosed_delims()
773+
.get(0)
774+
.map(|unclosed| {
775+
unclosed.unclosed_span.map(|s| s.lo()).unwrap_or(BytePos(0)) != BytePos(2)
776+
})
777+
.unwrap_or(true)
778+
})
753779
})
780+
.unwrap_or(false)
754781
}
755782

756783
fn partition_source(s: &str, edition: Edition) -> (String, String, String) {

src/test/rustdoc-ui/c-help.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// check-pass
2+
// compile-flags: -Chelp
3+
4+
pub struct Foo;

0 commit comments

Comments
 (0)