diff options
110 files changed, 1086 insertions, 714 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index d5ed9aa380f..4244e67482c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1377,7 +1377,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = self.lower_generic_params_mut(&generics.params).collect(); - let has_where_clause = !generics.where_clause.predicates.is_empty(); + let has_where_clause_predicates = !generics.where_clause.predicates.is_empty(); let where_clause_span = self.lower_span(generics.where_clause.span); let span = self.lower_span(generics.span); let res = f(self); @@ -1395,7 +1395,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let lowered_generics = self.arena.alloc(hir::Generics { params: self.arena.alloc_from_iter(params), predicates: self.arena.alloc_from_iter(predicates), - has_where_clause, + has_where_clause_predicates, where_clause_span, span, }); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6d780b8448c..6fe95a21fa4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1315,7 +1315,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { generics: self.arena.alloc(hir::Generics { params: lifetime_defs, predicates: &[], - has_where_clause: false, + has_where_clause_predicates: false, where_clause_span: lctx.lower_span(span), span: lctx.lower_span(span), }), @@ -1637,7 +1637,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { generics: this.arena.alloc(hir::Generics { params: generic_params, predicates: &[], - has_where_clause: false, + has_where_clause_predicates: false, where_clause_span: this.lower_span(span), span: this.lower_span(span), }), diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 50f8949c897..3864db9ffc1 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -463,7 +463,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( let llvm_selfprofiler = llvm_profiler.as_mut().map(|s| s as *mut _ as *mut c_void).unwrap_or(std::ptr::null_mut()); - let extra_passes = config.passes.join(","); + let extra_passes = if !is_lto { config.passes.join(",") } else { "".to_string() }; let llvm_plugins = config.llvm_plugins.join(","); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 1f5e2b76bf0..82213e7d748 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1003,10 +1003,14 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( let strip = strip_value(sess); if sess.target.is_like_osx { - match strip { - Strip::Debuginfo => strip_symbols_in_osx(sess, &out_filename, Some("-S")), - Strip::Symbols => strip_symbols_in_osx(sess, &out_filename, None), - Strip::None => {} + match (strip, crate_type) { + (Strip::Debuginfo, _) => strip_symbols_in_osx(sess, &out_filename, Some("-S")), + // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988) + (Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => { + strip_symbols_in_osx(sess, &out_filename, Some("-x")) + } + (Strip::Symbols, _) => strip_symbols_in_osx(sess, &out_filename, None), + (Strip::None, _) => {} } } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index b39a33aff09..630281bb092 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -338,6 +338,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' { "invalid drop function pointer in vtable (not pointing to a function)" }, err_ub!(InvalidVtableDropFn(..)) => { "invalid drop function pointer in vtable (function has incompatible signature)" }, + // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123. + // (We assume there are no other MachineStop errors possible here.) + InterpError::MachineStop(_) => + { "vtable pointer does not have permission to read drop function pointer" }, ); try_validation!( self.ecx.read_size_and_align_from_vtable(vtable), @@ -347,6 +351,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' err_ub!(InvalidVtableAlignment(msg)) => { "invalid vtable: alignment {}", msg }, err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" }, + // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123. + // (We assume there are no other MachineStop errors possible here.) + InterpError::MachineStop(_) => + { "vtable pointer does not have permission to read size and alignment" }, ); // FIXME: More checks for the vtable. } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index d2b5ef8ea6f..04410ca3828 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -20,6 +20,7 @@ Rust MIR: a lowered representation of Rust. #![feature(trusted_len)] #![feature(trusted_step)] #![feature(try_blocks)] +#![feature(yeet_expr)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 0114461e388..d507293ccb0 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -528,7 +528,7 @@ E0788: include_str!("./error_codes/E0788.md"), // E0190, // deprecated: can only cast a &-pointer to an &-object // E0194, // merged into E0403 // E0196, // cannot determine a type for this closure - E0208, + E0208, // internal error code // E0209, // builtin traits can only be implemented on structs or enums // E0213, // associated types are not accepted in this context // E0215, // angle-bracket notation is not stable with `Fn` @@ -633,14 +633,14 @@ E0788: include_str!("./error_codes/E0788.md"), // E0629, // missing 'feature' (rustc_const_unstable) // E0630, // rustc_const_unstable attribute must be paired with stable/unstable // attribute - E0640, // infer outlives requirements + E0640, // infer outlives requirements, internal error code // E0645, // trait aliases not finished // E0694, // an unknown tool name found in scoped attributes // E0702, // replaced with a generic attribute input check // E0707, // multiple elided lifetimes used in arguments of `async fn` // E0709, // multiple different lifetimes used in arguments of `async fn` - E0711, // a feature has been declared with conflicting stability attributes - E0717, // rustc_promotable without stability attribute + E0711, // a feature has been declared with conflicting stability attributes, internal error code + E0717, // rustc_promotable without stability attribute, internal error code // E0721, // `await` keyword // E0723, // unstable feature in `const` context // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 7043ad54645..86ff110eec1 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,4 +1,5 @@ #![allow(rustc::potential_query_instability)] +#![feature(array_windows)] #![feature(associated_type_bounds)] #![feature(associated_type_defaults)] #![feature(if_let_guard)] diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index b86304ba6b1..a66d36aaf72 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -123,7 +123,7 @@ impl<'a> ParserAnyMacro<'a> { is_trailing_mac, is_local, } = *self; - let snapshot = &mut parser.clone(); + let snapshot = &mut parser.create_snapshot_for_diagnostic(); let fragment = match parse_ast_fragment(parser, kind) { Ok(f) => f, Err(err) => { @@ -380,7 +380,7 @@ pub fn compile_declarative_macro( features: &Features, def: &ast::Item, edition: Edition, -) -> (SyntaxExtension, Vec<Span>) { +) -> (SyntaxExtension, Vec<(usize, Span)>) { debug!("compile_declarative_macro: {:?}", def); let mk_syn_ext = |expander| { SyntaxExtension::new( @@ -539,11 +539,22 @@ pub fn compile_declarative_macro( None => {} } - // Compute the spans of the macro rules - // We only take the span of the lhs here, - // so that the spans of created warnings are smaller. - let rule_spans = if def.id != DUMMY_NODE_ID { - lhses.iter().map(|lhs| lhs.span()).collect::<Vec<_>>() + // Compute the spans of the macro rules for unused rule linting. + // To avoid warning noise, only consider the rules of this + // macro for the lint, if all rules are valid. + // Also, we are only interested in non-foreign macros. + let rule_spans = if valid && def.id != DUMMY_NODE_ID { + lhses + .iter() + .zip(rhses.iter()) + .enumerate() + // If the rhs contains an invocation like compile_error!, + // don't consider the rule for the unused rule lint. + .filter(|(_idx, (_lhs, rhs))| !has_compile_error_macro(rhs)) + // We only take the span of the lhs here, + // so that the spans of created warnings are smaller. + .map(|(idx, (lhs, _rhs))| (idx, lhs.span())) + .collect::<Vec<_>>() } else { Vec::new() }; @@ -651,6 +662,29 @@ fn check_matcher(sess: &ParseSess, def: &ast::Item, matcher: &[mbe::TokenTree]) err == sess.span_diagnostic.err_count() } +fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool { + match rhs { + mbe::TokenTree::Delimited(_sp, d) => { + let has_compile_error = d.tts.array_windows::<3>().any(|[ident, bang, args]| { + if let mbe::TokenTree::Token(ident) = ident && + let TokenKind::Ident(ident, _) = ident.kind && + ident == sym::compile_error && + let mbe::TokenTree::Token(bang) = bang && + let TokenKind::Not = bang.kind && + let mbe::TokenTree::Delimited(_, del) = args && + del.delim != Delimiter::Invisible + { + true + } else { + false + } + }); + if has_compile_error { true } else { d.tts.iter().any(has_compile_error_macro) } + } + _ => false, + } +} + // `The FirstSets` for a matcher is a mapping from subsequences in the // matcher to the FIRST set for that subsequence. // diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2f5f271dc50..bd5973f31cf 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -535,7 +535,7 @@ pub struct GenericParamCount { pub struct Generics<'hir> { pub params: &'hir [GenericParam<'hir>], pub predicates: &'hir [WherePredicate<'hir>], - pub has_where_clause: bool, + pub has_where_clause_predicates: bool, pub where_clause_span: Span, pub span: Span, } @@ -545,7 +545,7 @@ impl<'hir> Generics<'hir> { const NOPE: Generics<'_> = Generics { params: &[], predicates: &[], - has_where_clause: false, + has_where_clause_predicates: false, where_clause_span: DUMMY_SP, span: DUMMY_SP, }; @@ -581,21 +581,11 @@ impl<'hir> Generics<'hir> { } } - pub fn where_clause_span(&self) -> Option<Span> { - if self.predicates.is_empty() { None } else { Some(self.where_clause_span) } - } - - /// The `where_span` under normal circumstances points at either the predicates or the empty - /// space where the `where` clause should be. Only of use for diagnostic suggestions. - pub fn span_for_predicates_or_empty_place(&self) -> Span { - self.where_clause_span - } - /// `Span` where further predicates would be suggested, accounting for trailing commas, like /// in `fn foo<T>(t: T) where T: Foo,` so we don't suggest two trailing commas. pub fn tail_span_for_predicate_suggestion(&self) -> Span { - let end = self.span_for_predicates_or_empty_place().shrink_to_hi(); - if self.has_where_clause { + let end = self.where_clause_span.shrink_to_hi(); + if self.has_where_clause_predicates { self.predicates .iter() .filter(|p| p.in_where_clause()) @@ -608,6 +598,17 @@ impl<'hir> Generics<'hir> { } } + pub fn add_where_or_trailing_comma(&self) -> &'static str { + if self.has_where_clause_predicates { + "," + } else if self.where_clause_span.is_empty() { + " where" + } else { + // No where clause predicates, but we have `where` token + "" + } + } + pub fn bounds_for_param( &self, param_def_id: LocalDefId, @@ -1885,7 +1886,7 @@ pub enum ExprKind<'hir> { /// To resolve the called method to a `DefId`, call [`type_dependent_def_id`] with /// the `hir_id` of the `MethodCall` node itself. /// - /// [`type_dependent_def_id`]: ../ty/struct.TypeckResults.html#method.type_dependent_def_id + /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id MethodCall(&'hir PathSegment<'hir>, &'hir [Expr<'hir>], Span), /// A tuple (e.g., `(a, b, c, d)`). Tup(&'hir [Expr<'hir>]), @@ -1982,7 +1983,7 @@ pub enum ExprKind<'hir> { /// /// To resolve the path to a `DefId`, call [`qpath_res`]. /// -/// [`qpath_res`]: ../rustc_middle/ty/struct.TypeckResults.html#method.qpath_res +/// [`qpath_res`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.qpath_res #[derive(Debug, HashStable_Generic)] pub enum QPath<'hir> { /// Path to a definition, optionally "fully-qualified" with a `Self` diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 1181925dd96..3eeea7fdb13 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1588,7 +1588,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Mismatch::Variable(infer::ExpectedFound { expected, found }), ) } - ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")), + ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => { + (false, Mismatch::Fixed("trait")) + } _ => (false, Mismatch::Fixed("type")), }; let vals = match self.values_str(values) { @@ -2509,11 +2511,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { labeled_user_string ); let pred = format!("{}: {}", bound_kind, sub); - let suggestion = format!( - "{} {}", - if !generics.predicates.is_empty() { "," } else { " where" }, - pred, - ); + let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,); err.span_suggestion( generics.tail_span_for_predicate_suggestion(), "consider adding a where clause", diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 207d2870c5c..4c734b1589b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -304,11 +304,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let error_code = error_code.into(); - let mut err = self.tcx.sess.struct_span_err_with_code( - span, - &format!("type annotations needed"), - error_code, - ); + let mut err = + self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code); err.span_label(span, arg_data.cannot_infer_msg()); err } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index cbdcf013522..67bbace39e3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -367,17 +367,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .collect(); if !clauses.is_empty() { - let where_clause_span = self - .tcx - .hir() - .get_generics(impl_item_def_id) - .unwrap() - .where_clause_span - .shrink_to_hi(); + let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap(); + let where_clause_span = generics.tail_span_for_predicate_suggestion(); let suggestion = format!( "{} {}", - if !impl_predicates.is_empty() { "," } else { " where" }, + generics.add_where_or_trailing_comma(), clauses.join(", "), ); err.span_suggestion( diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index f2cfbea207e..3747fb5eca0 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -789,6 +789,7 @@ fn test_debugging_options_tracking_hash() { tracked!(thinlto, Some(true)); tracked!(thir_unsafeck, true); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); + tracked!(translate_remapped_path_to_local_path, false); tracked!(trap_unreachable, Some(false)); tracked!(treat_err_as_bug, NonZeroUsize::new(1)); tracked!(tune_cpu, Some(String::from("abc"))); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 92cd8c2b611..205ca72aae8 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2293,10 +2293,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { // If all predicates are inferable, drop the entire clause // (including the `where`) - if hir_generics.has_where_clause && dropped_predicate_count == num_predicates { - let where_span = hir_generics - .where_clause_span() - .expect("span of (nonempty) where clause should exist"); + if hir_generics.has_where_clause_predicates && dropped_predicate_count == num_predicates + { + let where_span = hir_generics.where_clause_span; // Extend the where clause back to the closing `>` of the // generics, except for tuple struct, which have the `where` // after the fields of the struct. diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 775ebb48402..186031d4586 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -774,17 +774,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn opt_item_ident(self, item_index: DefIndex, sess: &Session) -> Option<Ident> { let name = self.opt_item_name(item_index)?; - let span = match self.root.tables.def_ident_span.get(self, item_index) { - Some(lazy_span) => lazy_span.decode((self, sess)), - None => { - // FIXME: this weird case of a name with no span is specific to `extern crate` - // items, which are supposed to be treated like `use` items and only be encoded - // to metadata as `Export`s, return `None` because that's what all the callers - // expect in this case. - assert_eq!(self.def_kind(item_index), DefKind::ExternCrate); - return None; - } - }; + let span = + self.root.tables.def_ident_span.get(self, item_index).unwrap().decode((self, sess)); Some(Ident::new(name, span)) } @@ -1486,6 +1477,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .filter(|_| { // Only spend time on further checks if we have what to translate *to*. sess.opts.real_rust_source_base_dir.is_some() + // Some tests need the translation to be always skipped. + && sess.opts.debugging_opts.translate_remapped_path_to_local_path }) .filter(|virtual_dir| { // Don't translate away `/rustc/$hash` if we're still remapping to it, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3285273ba90..50c09aaf8d4 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -31,7 +31,7 @@ use rustc_serialize::{opaque, Encodable, Encoder}; use rustc_session::config::CrateType; use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::{ self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext, }; @@ -1007,6 +1007,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.def_span[def_id] <- tcx.def_span(def_id)); self.encode_attrs(local_id); record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id)); + if let Some(ident_span) = tcx.def_ident_span(def_id) { + record!(self.tables.def_ident_span[def_id] <- ident_span); + } if def_kind.has_codegen_attrs() { record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id)); } @@ -1071,7 +1074,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { assert!(f.did.is_local()); f.did.index })); - self.encode_ident_span(def_id, variant.ident(tcx)); self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`. @@ -1163,7 +1165,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EncodeContext::encode_field({:?})", def_id); record!(self.tables.kind[def_id] <- EntryKind::Field); - self.encode_ident_span(def_id, field.ident(self.tcx)); self.encode_item_type(def_id); } @@ -1242,7 +1243,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id] <- EntryKind::AssocType(container)); } } - self.encode_ident_span(def_id, ast_item.ident); match trait_item.kind { ty::AssocKind::Const | ty::AssocKind::Fn => { self.encode_item_type(def_id); @@ -1306,7 +1306,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id] <- EntryKind::AssocType(container)); } } - self.encode_ident_span(def_id, impl_item.ident(self.tcx)); self.encode_item_type(def_id); if let Some(trait_item_def_id) = impl_item.trait_item_def_id { self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into()); @@ -1408,8 +1407,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EncodeContext::encode_info_for_item({:?})", def_id); - self.encode_ident_span(def_id, item.ident); - let entry_kind = match item.kind { hir::ItemKind::Static(..) => EntryKind::Static, hir::ItemKind::Const(_, body_id) => { @@ -1953,7 +1950,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id] <- EntryKind::ForeignType); } } - self.encode_ident_span(def_id, nitem.ident); self.encode_item_type(def_id); if let hir::ForeignItemKind::Fn(..) = nitem.kind { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); @@ -2035,10 +2031,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_ident_span(&mut self, def_id: DefId, ident: Ident) { - record!(self.tables.def_ident_span[def_id] <- ident.span); - } - /// In some cases, along with the item itself, we also /// encode some sub-items. Usually we want some info from the item /// so it's easier to do that here then to wait until we would encounter diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index ebda9f7588d..0f1597e66e7 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -912,27 +912,33 @@ impl<'hir> Map<'hir> { } } + #[inline] + fn opt_ident(self, id: HirId) -> Option<Ident> { + match self.get(id) { + Node::Binding(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident), + // A `Ctor` doesn't have an identifier itself, but its parent + // struct/variant does. Compare with `hir::Map::opt_span`. + Node::Ctor(..) => match self.find(self.get_parent_node(id))? { + Node::Item(item) => Some(item.ident), + Node::Variant(variant) => Some(variant.ident), + _ => unreachable!(), + }, + node => node.ident(), + } + } + + #[inline] + pub(super) fn opt_ident_span(self, id: HirId) -> Option<Span> { + self.opt_ident(id).map(|ident| ident.span) + } + + #[inline] pub fn opt_name(self, id: HirId) -> Option<Symbol> { - Some(match self.get(id) { - Node::Item(i) => i.ident.name, - Node::ForeignItem(fi) => fi.ident.name, - Node::ImplItem(ii) => ii.ident.name, - Node::TraitItem(ti) => ti.ident.name, - Node::Variant(v) => v.ident.name, - Node::Field(f) => f.ident.name, - Node::Lifetime(lt) => lt.name.ident().name, - Node::GenericParam(param) => param.name.ident().name, - Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name, - Node::Ctor(..) => self.name(HirId::make_owner(self.get_parent_item(id))), - _ => return None, - }) + self.opt_ident(id).map(|ident| ident.name) } pub fn name(self, id: HirId) -> Symbol { - match self.opt_name(id) { - Some(name) => name, - None => bug!("no name for {}", self.node_to_string(id)), - } + self.opt_name(id).unwrap_or_else(|| bug!("no name for {}", self.node_to_string(id))) } /// Given a node ID, gets a list of attributes associated with the AST @@ -1008,7 +1014,7 @@ impl<'hir> Map<'hir> { } pub fn span_if_local(self, id: DefId) -> Option<Span> { - id.as_local().and_then(|id| self.opt_span(self.local_def_id_to_hir_id(id))) + if id.is_local() { Some(self.tcx.def_span(id)) } else { None } } pub fn res_span(self, res: Res) -> Option<Span> { diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index b50f121eff2..34ed5788c54 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -121,7 +121,16 @@ pub fn provide(providers: &mut Providers) { providers.hir_attrs = |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs); providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id); - providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP); + providers.def_span = |tcx, def_id| { + let def_id = def_id.expect_local(); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + tcx.hir().opt_span(hir_id).unwrap_or(DUMMY_SP) + }; + providers.def_ident_span = |tcx, def_id| { + let def_id = def_id.expect_local(); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + tcx.hir().opt_ident_span(hir_id) + }; providers.fn_arg_names = |tcx, id| { let hir = tcx.hir(); let hir_id = hir.local_def_id_to_hir_id(id.expect_local()); diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 8004319bf9b..46c34247d40 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -58,6 +58,7 @@ #![feature(decl_macro)] #![feature(drain_filter)] #![feature(intra_doc_pointers)] +#![feature(yeet_expr)] #![recursion_limit = "512"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 214b919e24d..8733a85ef3f 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -56,7 +56,7 @@ macro_rules! err_machine_stop { // In the `throw_*` macros, avoid `return` to make them work with `try {}`. #[macro_export] macro_rules! throw_unsup { - ($($tt:tt)*) => { Err::<!, _>(err_unsup!($($tt)*))? }; + ($($tt:tt)*) => { do yeet err_unsup!($($tt)*) }; } #[macro_export] @@ -66,12 +66,12 @@ macro_rules! throw_unsup_format { #[macro_export] macro_rules! throw_inval { - ($($tt:tt)*) => { Err::<!, _>(err_inval!($($tt)*))? }; + ($($tt:tt)*) => { do yeet err_inval!($($tt)*) }; } #[macro_export] macro_rules! throw_ub { - ($($tt:tt)*) => { Err::<!, _>(err_ub!($($tt)*))? }; + ($($tt:tt)*) => { do yeet err_ub!($($tt)*) }; } #[macro_export] @@ -81,12 +81,12 @@ macro_rules! throw_ub_format { #[macro_export] macro_rules! throw_exhaust { - ($($tt:tt)*) => { Err::<!, _>(err_exhaust!($($tt)*))? }; + ($($tt:tt)*) => { do yeet err_exhaust!($($tt)*) }; } #[macro_export] macro_rules! throw_machine_stop { - ($($tt:tt)*) => { Err::<!, _>(err_machine_stop!($($tt)*))? }; + ($($tt:tt)*) => { do yeet err_machine_stop!($($tt)*) }; } mod allocation; diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index c3b79917dda..120d09ee353 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -191,6 +191,20 @@ pub enum StmtKind<'tcx> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(Expr<'_>, 104); +#[derive( + Clone, + Debug, + Copy, + PartialEq, + Eq, + Hash, + HashStable, + TyEncodable, + TyDecodable, + TypeFoldable +)] +pub struct LocalVarId(pub hir::HirId); + /// A THIR expression. #[derive(Clone, Debug, HashStable)] pub struct Expr<'tcx> { @@ -332,7 +346,7 @@ pub enum ExprKind<'tcx> { }, /// A local variable. VarRef { - id: hir::HirId, + id: LocalVarId, }, /// Used to represent upvars mentioned in a closure/generator UpvarRef { @@ -340,7 +354,7 @@ pub enum ExprKind<'tcx> { closure_def_id: DefId, /// HirId of the root variable - var_hir_id: hir::HirId, + var_hir_id: LocalVarId, }, /// A borrow, e.g. `&arg`. Borrow { @@ -596,7 +610,7 @@ pub enum PatKind<'tcx> { mutability: Mutability, name: Symbol, mode: BindingMode, - var: hir::HirId, + var: LocalVarId, ty: Ty<'tcx>, subpattern: Option<Pat<'tcx>>, /// Is this the leftmost occurrence of the binding, i.e., is `var` the diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 9bb64d4023b..1acded8c6e4 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -1,9 +1,10 @@ //! Diagnostics related methods for `Ty`. -use crate::ty::subst::{GenericArg, GenericArgKind}; +use std::ops::ControlFlow; + use crate::ty::{ - ConstKind, DefIdTree, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, - InferTy, ProjectionTy, Term, Ty, TyCtxt, TypeAndMut, + fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, + PolyTraitPredicate, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor, }; use rustc_data_structures::fx::FxHashMap; @@ -72,103 +73,55 @@ impl<'tcx> Ty<'tcx> { _ => self.is_simple_ty(), } } +} - /// Whether the type can be safely suggested during error recovery. - pub fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool { - fn generic_arg_is_suggestible<'tcx>(arg: GenericArg<'tcx>, tcx: TyCtxt<'tcx>) -> bool { - match arg.unpack() { - GenericArgKind::Type(ty) => ty.is_suggestable(tcx), - GenericArgKind::Const(c) => const_is_suggestable(c.val()), - _ => true, - } - } - - fn const_is_suggestable(kind: ConstKind<'_>) -> bool { - match kind { - ConstKind::Infer(..) - | ConstKind::Bound(..) - | ConstKind::Placeholder(..) - | ConstKind::Error(..) => false, - _ => true, - } - } - - // FIXME(compiler-errors): Some types are still not good to suggest, - // specifically references with lifetimes within the function. Not - //sure we have enough information to resolve whether a region is - // temporary, so I'll leave this as a fixme. +pub trait IsSuggestable<'tcx> { + /// Whether this makes sense to suggest in a diagnostic. + /// + /// We filter out certain types and constants since they don't provide + /// meaningful rendered suggestions when pretty-printed. We leave some + /// nonsense, such as region vars, since those render as `'_` and are + /// usually okay to reinterpret as elided lifetimes. + fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool; +} - match self.kind() { - FnDef(..) - | Closure(..) - | Infer(..) - | Generator(..) - | GeneratorWitness(..) - | Bound(_, _) - | Placeholder(_) - | Error(_) => false, - Opaque(did, substs) => { - let parent = tcx.parent(*did); - if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = tcx.def_kind(parent) - && let Opaque(parent_did, _) = tcx.type_of(parent).kind() - && parent_did == did - { - substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) - } else { - false - } - } - Dynamic(dty, _) => dty.iter().all(|pred| match pred.skip_binder() { - ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => { - substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) - } - ExistentialPredicate::Projection(ExistentialProjection { - substs, term, .. - }) => { - let term_is_suggestable = match term { - Term::Ty(ty) => ty.is_suggestable(tcx), - Term::Const(c) => const_is_suggestable(c.val()), - }; - term_is_suggestable && substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) - } - _ => true, - }), - Projection(ProjectionTy { substs: args, .. }) | Adt(_, args) => { - args.iter().all(|a| generic_arg_is_suggestible(a, tcx)) - } - Tuple(args) => args.iter().all(|ty| ty.is_suggestable(tcx)), - Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(tcx), - Array(ty, c) => ty.is_suggestable(tcx) && const_is_suggestable(c.val()), - _ => true, - } +impl<'tcx, T> IsSuggestable<'tcx> for T +where + T: TypeFoldable<'tcx>, +{ + fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool { + self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue() } } -pub fn suggest_arbitrary_trait_bound( +pub fn suggest_arbitrary_trait_bound<'tcx>( + tcx: TyCtxt<'tcx>, generics: &hir::Generics<'_>, err: &mut Diagnostic, - param_name: &str, - constraint: &str, + trait_pred: PolyTraitPredicate<'tcx>, ) -> bool { + if !trait_pred.is_suggestable(tcx) { + return false; + } + + let param_name = trait_pred.skip_binder().self_ty().to_string(); + let constraint = trait_pred.print_modifiers_and_trait_path().to_string(); let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); - match (param, param_name) { - (Some(_), "Self") => return false, - _ => {} + + // Skip, there is a param named Self + if param.is_some() && param_name == "Self" { + return false; } + // Suggest a where clause bound for a non-type parameter. - let (action, prefix) = if generics.has_where_clause { - ("extending the", ", ") - } else { - ("introducing a", " where ") - }; err.span_suggestion_verbose( generics.tail_span_for_predicate_suggestion(), &format!( - "consider {} `where` bound, but there might be an alternative better way to express \ + "consider {} `where` clause, but there might be an alternative better way to express \ this requirement", - action, + if generics.where_clause_span.is_empty() { "introducing a" } else { "extending the" }, ), - format!("{}{}: {}", prefix, param_name, constraint), + format!("{} {}: {}", generics.add_where_or_trailing_comma(), param_name, constraint), Applicability::MaybeIncorrect, ); true @@ -321,7 +274,7 @@ pub fn suggest_constraining_type_params<'a>( continue; } - if generics.has_where_clause { + if generics.has_where_clause_predicates { // This part is a bit tricky, because using the `where` clause user can // provide zero, one or many bounds for the same type parameter, so we // have following cases to consider: @@ -463,3 +416,78 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> { } } } + +pub struct IsSuggestableVisitor<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { + type BreakTy = (); + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + match t.kind() { + FnDef(..) + | Closure(..) + | Infer(..) + | Generator(..) + | GeneratorWitness(..) + | Bound(_, _) + | Placeholder(_) + | Error(_) => { + return ControlFlow::Break(()); + } + + Opaque(did, _) => { + let parent = self.tcx.parent(*did); + if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent) + && let Opaque(parent_did, _) = self.tcx.type_of(parent).kind() + && parent_did == did + { + // Okay + } else { + return ControlFlow::Break(()); + } + } + + Dynamic(dty, _) => { + for pred in *dty { + match pred.skip_binder() { + ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => { + // Okay + } + _ => return ControlFlow::Break(()), + } + } + } + + Param(param) => { + // FIXME: It would be nice to make this not use string manipulation, + // but it's pretty hard to do this, since `ty::ParamTy` is missing + // sufficient info to determine if it is synthetic, and we don't + // always have a convenient way of getting `ty::Generics` at the call + // sites we invoke `IsSuggestable::is_suggestable`. + if param.name.as_str().starts_with("impl ") { + return ControlFlow::Break(()); + } + } + + _ => {} + } + + t.super_visit_with(self) + } + + fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> { + match c.val() { + ConstKind::Infer(..) + | ConstKind::Bound(..) + | ConstKind::Placeholder(..) + | ConstKind::Error(..) => { + return ControlFlow::Break(()); + } + _ => {} + } + + c.super_visit_with(self) + } +} diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 5fff840c39e..84547dca453 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -39,6 +39,13 @@ impl GenericParamDefKind { GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => true, } } + + pub fn is_synthetic(&self) -> bool { + match self { + GenericParamDefKind::Type { synthetic, .. } => *synthetic, + _ => false, + } + } } #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 981441fab04..e77f5931dd6 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -3,8 +3,7 @@ use crate::build::expr::category::Category; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; -use rustc_hir::def_id::DefId; -use rustc_hir::HirId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::hir::place::Projection as HirProjection; use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::middle::region; @@ -57,7 +56,7 @@ pub(crate) enum PlaceBase { /// figure out that it is captured until all the `Field` projections are applied. Upvar { /// HirId of the upvar - var_hir_id: HirId, + var_hir_id: LocalVarId, /// DefId of the closure closure_def_id: DefId, /// The trait closure implements, `Fn`, `FnMut`, `FnOnce` @@ -151,12 +150,12 @@ fn is_ancestor_or_same_capture( /// `ty::MinCaptureList` of the root variable `var_hir_id`. fn compute_capture_idx<'tcx>( closure_min_captures: &ty::RootVariableMinCaptureList<'tcx>, - var_hir_id: HirId, + var_hir_id: LocalVarId, root_var_idx: usize, ) -> usize { let mut res = 0; for (var_id, capture_list) in closure_min_captures { - if *var_id == var_hir_id { + if *var_id == var_hir_id.0 { res += root_var_idx; break; } else { @@ -176,12 +175,12 @@ fn compute_capture_idx<'tcx>( /// Returns None, when the ancestor is not found. fn find_capture_matching_projections<'a, 'tcx>( typeck_results: &'a ty::TypeckResults<'tcx>, - var_hir_id: HirId, + var_hir_id: LocalVarId, closure_def_id: DefId, projections: &[PlaceElem<'tcx>], ) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> { let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?; - let root_variable_min_captures = closure_min_captures.get(&var_hir_id)?; + let root_variable_min_captures = closure_min_captures.get(&var_hir_id.0)?; let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections); @@ -500,8 +499,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, ), ExprKind::UpvarRef { closure_def_id, var_hir_id } => { - let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local()); - this.lower_captured_upvar(block, upvar_id) + this.lower_captured_upvar(block, closure_def_id.expect_local(), var_hir_id) } ExprKind::VarRef { id } => { @@ -627,11 +625,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn lower_captured_upvar( &mut self, block: BasicBlock, - upvar_id: ty::UpvarId, + closure_expr_id: LocalDefId, + var_hir_id: LocalVarId, ) -> BlockAnd<PlaceBuilder<'tcx>> { - let closure_ty = self - .typeck_results - .node_type(self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id)); + let closure_ty = + self.typeck_results.node_type(self.tcx.hir().local_def_id_to_hir_id(closure_expr_id)); let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() { self.infcx.closure_kind(closure_substs).unwrap() @@ -641,8 +639,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; block.and(PlaceBuilder::from(PlaceBase::Upvar { - var_hir_id: upvar_id.var_path.hir_id, - closure_def_id: upvar_id.closure_expr_id.to_def_id(), + var_hir_id, + closure_def_id: closure_expr_id.to_def_id(), closure_kind, })) } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 43a84f69699..dc1860cb112 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -14,7 +14,6 @@ use rustc_data_structures::{ fx::{FxHashSet, FxIndexMap, FxIndexSet}, stack::ensure_sufficient_stack, }; -use rustc_hir::HirId; use rustc_index::bit_set::BitSet; use rustc_middle::middle::region; use rustc_middle::mir::*; @@ -690,7 +689,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn storage_live_binding( &mut self, block: BasicBlock, - var: HirId, + var: LocalVarId, span: Span, for_guard: ForGuard, schedule_drop: bool, @@ -700,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) }); // Altough there is almost always scope for given variable in corner cases // like #92893 we might get variable with no scope. - if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) && schedule_drop{ + if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop{ self.schedule_drop(span, region_scope, local_id, DropKind::Storage); } Place::from(local_id) @@ -708,12 +707,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn schedule_drop_for_binding( &mut self, - var: HirId, + var: LocalVarId, span: Span, for_guard: ForGuard, ) { let local_id = self.var_local_id(var, for_guard); - if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) { + if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) { self.schedule_drop(span, region_scope, local_id, DropKind::Value); } } @@ -730,7 +729,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability, Symbol, BindingMode, - HirId, + LocalVarId, Span, Ty<'tcx>, UserTypeProjections, @@ -917,7 +916,7 @@ fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>( struct Binding<'tcx> { span: Span, source: Place<'tcx>, - var_id: HirId, + var_id: LocalVarId, binding_mode: BindingMode, } @@ -2184,7 +2183,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mutability: Mutability, name: Symbol, mode: BindingMode, - var_id: HirId, + var_id: LocalVarId, var_ty: Ty<'tcx>, user_ty: UserTypeProjections, has_guard: ArmHasGuard, diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 4ae74433df6..793066e43c3 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -4,11 +4,12 @@ use crate::build::scope::DropKind; use crate::thir::constant::parse_float; use crate::thir::pattern::pat_from_hir; use rustc_ast as ast; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{GeneratorKind, HirIdMap, Node}; +use rustc_hir::{GeneratorKind, Node}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::hir::place::PlaceBase as HirPlaceBase; @@ -16,7 +17,7 @@ use rustc_middle::middle::region; use rustc_middle::mir::interpret::Allocation; use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar}; use rustc_middle::mir::*; -use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, PatKind, Thir}; +use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, LocalVarId, PatKind, Thir}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults}; use rustc_span::symbol::sym; @@ -445,7 +446,7 @@ struct Builder<'a, 'tcx> { /// Maps `HirId`s of variable bindings to the `Local`s created for them. /// (A match binding can have two locals; the 2nd is for the arm's guard.) - var_indices: HirIdMap<LocalsForNode>, + var_indices: FxHashMap<LocalVarId, LocalsForNode>, local_decls: IndexVec<Local, LocalDecl<'tcx>>, canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, upvar_mutbls: Vec<Mutability>, @@ -455,11 +456,11 @@ struct Builder<'a, 'tcx> { } impl<'a, 'tcx> Builder<'a, 'tcx> { - fn is_bound_var_in_guard(&self, id: hir::HirId) -> bool { + fn is_bound_var_in_guard(&self, id: LocalVarId) -> bool { self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id)) } - fn var_local_id(&self, id: hir::HirId, for_guard: ForGuard) -> Local { + fn var_local_id(&self, id: LocalVarId, for_guard: ForGuard) -> Local { self.var_indices[&id].local_id(for_guard) } } @@ -543,11 +544,11 @@ enum LocalsForNode { #[derive(Debug)] struct GuardFrameLocal { - id: hir::HirId, + id: LocalVarId, } impl GuardFrameLocal { - fn new(id: hir::HirId, _binding_mode: BindingMode) -> Self { + fn new(id: LocalVarId, _binding_mode: BindingMode) -> Self { GuardFrameLocal { id } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index bd9f599fff0..fb2f5861c6f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -903,9 +903,12 @@ impl<'tcx> Cx<'tcx> { ); if is_upvar { - ExprKind::UpvarRef { closure_def_id: self.body_owner, var_hir_id } + ExprKind::UpvarRef { + closure_def_id: self.body_owner, + var_hir_id: LocalVarId(var_hir_id), + } } else { - ExprKind::VarRef { id: var_hir_id } + ExprKind::VarRef { id: LocalVarId(var_hir_id) } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index e0dec1daf63..417cf0f89c4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue}; use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput}; use rustc_middle::mir::{self, UserTypeProjection}; use rustc_middle::mir::{BorrowKind, Field, Mutability}; -use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange}; +use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange}; use rustc_middle::ty::subst::{GenericArg, SubstsRef}; use rustc_middle::ty::CanonicalUserTypeAnnotation; use rustc_middle::ty::{self, AdtDef, ConstKind, DefIdTree, Region, Ty, TyCtxt, UserType}; @@ -288,7 +288,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { mutability, mode, name: ident.name, - var: id, + var: LocalVarId(id), ty: var_ty, subpattern: self.lower_opt_pattern(sub), is_primary: id == pat.hir_id, @@ -664,7 +664,7 @@ macro_rules! ClonePatternFoldableImpls { } ClonePatternFoldableImpls! { <'tcx> - Span, Field, Mutability, Symbol, hir::HirId, usize, ty::Const<'tcx>, + Span, Field, Mutability, Symbol, LocalVarId, usize, ty::Const<'tcx>, Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>, SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>, UserTypeProjection, CanonicalUserTypeAnnotation<'tcx> diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 4981ab5152c..627fe3f7f57 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -85,13 +85,7 @@ where self.super_rvalue(rvalue, location); match rvalue { - mir::Rvalue::AddressOf(_mt, borrowed_place) => { - if !borrowed_place.is_indirect() { - self.trans.gen(borrowed_place.local); - } - } - - mir::Rvalue::Ref(_, _kind, borrowed_place) => { + mir::Rvalue::AddressOf(_, borrowed_place) | mir::Rvalue::Ref(_, _, borrowed_place) => { if !borrowed_place.is_indirect() { self.trans.gen(borrowed_place.local); } @@ -145,3 +139,23 @@ where } } } + +/// The set of locals that are borrowed at some point in the MIR body. +pub fn borrowed_locals(body: &Body<'_>) -> BitSet<Local> { + struct Borrowed(BitSet<Local>); + + impl GenKill<Local> for Borrowed { + #[inline] + fn gen(&mut self, elem: Local) { + self.0.gen(elem) + } + #[inline] + fn kill(&mut self, _: Local) { + // Ignore borrow invalidation. + } + } + + let mut borrowed = Borrowed(BitSet::new_empty(body.local_decls.len())); + TransferFunction { trans: &mut borrowed }.visit_body(body); + borrowed.0 +} diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index 41cf43fc8e1..af6a1bb1545 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -23,6 +23,7 @@ mod init_locals; mod liveness; mod storage_liveness; +pub use self::borrowed_locals::borrowed_locals; pub use self::borrowed_locals::MaybeBorrowedLocals; pub use self::init_locals::MaybeInitializedLocals; pub use self::liveness::MaybeLiveLocals; diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 779f3c77815..28f3790914b 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -13,16 +13,15 @@ //! use rustc_index::bit_set::BitSet; -use rustc_middle::{ - mir::{visit::Visitor, *}, - ty::TyCtxt, -}; -use rustc_mir_dataflow::{impls::MaybeTransitiveLiveLocals, Analysis}; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::impls::{borrowed_locals, MaybeTransitiveLiveLocals}; +use rustc_mir_dataflow::Analysis; /// Performs the optimization on the body /// /// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It -/// can be generated via the [`get_borrowed_locals`] function. +/// can be generated via the [`borrowed_locals`] function. pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet<Local>) { let mut live = MaybeTransitiveLiveLocals::new(borrowed) .into_engine(tcx, body) @@ -73,67 +72,6 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS } } -pub fn get_borrowed_locals(body: &Body<'_>) -> BitSet<Local> { - let mut b = BorrowedLocals(BitSet::new_empty(body.local_decls.len())); - b.visit_body(body); - b.0 -} - -struct BorrowedLocals(BitSet<Local>); - -impl<'tcx> Visitor<'tcx> for BorrowedLocals { - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) { - self.super_rvalue(rvalue, loc); - match rvalue { - Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => { - if !borrowed_place.is_indirect() { - self.0.insert(borrowed_place.local); - } - } - - Rvalue::Cast(..) - | Rvalue::ShallowInitBox(..) - | Rvalue::Use(..) - | Rvalue::Repeat(..) - | Rvalue::Len(..) - | Rvalue::BinaryOp(..) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::NullaryOp(..) - | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) - | Rvalue::Aggregate(..) - | Rvalue::ThreadLocalRef(..) => {} - } - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - self.super_terminator(terminator, location); - - match terminator.kind { - TerminatorKind::Drop { place: dropped_place, .. } => { - if !dropped_place.is_indirect() { - self.0.insert(dropped_place.local); - } - } - - TerminatorKind::Abort - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::Assert { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Return - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable - | TerminatorKind::Yield { .. } - | TerminatorKind::InlineAsm { .. } => {} - } - } -} - pub struct DeadStoreElimination; impl<'tcx> MirPass<'tcx> for DeadStoreElimination { @@ -142,7 +80,7 @@ impl<'tcx> MirPass<'tcx> for DeadStoreElimination { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let borrowed = get_borrowed_locals(body); + let borrowed = borrowed_locals(body); eliminate(tcx, body, &borrowed); } } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 182dd6f379c..84c7aada5e5 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -104,7 +104,7 @@ use rustc_middle::mir::{ Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::TyCtxt; -use rustc_mir_dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals}; +use rustc_mir_dataflow::impls::{borrowed_locals, MaybeInitializedLocals, MaybeLiveLocals}; use rustc_mir_dataflow::Analysis; // Empirical measurements have resulted in some observations: @@ -805,7 +805,7 @@ fn find_candidates<'tcx>(body: &Body<'tcx>) -> Vec<CandidateAssignment<'tcx>> { let mut visitor = FindAssignments { body, candidates: Vec::new(), - ever_borrowed_locals: ever_borrowed_locals(body), + ever_borrowed_locals: borrowed_locals(body), locals_used_as_array_index: locals_used_as_array_index(body), }; visitor.visit_body(body); @@ -886,69 +886,6 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool { } } -/// Walks MIR to find all locals that have their address taken anywhere. -fn ever_borrowed_locals(body: &Body<'_>) -> BitSet<Local> { - let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) }; - visitor.visit_body(body); - visitor.locals -} - -struct BorrowCollector { - locals: BitSet<Local>, -} - -impl<'tcx> Visitor<'tcx> for BorrowCollector { - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - self.super_rvalue(rvalue, location); - - match rvalue { - Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => { - if !borrowed_place.is_indirect() { - self.locals.insert(borrowed_place.local); - } - } - - Rvalue::Cast(..) - | Rvalue::ShallowInitBox(..) - | Rvalue::Use(..) - | Rvalue::Repeat(..) - | Rvalue::Len(..) - | Rvalue::BinaryOp(..) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::NullaryOp(..) - | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) - | Rvalue::Aggregate(..) - | Rvalue::ThreadLocalRef(..) => {} - } - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - self.super_terminator(terminator, location); - - match terminator.kind { - TerminatorKind::Drop { place: dropped_place, .. } - | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { - self.locals.insert(dropped_place.local); - } - - TerminatorKind::Abort - | TerminatorKind::Assert { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Return - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable - | TerminatorKind::Yield { .. } - | TerminatorKind::InlineAsm { .. } => {} - } - } -} - /// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`. /// /// Collect locals used as indices so we don't generate candidates that are impossible to apply diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 0e57c3c6979..0e52da57e60 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -9,6 +9,7 @@ #![feature(option_get_or_insert_default)] #![feature(trusted_step)] #![feature(try_blocks)] +#![feature(yeet_expr)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a4cdfdf55f9..6a44f5d6653 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -336,7 +336,7 @@ struct InInTypo { // SnapshotParser is used to create a snapshot of the parser // without causing duplicate errors being emitted when the `Parser` // is dropped. -pub(super) struct SnapshotParser<'a> { +pub struct SnapshotParser<'a> { parser: Parser<'a>, unclosed_delims: Vec<UnmatchedBrace>, } @@ -392,7 +392,7 @@ impl<'a> Parser<'a> { } /// Create a snapshot of the `Parser`. - pub(super) fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> { + pub fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> { let mut snapshot = self.clone(); let unclosed_delims = self.unclosed_delims.clone(); // Clear `unclosed_delims` in snapshot to avoid diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 20d9123e411..f8fa7a0941d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1220,12 +1220,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ident: Ident, def_id: LocalDefId, node_id: NodeId, - rule_spans: &[Span], + rule_spans: &[(usize, Span)], ) { if !ident.as_str().starts_with('_') { self.r.unused_macros.insert(def_id, (node_id, ident)); - for (rule_i, rule_span) in rule_spans.iter().enumerate() { - self.r.unused_macro_rules.insert((def_id, rule_i), (ident, *rule_span)); + for (rule_i, rule_span) in rule_spans.iter() { + self.r.unused_macro_rules.insert((def_id, *rule_i), (ident, *rule_span)); } } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 2e2d3674560..3fb34cdcd9b 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -870,7 +870,7 @@ impl<'a> Resolver<'a> { &mut self, item: &ast::Item, edition: Edition, - ) -> (SyntaxExtension, Vec<Span>) { + ) -> (SyntaxExtension, Vec<(usize, Span)>) { let (mut result, mut rule_spans) = compile_declarative_macro( &self.session, self.session.features_untracked(), diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index d89c61c2e44..007fa87189f 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1541,6 +1541,8 @@ options! { "choose the TLS model to use (`rustc --print tls-models` for details)"), trace_macros: bool = (false, parse_bool, [UNTRACKED], "for every macro invocation, print its name and arguments (default: no)"), + translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED], + "translate remapped paths into local paths when possible (default: yes)"), trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED], "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"), treat_err_as_bug: Option<NonZeroUsize> = (None, parse_treat_err_as_bug, [TRACKED], diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 185f500808f..353547a2fb8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -7,6 +7,7 @@ use crate::autoderef::Autoderef; use crate::infer::InferCtxt; use crate::traits::normalize_to; +use hir::HirId; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ @@ -21,11 +22,9 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; use rustc_middle::hir::map; use rustc_middle::ty::{ - self, - subst::{GenericArgKind, SubstsRef}, - suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, - GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt, - TypeFoldable, + self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, + GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable, + ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, }; use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_session::Limit; @@ -324,7 +323,7 @@ pub trait InferCtxtExt<'tcx> { fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) { ( generics.tail_span_for_predicate_suggestion(), - format!("{} {}", if generics.has_where_clause { "," } else { " where" }, pred,), + format!("{} {}", generics.add_where_or_trailing_comma(), pred), ) } @@ -333,35 +332,53 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, St /// param for cleaner code. fn suggest_restriction<'tcx>( tcx: TyCtxt<'tcx>, - generics: &hir::Generics<'tcx>, + hir_id: HirId, + hir_generics: &hir::Generics<'tcx>, msg: &str, err: &mut Diagnostic, fn_sig: Option<&hir::FnSig<'_>>, projection: Option<&ty::ProjectionTy<'_>>, trait_pred: ty::PolyTraitPredicate<'tcx>, - super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>, -) { // When we are dealing with a trait, `super_traits` will be `Some`: // Given `trait T: A + B + C {}` // - ^^^^^^^^^ GenericBounds // | // &Ident - let span = generics.span_for_predicates_or_empty_place(); - if span.from_expansion() || span.desugaring_kind().is_some() { + super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>, +) { + if hir_generics.where_clause_span.from_expansion() + || hir_generics.where_clause_span.desugaring_kind().is_some() + { return; } + let Some(item_id) = hir_id.as_owner() else { return; }; + let generics = tcx.generics_of(item_id); // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`... - if let Some((bound_str, fn_sig)) = + if let Some((param, bound_str, fn_sig)) = fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind() { // Shenanigans to get the `Trait` from the `impl Trait`. ty::Param(param) => { - // `fn foo(t: impl Trait)` - // ^^^^^ get this string - param.name.as_str().strip_prefix("impl").map(|s| (s.trim_start().to_string(), sig)) + let param_def = generics.type_param(param, tcx); + if param_def.kind.is_synthetic() { + let bound_str = + param_def.name.as_str().strip_prefix("impl ")?.trim_start().to_string(); + return Some((param_def, bound_str, sig)); + } + None } _ => None, }) { + let type_param_name = hir_generics.params.next_type_param_name(Some(&bound_str)); + let trait_pred = trait_pred.fold_with(&mut ReplaceImplTraitFolder { + tcx, + param, + replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name)) + .to_ty(tcx), + }); + if !trait_pred.is_suggestable(tcx) { + return; + } // We know we have an `impl Trait` that doesn't satisfy a required projection. // Find all of the occurrences of `impl Trait` for `Trait` in the function arguments' @@ -370,40 +387,22 @@ fn suggest_restriction<'tcx>( // but instead we choose to suggest replacing all instances of `impl Trait` with `T` // where `T: Trait`. let mut ty_spans = vec![]; - let impl_trait_str = format!("impl {}", bound_str); for input in fn_sig.decl.inputs { - if let hir::TyKind::Path(hir::QPath::Resolved( - None, - hir::Path { segments: [segment], .. }, - )) = input.kind - { - if segment.ident.as_str() == impl_trait_str.as_str() { - // `fn foo(t: impl Trait)` - // ^^^^^^^^^^ get this to suggest `T` instead - - // There might be more than one `impl Trait`. - ty_spans.push(input.span); - } - } + ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id } + .visit_ty(input); } - - let type_param_name = generics.params.next_type_param_name(Some(&bound_str)); // The type param `T: Trait` we will suggest to introduce. let type_param = format!("{}: {}", type_param_name, bound_str); - // FIXME: modify the `trait_pred` instead of string shenanigans. - // Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`. - let pred = trait_pred.to_predicate(tcx).to_string(); - let pred = pred.replace(&impl_trait_str, &type_param_name); let mut sugg = vec![ - if let Some(span) = generics.span_for_param_suggestion() { + if let Some(span) = hir_generics.span_for_param_suggestion() { (span, format!(", {}", type_param)) } else { - (generics.span, format!("<{}>", type_param)) + (hir_generics.span, format!("<{}>", type_param)) }, // `fn foo(t: impl Trait)` // ^ suggest `where <T as Trait>::A: Bound` - predicate_constraint(generics, pred), + predicate_constraint(hir_generics, trait_pred.to_predicate(tcx).to_string()), ]; sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string()))); @@ -416,15 +415,20 @@ fn suggest_restriction<'tcx>( Applicability::MaybeIncorrect, ); } else { + if !trait_pred.is_suggestable(tcx) { + return; + } // Trivial case: `T` needs an extra bound: `T: Bound`. let (sp, suggestion) = match ( - generics + hir_generics .params .iter() .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })), super_traits, ) { - (_, None) => predicate_constraint(generics, trait_pred.to_predicate(tcx).to_string()), + (_, None) => { + predicate_constraint(hir_generics, trait_pred.to_predicate(tcx).to_string()) + } (None, Some((ident, []))) => ( ident.span.shrink_to_hi(), format!(": {}", trait_pred.print_modifiers_and_trait_path()), @@ -434,7 +438,7 @@ fn suggest_restriction<'tcx>( format!(" + {}", trait_pred.print_modifiers_and_trait_path()), ), (Some(_), Some((_, []))) => ( - generics.span.shrink_to_hi(), + hir_generics.span.shrink_to_hi(), format!(": {}", trait_pred.print_modifiers_and_trait_path()), ), }; @@ -455,6 +459,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, body_id: hir::HirId, ) { + let trait_pred = self.resolve_numeric_literals_with_default(trait_pred); + let self_ty = trait_pred.skip_binder().self_ty(); let (param_ty, projection) = match self_ty.kind() { ty::Param(_) => (true, None), @@ -462,16 +468,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => (false, None), }; - let generic_args_have_impl_trait = |args: SubstsRef<'tcx>| -> bool { - args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Type(ty) => match ty.kind() { - ty::Param(param) => param.name.as_str().starts_with("impl"), - _ => false, - }, - _ => false, - }) - }; - // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we // don't suggest `T: Sized + ?Sized`. let mut hir_id = body_id; @@ -486,6 +482,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Restricting `Self` for a single method. suggest_restriction( self.tcx, + hir_id, &generics, "`Self`", err, @@ -505,7 +502,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { assert!(param_ty); // Restricting `Self` for a single method. suggest_restriction( - self.tcx, &generics, "`Self`", err, None, projection, trait_pred, None, + self.tcx, hir_id, &generics, "`Self`", err, None, projection, trait_pred, + None, ); return; } @@ -526,6 +524,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( self.tcx, + hir_id, &generics, "the associated type", err, @@ -545,6 +544,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( self.tcx, + hir_id, &generics, "the associated type", err, @@ -573,6 +573,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | hir::Node::ImplItem(hir::ImplItem { generics, .. }) if param_ty => { + // We skip the 0'th subst (self) because we do not want + // to consider the predicate as not suggestible if the + // self type is an arg position `impl Trait` -- instead, + // we handle that by adding ` + Bound` below. + // FIXME(compiler-errors): It would be nice to do the same + // this that we do in `suggest_restriction` and pull the + // `impl Trait` into a new generic if it shows up somewhere + // else in the predicate. + if !trait_pred.skip_binder().trait_ref.substs[1..] + .iter() + .all(|g| g.is_suggestable(self.tcx)) + { + return; + } // Missing generic type parameter bound. let param_name = self_ty.to_string(); let constraint = with_no_trimmed_paths!( @@ -602,13 +616,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | hir::ItemKind::TraitAlias(generics, _) | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), .. - }) if !param_ty - && !generic_args_have_impl_trait(trait_pred.skip_binder().trait_ref.substs) => - { + }) if !param_ty => { // Missing generic type parameter bound. - let param_name = self_ty.to_string(); - let constraint = trait_pred.print_modifiers_and_trait_path().to_string(); - if suggest_arbitrary_trait_bound(generics, &mut err, ¶m_name, &constraint) { + if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) { return; } } @@ -2982,3 +2992,52 @@ fn suggest_trait_object_return_type_alternatives( ); } } + +/// Collect the spans that we see the generic param `param_did` +struct ReplaceImplTraitVisitor<'a> { + ty_spans: &'a mut Vec<Span>, + param_did: DefId, +} + +impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { + fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) { + if let hir::TyKind::Path(hir::QPath::Resolved( + None, + hir::Path { res: hir::def::Res::Def(_, segment_did), .. }, + )) = t.kind + { + if self.param_did == *segment_did { + // `fn foo(t: impl Trait)` + // ^^^^^^^^^^ get this to suggest `T` instead + + // There might be more than one `impl Trait`. + self.ty_spans.push(t.span); + return; + } + } + + hir::intravisit::walk_ty(self, t); + } +} + +// Replace `param` with `replace_ty` +struct ReplaceImplTraitFolder<'tcx> { + tcx: TyCtxt<'tcx>, + param: &'tcx ty::GenericParamDef, + replace_ty: Ty<'tcx>, +} + +impl<'tcx> TypeFolder<'tcx> for ReplaceImplTraitFolder<'tcx> { + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Param(ty::ParamTy { index, .. }) = t.kind() { + if self.param.index == *index { + return self.replace_ty; + } + } + t.super_fold_with(self) + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 8056198b20c..38ae6a25b18 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -5,7 +5,6 @@ use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{ self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, }; -use rustc_span::Span; use rustc_trait_selection::traits; fn sized_constraint_for_ty<'tcx>( @@ -103,21 +102,6 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain ty::AdtSizedConstraint(result) } -fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> { - tcx.hir() - .get_if_local(def_id) - .and_then(|node| match node { - // A `Ctor` doesn't have an identifier itself, but its parent - // struct/variant does. Compare with `hir::Map::opt_span`. - hir::Node::Ctor(ctor) => ctor - .ctor_hir_id() - .and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id))) - .and_then(|parent| parent.ident()), - _ => node.ident(), - }) - .map(|ident| ident.span) -} - /// See `ParamEnv` struct definition for details. #[instrument(level = "debug", skip(tcx))] fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { @@ -480,7 +464,6 @@ pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { asyncness, adt_sized_constraint, - def_ident_span, param_env, param_env_reveal_all_normalized, instance_def_size_estimate, diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 3fe4b5b46e0..60682aa3435 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::{ - self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt, + self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt, }; use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS; use rustc_span::{symbol::kw, Span}; diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 26e954b0026..b5025b794bb 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -27,7 +27,9 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ + self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeFoldable, +}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS}; use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 48bbd4d76ea..bf5bd744f62 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -41,8 +41,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::infer::InferOk; use rustc_middle::middle::stability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; -use rustc_middle::ty::error::ExpectedFound; -use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts}; +use rustc_middle::ty::error::TypeError::FieldMisMatch; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeFoldable}; use rustc_session::parse::feature_err; @@ -65,7 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, - extend_err: impl Fn(&mut Diagnostic), + extend_err: impl FnMut(&mut Diagnostic), ) -> Ty<'tcx> { self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected), extend_err) } @@ -74,7 +73,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, - extend_err: impl Fn(&mut Diagnostic), + mut extend_err: impl FnMut(&mut Diagnostic), ) -> Ty<'tcx> { let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool); let mut ty = self.check_expr_with_expectation(expr, expected); @@ -1480,10 +1479,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // re-link the regions that EIfEO can erase. self.demand_eqtype(span, adt_ty_hint, adt_ty); - let (substs, adt_kind, kind_name) = match adt_ty.kind() { - ty::Adt(adt, substs) => (substs, adt.adt_kind(), adt.variant_descr()), - _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields"), + let ty::Adt(adt, substs) = adt_ty.kind() else { + span_bug!(span, "non-ADT passed to check_expr_struct_fields"); }; + let adt_kind = adt.adt_kind(); let mut remaining_fields = variant .fields @@ -1521,7 +1520,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); } else { self.report_unknown_field( - adt_ty, variant, field, ast_fields, kind_name, expr_span, + adt_ty, + variant, + field, + ast_fields, + adt.variant_descr(), + expr_span, ); } @@ -1534,7 +1538,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Make sure the programmer specified correct number of fields. - if kind_name == "union" { + if adt_kind == AdtKind::Union { if ast_fields.len() != 1 { struct_span_err!( tcx.sess, @@ -1557,67 +1561,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: We are currently creating two branches here in order to maintain // consistency. But they should be merged as much as possible. let fru_tys = if self.tcx.features().type_changing_struct_update { - let base_ty = self.check_expr(base_expr); - match adt_ty.kind() { - ty::Adt(adt, substs) if adt.is_struct() => { - match base_ty.kind() { - ty::Adt(base_adt, base_subs) if adt == base_adt => { - variant - .fields - .iter() - .map(|f| { - let fru_ty = self.normalize_associated_types_in( - expr_span, - self.field_ty(base_expr.span, f, base_subs), - ); - let ident = self - .tcx - .adjust_ident(f.ident(self.tcx), variant.def_id); - if let Some(_) = remaining_fields.remove(&ident) { - let target_ty = - self.field_ty(base_expr.span, f, substs); - let cause = self.misc(base_expr.span); - match self - .at(&cause, self.param_env) - .sup(target_ty, fru_ty) - { - Ok(InferOk { obligations, value: () }) => { - self.register_predicates(obligations) - } - // FIXME: Need better diagnostics for `FieldMisMatch` error - Err(_) => { - self.report_mismatched_types( - &cause, - target_ty, - fru_ty, - FieldMisMatch(variant.name, ident.name), - ) - .emit(); - } - } + if let ty::Adt(adt, substs) = adt_ty.kind() && adt.is_struct() { + // Make an ADT with fresh inference substitutions. This + // will allow us to guide inference along so that, e.g. + // ``` + // let x = MyStruct<'a, B, const C: usize> { + // f: 1, + // ..Default::default() + // }; + // ``` + // will have the default base expression constrained to + // `MyStruct<'_, _, _>`, as opposed to just `_`... This + // will allow us to then do a subtyping relation on all + // of the `remaining_fields` below, per the RFC. + let fresh_substs = self.fresh_substs_for_item(base_expr.span, adt.did()); + let fresh_base_ty = self.tcx.mk_adt(*adt, fresh_substs); + let base_ty = self.check_expr_has_type_or_error( + base_expr, + fresh_base_ty, + |_| { + error_happened = true; + }, + ); + let base_ty = self.shallow_resolve(base_ty); + if let ty::Adt(base_adt, base_substs) = base_ty.kind() && adt == base_adt { + variant + .fields + .iter() + .map(|f| { + let fru_ty = self.normalize_associated_types_in( + expr_span, + self.field_ty(base_expr.span, f, base_substs), + ); + let ident = self + .tcx + .adjust_ident(f.ident(self.tcx), variant.def_id); + if let Some(_) = remaining_fields.remove(&ident) { + let target_ty = + self.field_ty(base_expr.span, f, substs); + let cause = self.misc(base_expr.span); + match self + .at(&cause, self.param_env) + .sup(target_ty, fru_ty) + { + Ok(InferOk { obligations, value: () }) => { + self.register_predicates(obligations) } - fru_ty - }) - .collect() - } - _ => { - self.report_mismatched_types( - &self.misc(base_expr.span), - adt_ty, - base_ty, - Sorts(ExpectedFound::new(true, adt_ty, base_ty)), - ) - .emit(); - return; - } + // FIXME: Need better diagnostics for `FieldMisMatch` error + Err(_) => { + self.report_mismatched_types( + &cause, + target_ty, + fru_ty, + FieldMisMatch(variant.name, ident.name), + ) + .emit(); + } + } + } + self.resolve_vars_if_possible(fru_ty) + }) + .collect() + } else { + if !error_happened && !base_ty.references_error() { + span_bug!(base_expr.span, "expected an error to have been reported in `check_expr_has_type_or_error`"); } - } - _ => { - self.tcx - .sess - .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); return; } + } else { + // Check the base_expr, regardless of a bad expected adt_ty, so we can get + // type errors on that expression, too. + self.check_expr(base_expr); + self.tcx + .sess + .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); + return; } } else { self.check_expr_has_type_or_error(base_expr, adt_ty, |_| { @@ -1653,7 +1671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys); - } else if kind_name != "union" && !remaining_fields.is_empty() { + } else if adt_kind != AdtKind::Union && !remaining_fields.is_empty() { let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| { !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) }); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index ca55a4299eb..99c766d54c8 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -15,7 +15,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt}; use rustc_infer::traits; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Binder, ToPredicate, Ty}; +use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty}; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 4071c389266..5f6ddc1e1c9 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -538,10 +538,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(hir::Node::Item(hir::Item { kind, .. })) = node { if let Some(g) = kind.generics() { - let key = match g.predicates { - [.., pred] => (pred.span().shrink_to_hi(), false), - [] => (g.span_for_predicates_or_empty_place(), true), - }; + let key = ( + g.tail_span_for_predicate_suggestion(), + g.add_where_or_trailing_comma(), + ); type_params .entry(key) .or_insert_with(FxHashSet::default) @@ -805,7 +805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .enumerate() .collect::<Vec<(usize, String)>>(); - for ((span, empty_where), obligations) in type_params.into_iter() { + for ((span, add_where_or_comma), obligations) in type_params.into_iter() { restrict_type_params = true; // #74886: Sort here so that the output is always the same. let mut obligations = obligations.into_iter().collect::<Vec<_>>(); @@ -817,11 +817,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait bound{s}", s = pluralize!(obligations.len()) ), - format!( - "{} {}", - if empty_where { " where" } else { "," }, - obligations.join(", ") - ), + format!("{} {}", add_where_or_comma, obligations.join(", ")), Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index d506314eb93..362e034ba54 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -421,7 +421,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe let suggestion = format!( "{} {}", - if !gat_item_hir.generics.predicates.is_empty() { "," } else { " where" }, + gat_item_hir.generics.add_where_or_trailing_comma(), unsatisfied_bounds.join(", "), ); err.span_suggestion( diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index de40126e724..5a70dc1e594 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -39,7 +39,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, Ty, TyCtxt}; use rustc_middle::ty::{ReprOptions, ToPredicate}; use rustc_session::lint; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 2fc9705527b..d613edf0ab0 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -211,7 +211,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); match tcx.hir().find(hir_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => { - generics.where_clause_span() + Some(generics.where_clause_span) } _ => { span_bug!(tcx.def_span(def_id), "main has a non-function type"); @@ -401,14 +401,17 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { .emit(); error = true; } - if let Some(sp) = generics.where_clause_span() { + if generics.has_where_clause_predicates { struct_span_err!( tcx.sess, - sp, + generics.where_clause_span, E0647, "start function is not allowed to have a `where` clause" ) - .span_label(sp, "start function cannot have a `where` clause") + .span_label( + generics.where_clause_span, + "start function cannot have a `where` clause", + ) .emit(); error = true; } diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 39dfd98ddcc..d5ed2c4adf4 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -271,6 +271,7 @@ impl str { /// let s = "this is old"; /// /// assert_eq!("this is new", s.replace("old", "new")); + /// assert_eq!("than an old", s.replace("is", "an")); /// ``` /// /// When the pattern doesn't match: diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 5eda860264c..866419ac34b 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -94,7 +94,7 @@ //! functions for requesting data from an object which implements `Provider`. Generally, end users //! should not call `request_*` directly, they are helper functions for intermediate implementers //! to use to implement a user-facing interface. This is purely for the sake of ergonomics, there is -//! safety concern here; intermediate implementers can typically support methods rather than +//! no safety concern here; intermediate implementers can typically support methods rather than //! free functions and use more specific names. //! //! Typically, a data provider is a trait object of a trait which extends `Provider`. A user will @@ -1007,7 +1007,7 @@ mod tags { type Reified = T; } - /// Type-based tag similar to [`Value`] but which may be unsized (i.e., has a `'Sized` bound). + /// Type-based tag similar to [`Value`] but which may be unsized (i.e., has a `?Sized` bound). #[derive(Debug)] pub struct MaybeSizedValue<T: ?Sized + 'static>(PhantomData<T>); diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index f281e8429c6..064675ee7cf 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -61,8 +61,8 @@ use self::Ordering::*; /// /// This trait can be used with `#[derive]`. When `derive`d on structs, two /// instances are equal if all fields are equal, and not equal if any fields -/// are not equal. When `derive`d on enums, each variant is equal to itself -/// and not equal to the other variants. +/// are not equal. When `derive`d on enums, two instances are equal if they +/// are the same variant and all fields are equal. /// /// ## How can I implement `PartialEq`? /// @@ -1349,7 +1349,7 @@ mod impls { impl PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &$t) -> Option<Ordering> { - match (self <= other, self >= other) { + match (*self <= *other, *self >= *other) { (false, false) => None, (false, true) => Some(Greater), (true, false) => Some(Less), diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index dbc3d2923ed..673a39c298f 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -795,7 +795,7 @@ pub(crate) mod builtin { /// /// Two such examples are macros and `#[cfg]` environments. /// - /// Emit better compiler error if a macro is passed invalid values. Without the final branch, + /// Emit a better compiler error if a macro is passed invalid values. Without the final branch, /// the compiler would still emit an error, but the error's message would not mention the two /// valid values. /// @@ -812,7 +812,7 @@ pub(crate) mod builtin { /// // ^ will fail at compile time with message "This macro only accepts `foo` or `bar`" /// ``` /// - /// Emit compiler error if one of a number of features isn't available. + /// Emit a compiler error if one of a number of features isn't available. /// /// ```compile_fail /// #[cfg(not(any(feature = "foo", feature = "bar")))] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 43cfb1bb640..cedeb27d6d9 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -350,7 +350,7 @@ impl AtomicBool { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, inline_const, scoped_threads)] + /// #![feature(atomic_from_mut, inline_const)] /// use std::sync::atomic::{AtomicBool, Ordering}; /// /// let mut some_bools = [const { AtomicBool::new(false) }; 10]; @@ -381,7 +381,7 @@ impl AtomicBool { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, scoped_threads)] + /// #![feature(atomic_from_mut)] /// use std::sync::atomic::{AtomicBool, Ordering}; /// /// let mut some_bools = [false; 10]; @@ -1015,7 +1015,7 @@ impl<T> AtomicPtr<T> { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, inline_const, scoped_threads)] + /// #![feature(atomic_from_mut, inline_const)] /// use std::ptr::null_mut; /// use std::sync::atomic::{AtomicPtr, Ordering}; /// @@ -1052,7 +1052,7 @@ impl<T> AtomicPtr<T> { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, scoped_threads)] + /// #![feature(atomic_from_mut)] /// use std::ptr::null_mut; /// use std::sync::atomic::{AtomicPtr, Ordering}; /// @@ -1607,7 +1607,7 @@ macro_rules! atomic_int { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, inline_const, scoped_threads)] + /// #![feature(atomic_from_mut, inline_const)] #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")] /// #[doc = concat!("let mut some_ints = [const { ", stringify!($atomic_type), "::new(0) }; 10];")] @@ -1640,7 +1640,7 @@ macro_rules! atomic_int { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, scoped_threads)] + /// #![feature(atomic_from_mut)] #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")] /// /// let mut some_ints = [0; 10]; diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 82cd3647040..e733766741d 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2161,7 +2161,9 @@ impl Termination for ! { impl<E: fmt::Debug> Termination for Result<!, E> { fn report(self) -> ExitCode { let Err(err) = self; - eprintln!("Error: {err:?}"); + // Ignore error if the write fails, for example because stderr is + // already closed. There is not much point panicking at this point. + let _ = writeln!(io::stderr(), "Error: {err:?}"); ExitCode::FAILURE } } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 7f9b297e9dc..f7af66ae5b5 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -183,10 +183,10 @@ use crate::time::Duration; #[macro_use] mod local; -#[unstable(feature = "scoped_threads", issue = "93203")] +#[stable(feature = "scoped_threads", since = "1.63.0")] mod scoped; -#[unstable(feature = "scoped_threads", issue = "93203")] +#[stable(feature = "scoped_threads", since = "1.63.0")] pub use scoped::{scope, Scope, ScopedJoinHandle}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index eeccc99b3a3..4fd076e4a2d 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -9,6 +9,7 @@ use crate::sync::Arc; /// A scope to spawn scoped threads in. /// /// See [`scope`] for details. +#[stable(feature = "scoped_threads", since = "1.63.0")] pub struct Scope<'scope, 'env: 'scope> { data: ScopeData, /// Invariance over 'scope, to make sure 'scope cannot shrink, @@ -17,8 +18,6 @@ pub struct Scope<'scope, 'env: 'scope> { /// Without invariance, this would compile fine but be unsound: /// /// ```compile_fail,E0373 - /// #![feature(scoped_threads)] - /// /// std::thread::scope(|s| { /// s.spawn(|| { /// let a = String::from("abcd"); @@ -33,6 +32,7 @@ pub struct Scope<'scope, 'env: 'scope> { /// An owned permission to join on a scoped thread (block on its termination). /// /// See [`Scope::spawn`] for details. +#[stable(feature = "scoped_threads", since = "1.63.0")] pub struct ScopedJoinHandle<'scope, T>(JoinInner<'scope, T>); pub(super) struct ScopeData { @@ -82,7 +82,6 @@ impl ScopeData { /// # Example /// /// ``` -/// #![feature(scoped_threads)] /// use std::thread; /// /// let mut a = vec![1, 2, 3]; @@ -126,6 +125,7 @@ impl ScopeData { /// /// The `'env: 'scope` bound is part of the definition of the `Scope` type. #[track_caller] +#[stable(feature = "scoped_threads", since = "1.63.0")] pub fn scope<'env, F, T>(f: F) -> T where F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T, @@ -183,6 +183,7 @@ impl<'scope, 'env> Scope<'scope, 'env> { /// to recover from such errors. /// /// [`join`]: ScopedJoinHandle::join + #[stable(feature = "scoped_threads", since = "1.63.0")] pub fn spawn<F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T> where F: FnOnce() -> T + Send + 'scope, @@ -207,7 +208,6 @@ impl Builder { /// # Example /// /// ``` - /// #![feature(scoped_threads)] /// use std::thread; /// /// let mut a = vec![1, 2, 3]; @@ -240,6 +240,7 @@ impl Builder { /// a.push(4); /// assert_eq!(x, a.len()); /// ``` + #[stable(feature = "scoped_threads", since = "1.63.0")] pub fn spawn_scoped<'scope, 'env, F, T>( self, scope: &'scope Scope<'scope, 'env>, @@ -259,8 +260,6 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> { /// # Examples /// /// ``` - /// #![feature(scoped_threads)] - /// /// use std::thread; /// /// thread::scope(|s| { @@ -271,6 +270,7 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> { /// }); /// ``` #[must_use] + #[stable(feature = "scoped_threads", since = "1.63.0")] pub fn thread(&self) -> &Thread { &self.0.thread } @@ -292,8 +292,6 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> { /// # Examples /// /// ``` - /// #![feature(scoped_threads)] - /// /// use std::thread; /// /// thread::scope(|s| { @@ -303,6 +301,7 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> { /// assert!(t.join().is_err()); /// }); /// ``` + #[stable(feature = "scoped_threads", since = "1.63.0")] pub fn join(self) -> Result<T> { self.0.join() } @@ -316,11 +315,13 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> { /// /// This function does not block. To block while waiting on the thread to finish, /// use [`join`][Self::join]. + #[stable(feature = "scoped_threads", since = "1.63.0")] pub fn is_finished(&self) -> bool { Arc::strong_count(&self.0.packet) == 1 } } +#[stable(feature = "scoped_threads", since = "1.63.0")] impl fmt::Debug for Scope<'_, '_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Scope") @@ -331,6 +332,7 @@ impl fmt::Debug for Scope<'_, '_> { } } +#[stable(feature = "scoped_threads", since = "1.63.0")] impl<'scope, T> fmt::Debug for ScopedJoinHandle<'scope, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ScopedJoinHandle").finish_non_exhaustive() diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js index 9088e06e508..fc8b5678080 100644 --- a/src/librustdoc/html/static/.eslintrc.js +++ b/src/librustdoc/html/static/.eslintrc.js @@ -84,5 +84,10 @@ module.exports = { "no-implicit-globals": "error", "no-implied-eval": "error", "no-label-var": "error", + "no-lonely-if": "error", + "no-mixed-operators": "error", + "no-multi-assign": "error", + "no-return-assign": "error", + "no-script-url": "error", } }; diff --git a/src/test/ui/asm/x86_64/issue-82869.rs b/src/test/ui/asm/x86_64/issue-82869.rs index 3e632eaf88d..67933666eb5 100644 --- a/src/test/ui/asm/x86_64/issue-82869.rs +++ b/src/test/ui/asm/x86_64/issue-82869.rs @@ -1,3 +1,4 @@ +// needs-asm-support // only-x86_64 // Make sure rustc doesn't ICE on asm! for a foreign architecture. diff --git a/src/test/ui/asm/x86_64/issue-82869.stderr b/src/test/ui/asm/x86_64/issue-82869.stderr index 42be1b6de72..3cf9d6d1c1c 100644 --- a/src/test/ui/asm/x86_64/issue-82869.stderr +++ b/src/test/ui/asm/x86_64/issue-82869.stderr @@ -1,17 +1,17 @@ error: invalid register class `vreg`: unknown register class - --> $DIR/issue-82869.rs:10:32 + --> $DIR/issue-82869.rs:11:32 | LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { | ^^^^^^^^^^^ error: invalid register class `vreg`: unknown register class - --> $DIR/issue-82869.rs:10:45 + --> $DIR/issue-82869.rs:11:45 | LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { | ^^^^^^^^^^ error: invalid register `d0`: unknown register - --> $DIR/issue-82869.rs:10:57 + --> $DIR/issue-82869.rs:11:57 | LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { | _________________________________________________________^ diff --git a/src/test/ui/closures/issue-87461.stderr b/src/test/ui/closures/issue-87461.stderr index b35fa2b8c9a..0e788a16eb0 100644 --- a/src/test/ui/closures/issue-87461.stderr +++ b/src/test/ui/closures/issue-87461.stderr @@ -5,6 +5,12 @@ LL | Ok(()) | -- ^^ expected `u16`, found `()` | | | arguments to this enum variant are incorrect + | +note: tuple variant defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^ error[E0308]: mismatched types --> $DIR/issue-87461.rs:17:8 @@ -13,6 +19,12 @@ LL | Ok(()) | -- ^^ expected `u16`, found `()` | | | arguments to this enum variant are incorrect + | +note: tuple variant defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^ error[E0308]: mismatched types --> $DIR/issue-87461.rs:26:12 @@ -21,6 +33,12 @@ LL | Ok(()) | -- ^^ expected `u16`, found `()` | | | arguments to this enum variant are incorrect + | +note: tuple variant defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr index 42f469d9817..d5eefd35753 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr @@ -5,6 +5,12 @@ LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8 | ------------------------- ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements | | | arguments to this struct are incorrect + | +note: tuple struct defined here + --> $DIR/auxiliary/const_generic_lib.rs:1:12 + | +LL | pub struct Struct<const N: usize>(pub [u8; N]); + | ^^^^^^ error[E0308]: mismatched types --> $DIR/const-argument-cross-crate-mismatch.rs:8:65 @@ -13,6 +19,12 @@ LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, | ------------------------- ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements | | | arguments to this struct are incorrect + | +note: tuple struct defined here + --> $DIR/auxiliary/const_generic_lib.rs:1:12 + | +LL | pub struct Struct<const N: usize>(pub [u8; N]); + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/drop/repeat-drop.rs b/src/test/ui/drop/repeat-drop.rs index 03e832adb3b..a43612e5d85 100644 --- a/src/test/ui/drop/repeat-drop.rs +++ b/src/test/ui/drop/repeat-drop.rs @@ -1,4 +1,5 @@ // run-pass +// needs-unwind // ignore-wasm32-bare no unwinding panic // ignore-avr no unwinding panic // ignore-nvptx64 no unwinding panic diff --git a/src/test/ui/generator/resume-arg-late-bound.stderr b/src/test/ui/generator/resume-arg-late-bound.stderr index b5144c607a8..34ee4036cc5 100644 --- a/src/test/ui/generator/resume-arg-late-bound.stderr +++ b/src/test/ui/generator/resume-arg-late-bound.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | test(gen); | ^^^^^^^^^ one type is more general than the other | - = note: expected type `for<'a> Generator<&'a mut bool>` - found type `Generator<&mut bool>` + = note: expected trait `for<'a> Generator<&'a mut bool>` + found trait `Generator<&mut bool>` note: the lifetime requirement is introduced here --> $DIR/resume-arg-late-bound.rs:8:17 | diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr index 340371031e8..1e2575116a8 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | foo(bar, "string", |s| s.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected type `for<'r, 's> FnOnce<(&'r &'s str,)>` - found type `for<'r> FnOnce<(&'r &str,)>` + = note: expected trait `for<'r, 's> FnOnce<(&'r &'s str,)>` + found trait `for<'r> FnOnce<(&'r &str,)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 | @@ -23,8 +23,8 @@ error[E0308]: mismatched types LL | foo(bar, "string", |s| s.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected type `FnOnce<(&&str,)>` - found type `for<'r> FnOnce<(&'r &str,)>` + = note: expected trait `FnOnce<(&&str,)>` + found trait `for<'r> FnOnce<(&'r &str,)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 | @@ -42,8 +42,8 @@ error[E0308]: mismatched types LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected type `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>` - found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>` + = note: expected trait `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>` + found trait `for<'r> FnOnce<(&'r Wrapper<'_>,)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 | @@ -61,8 +61,8 @@ error[E0308]: mismatched types LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected type `FnOnce<(&Wrapper<'_>,)>` - found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>` + = note: expected trait `FnOnce<(&Wrapper<'_>,)>` + found trait `for<'r> FnOnce<(&'r Wrapper<'_>,)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 | diff --git a/src/test/ui/issues/issue-27942.stderr b/src/test/ui/issues/issue-27942.stderr index a0126b68fdc..7ea9345a668 100644 --- a/src/test/ui/issues/issue-27942.stderr +++ b/src/test/ui/issues/issue-27942.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | fn select(&self) -> BufferViewHandle<R>; | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected type `Resources<'_>` - found type `Resources<'a>` + = note: expected trait `Resources<'_>` + found trait `Resources<'a>` note: the anonymous lifetime defined here... --> $DIR/issue-27942.rs:5:15 | @@ -23,8 +23,8 @@ error[E0308]: mismatched types LL | fn select(&self) -> BufferViewHandle<R>; | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected type `Resources<'_>` - found type `Resources<'a>` + = note: expected trait `Resources<'_>` + found trait `Resources<'a>` note: the lifetime `'a` as defined here... --> $DIR/issue-27942.rs:3:18 | diff --git a/src/test/ui/issues/issue-35668.stderr b/src/test/ui/issues/issue-35668.stderr index 07409e9834a..84add5799ab 100644 --- a/src/test/ui/issues/issue-35668.stderr +++ b/src/test/ui/issues/issue-35668.stderr @@ -6,7 +6,7 @@ LL | a.iter().map(|a| a*a) | | | &T | -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | fn func<'a, T>(a: &'a [T]) -> impl Iterator<Item=&'a T> where &T: Mul<&T> { | +++++++++++++++++ diff --git a/src/test/ui/lifetimes/issue-79187-2.stderr b/src/test/ui/lifetimes/issue-79187-2.stderr index 06eac16c88f..6d8f2f56683 100644 --- a/src/test/ui/lifetimes/issue-79187-2.stderr +++ b/src/test/ui/lifetimes/issue-79187-2.stderr @@ -31,8 +31,8 @@ error[E0308]: mismatched types LL | take_foo(|a| a); | ^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected type `for<'r> Fn<(&'r i32,)>` - found type `Fn<(&i32,)>` + = note: expected trait `for<'r> Fn<(&'r i32,)>` + found trait `Fn<(&i32,)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-79187-2.rs:8:14 | diff --git a/src/test/ui/lifetimes/issue-79187.stderr b/src/test/ui/lifetimes/issue-79187.stderr index 3a993e88d8a..1d89d4dac5e 100644 --- a/src/test/ui/lifetimes/issue-79187.stderr +++ b/src/test/ui/lifetimes/issue-79187.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected type `for<'r> FnOnce<(&'r u32,)>` - found type `FnOnce<(&u32,)>` + = note: expected trait `for<'r> FnOnce<(&'r u32,)>` + found trait `FnOnce<(&u32,)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-79187.rs:4:13 | diff --git a/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr b/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr index 2906c05864b..d82b2684cce 100644 --- a/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr @@ -15,8 +15,8 @@ error[E0308]: mismatched types LL | f(data, identity) | ^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected type `for<'r> Fn<(&'r T,)>` - found type `Fn<(&T,)>` + = note: expected trait `for<'r> Fn<(&'r T,)>` + found trait `Fn<(&T,)>` note: the lifetime requirement is introduced here --> $DIR/issue_74400.rs:8:34 | diff --git a/src/test/ui/lint/unused/unused-macro-rules-compile-error.rs b/src/test/ui/lint/unused/unused-macro-rules-compile-error.rs new file mode 100644 index 00000000000..4d51db89bc0 --- /dev/null +++ b/src/test/ui/lint/unused/unused-macro-rules-compile-error.rs @@ -0,0 +1,27 @@ +#![deny(unused_macro_rules)] +// To make sure we are not hitting this +#![deny(unused_macros)] + +macro_rules! num { + (one) => { 1 }; + // Most simple (and common) case + (two) => { compile_error!("foo"); }; + // Some nested use + (two_) => { foo(compile_error!("foo")); }; + (three) => { 3 }; + (four) => { 4 }; //~ ERROR: rule of macro +} +const _NUM: u8 = num!(one) + num!(three); + +// compile_error not used as a macro invocation +macro_rules! num2 { + (one) => { 1 }; + // Only identifier present + (two) => { fn compile_error() {} }; //~ ERROR: rule of macro + // Only identifier and bang present + (two_) => { compile_error! }; //~ ERROR: rule of macro + (three) => { 3 }; +} +const _NUM2: u8 = num2!(one) + num2!(three); + +fn main() {} diff --git a/src/test/ui/lint/unused/unused-macro-rules-compile-error.stderr b/src/test/ui/lint/unused/unused-macro-rules-compile-error.stderr new file mode 100644 index 00000000000..76af8c967db --- /dev/null +++ b/src/test/ui/lint/unused/unused-macro-rules-compile-error.stderr @@ -0,0 +1,26 @@ +error: 5th rule of macro `num` is never used + --> $DIR/unused-macro-rules-compile-error.rs:12:5 + | +LL | (four) => { 4 }; + | ^^^^^^ + | +note: the lint level is defined here + --> $DIR/unused-macro-rules-compile-error.rs:1:9 + | +LL | #![deny(unused_macro_rules)] + | ^^^^^^^^^^^^^^^^^^ + +error: 3rd rule of macro `num2` is never used + --> $DIR/unused-macro-rules-compile-error.rs:22:5 + | +LL | (two_) => { compile_error! }; + | ^^^^^^ + +error: 2nd rule of macro `num2` is never used + --> $DIR/unused-macro-rules-compile-error.rs:20:5 + | +LL | (two) => { fn compile_error() {} }; + | ^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.rs b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.rs new file mode 100644 index 00000000000..a826026ec40 --- /dev/null +++ b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.rs @@ -0,0 +1,11 @@ +#![deny(unused_macro_rules)] + +macro_rules! foo { + (v) => {}; + (w) => {}; + () => 0; //~ ERROR: macro rhs must be delimited +} + +fn main() { + foo!(v); +} diff --git a/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.stderr b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.stderr new file mode 100644 index 00000000000..797c867103f --- /dev/null +++ b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.stderr @@ -0,0 +1,8 @@ +error: macro rhs must be delimited + --> $DIR/unused-macro-rules-malformed-rule.rs:6:11 + | +LL | () => 0; + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/lint/unused/unused-macros-malformed-rule.rs b/src/test/ui/lint/unused/unused-macros-malformed-rule.rs new file mode 100644 index 00000000000..d4c35fad9b0 --- /dev/null +++ b/src/test/ui/lint/unused/unused-macros-malformed-rule.rs @@ -0,0 +1,15 @@ +#![deny(unused_macros)] + +macro_rules! foo { //~ ERROR: unused macro definition + (v) => {}; + () => 0; //~ ERROR: macro rhs must be delimited +} + +macro_rules! bar { + (v) => {}; + () => 0; //~ ERROR: macro rhs must be delimited +} + +fn main() { + bar!(v); +} diff --git a/src/test/ui/lint/unused/unused-macros-malformed-rule.stderr b/src/test/ui/lint/unused/unused-macros-malformed-rule.stderr new file mode 100644 index 00000000000..9a880dccfbf --- /dev/null +++ b/src/test/ui/lint/unused/unused-macros-malformed-rule.stderr @@ -0,0 +1,26 @@ +error: macro rhs must be delimited + --> $DIR/unused-macros-malformed-rule.rs:5:11 + | +LL | () => 0; + | ^ + +error: macro rhs must be delimited + --> $DIR/unused-macros-malformed-rule.rs:10:11 + | +LL | () => 0; + | ^ + +error: unused macro definition: `foo` + --> $DIR/unused-macros-malformed-rule.rs:3:14 + | +LL | macro_rules! foo { + | ^^^ + | +note: the lint level is defined here + --> $DIR/unused-macros-malformed-rule.rs:1:9 + | +LL | #![deny(unused_macros)] + | ^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index bd36fab9288..c1a29dfc933 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | baz(|_| ()); | ^^^^^^^^^^^ one type is more general than the other | - = note: expected type `for<'r> Fn<(&'r (),)>` - found type `Fn<(&(),)>` + = note: expected trait `for<'r> Fn<(&'r (),)>` + found trait `Fn<(&(),)>` note: this closure does not fulfill the lifetime requirements --> $DIR/closure-mismatch.rs:8:9 | diff --git a/src/test/ui/mismatched_types/issue-35030.stderr b/src/test/ui/mismatched_types/issue-35030.stderr index f0dea75001c..5ea9bcfc122 100644 --- a/src/test/ui/mismatched_types/issue-35030.stderr +++ b/src/test/ui/mismatched_types/issue-35030.stderr @@ -11,6 +11,11 @@ LL | Some(true) | = note: expected type parameter `bool` (type parameter `bool`) found type `bool` (`bool`) +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/partialeq_help.rs b/src/test/ui/partialeq_help.rs index c3ba805405b..34b88b8a866 100644 --- a/src/test/ui/partialeq_help.rs +++ b/src/test/ui/partialeq_help.rs @@ -2,6 +2,11 @@ fn foo<T: PartialEq>(a: &T, b: T) { a == b; //~ ERROR E0277 } +fn foo2<T: PartialEq>(a: &T, b: T) where { + a == b; //~ ERROR E0277 +} + fn main() { foo(&1, 1); + foo2(&1, 1); } diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr index 528306b22dd..fdff94f425c 100644 --- a/src/test/ui/partialeq_help.stderr +++ b/src/test/ui/partialeq_help.stderr @@ -5,11 +5,23 @@ LL | a == b; | ^^ no implementation for `&T == T` | = help: the trait `PartialEq<T>` is not implemented for `&T` -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | fn foo<T: PartialEq>(a: &T, b: T) where &T: PartialEq<T> { | ++++++++++++++++++++++ -error: aborting due to previous error +error[E0277]: can't compare `&T` with `T` + --> $DIR/partialeq_help.rs:6:7 + | +LL | a == b; + | ^^ no implementation for `&T == T` + | + = help: the trait `PartialEq<T>` is not implemented for `&T` +help: consider extending the `where` clause, but there might be an alternative better way to express this requirement + | +LL | fn foo2<T: PartialEq>(a: &T, b: T) where &T: PartialEq<T> { + | ++++++++++++++++ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/pattern/pat-tuple-field-count-cross.stderr b/src/test/ui/pattern/pat-tuple-field-count-cross.stderr index cab8d4759df..07b678bc873 100644 --- a/src/test/ui/pattern/pat-tuple-field-count-cross.stderr +++ b/src/test/ui/pattern/pat-tuple-field-count-cross.stderr @@ -198,20 +198,19 @@ LL | pub struct S(pub u8, pub u8, pub u8); error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 3 fields --> $DIR/pat-tuple-field-count-cross.rs:24:9 | -LL | M() => {} - | ^^^ expected 3 fields, found 0 +LL | M() => {} + | ^^^ expected 3 fields, found 0 | - ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:1 + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12 | -LL | / pub struct M( -LL | | pub u8, - | | ------ -LL | | pub u8, - | | ------ -LL | | pub u8, - | | ------ tuple struct has 3 fields -LL | | ); - | |__- tuple struct defined here +LL | pub struct M( + | - tuple struct defined here +LL | pub u8, + | ------ +LL | pub u8, + | ------ +LL | pub u8, + | ------ tuple struct has 3 fields | help: use `_` to explicitly ignore each field | @@ -225,20 +224,19 @@ LL | M(..) => {} error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 3 fields --> $DIR/pat-tuple-field-count-cross.rs:25:11 | -LL | M(1) => {} - | ^ expected 3 fields, found 1 +LL | M(1) => {} + | ^ expected 3 fields, found 1 | - ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:1 + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12 | -LL | / pub struct M( -LL | | pub u8, - | | ------ -LL | | pub u8, - | | ------ -LL | | pub u8, - | | ------ tuple struct has 3 fields -LL | | ); - | |__- tuple struct defined here +LL | pub struct M( + | - tuple struct defined here +LL | pub u8, + | ------ +LL | pub u8, + | ------ +LL | pub u8, + | ------ tuple struct has 3 fields | help: use `_` to explicitly ignore each field | @@ -252,20 +250,19 @@ LL | M(1, ..) => {} error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields --> $DIR/pat-tuple-field-count-cross.rs:26:11 | -LL | M(xyz, abc) => {} - | ^^^ ^^^ expected 3 fields, found 2 +LL | M(xyz, abc) => {} + | ^^^ ^^^ expected 3 fields, found 2 | - ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:1 + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12 | -LL | / pub struct M( -LL | | pub u8, - | | ------ -LL | | pub u8, - | | ------ -LL | | pub u8, - | | ------ tuple struct has 3 fields -LL | | ); - | |__- tuple struct defined here +LL | pub struct M( + | - tuple struct defined here +LL | pub u8, + | ------ +LL | pub u8, + | ------ +LL | pub u8, + | ------ tuple struct has 3 fields | help: use `_` to explicitly ignore each field | @@ -275,20 +272,19 @@ LL | M(xyz, abc, _) => {} error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields --> $DIR/pat-tuple-field-count-cross.rs:27:11 | -LL | M(1, 2, 3, 4) => {} - | ^ ^ ^ ^ expected 3 fields, found 4 +LL | M(1, 2, 3, 4) => {} + | ^ ^ ^ ^ expected 3 fields, found 4 | - ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:1 + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12 | -LL | / pub struct M( -LL | | pub u8, - | | ------ -LL | | pub u8, - | | ------ -LL | | pub u8, - | | ------ tuple struct has 3 fields -LL | | ); - | |__- tuple struct defined here +LL | pub struct M( + | - tuple struct defined here +LL | pub u8, + | ------ +LL | pub u8, + | ------ +LL | pub u8, + | ------ tuple struct has 3 fields error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 0 fields --> $DIR/pat-tuple-field-count-cross.rs:36:16 @@ -438,20 +434,19 @@ LL | S(u8, u8, u8), error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 3 fields --> $DIR/pat-tuple-field-count-cross.rs:52:9 | -LL | E2::M() => {} - | ^^^^^^^ expected 3 fields, found 0 +LL | E2::M() => {} + | ^^^^^^^ expected 3 fields, found 0 | ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5 | -LL | / M( -LL | | u8, - | | -- -LL | | u8, - | | -- -LL | | u8, - | | -- tuple variant has 3 fields -LL | | ), - | |_____- tuple variant defined here +LL | M( + | - tuple variant defined here +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- tuple variant has 3 fields | help: use `_` to explicitly ignore each field | @@ -465,20 +460,19 @@ LL | E2::M(..) => {} error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 3 fields --> $DIR/pat-tuple-field-count-cross.rs:53:15 | -LL | E2::M(1) => {} - | ^ expected 3 fields, found 1 +LL | E2::M(1) => {} + | ^ expected 3 fields, found 1 | ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5 | -LL | / M( -LL | | u8, - | | -- -LL | | u8, - | | -- -LL | | u8, - | | -- tuple variant has 3 fields -LL | | ), - | |_____- tuple variant defined here +LL | M( + | - tuple variant defined here +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- tuple variant has 3 fields | help: use `_` to explicitly ignore each field | @@ -492,20 +486,19 @@ LL | E2::M(1, ..) => {} error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 3 fields --> $DIR/pat-tuple-field-count-cross.rs:54:15 | -LL | E2::M(xyz, abc) => {} - | ^^^ ^^^ expected 3 fields, found 2 +LL | E2::M(xyz, abc) => {} + | ^^^ ^^^ expected 3 fields, found 2 | ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5 | -LL | / M( -LL | | u8, - | | -- -LL | | u8, - | | -- -LL | | u8, - | | -- tuple variant has 3 fields -LL | | ), - | |_____- tuple variant defined here +LL | M( + | - tuple variant defined here +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- tuple variant has 3 fields | help: use `_` to explicitly ignore each field | @@ -515,20 +508,19 @@ LL | E2::M(xyz, abc, _) => {} error[E0023]: this pattern has 4 fields, but the corresponding tuple variant has 3 fields --> $DIR/pat-tuple-field-count-cross.rs:55:15 | -LL | E2::M(1, 2, 3, 4) => {} - | ^ ^ ^ ^ expected 3 fields, found 4 +LL | E2::M(1, 2, 3, 4) => {} + | ^ ^ ^ ^ expected 3 fields, found 4 | ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5 | -LL | / M( -LL | | u8, - | | -- -LL | | u8, - | | -- -LL | | u8, - | | -- tuple variant has 3 fields -LL | | ), - | |_____- tuple variant defined here +LL | M( + | - tuple variant defined here +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- tuple variant has 3 fields error: aborting due to 28 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr index 0788b17a1c0..64501c52374 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr @@ -15,7 +15,7 @@ note: required by a bound in `Foo::Bar` | LL | type Bar: ~const std::ops::Add; | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar` -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | impl const Foo for NonConstAdd where NonConstAdd: ~const Add { | +++++++++++++++++++++++++++++ diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr index 668e166c298..7542b81fe2a 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr @@ -14,7 +14,7 @@ note: required by a bound in `foo` | LL | const fn foo<T>() where T: ~const Tr {} | ^^^^^^^^^ required by this bound in `foo` -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | pub trait Foo where (): ~const Tr { | +++++++++++++++++++ diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 2ca56afbc57..b15a4cb110b 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | f: &id, | ^^^ one type is more general than the other | - = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>` - found type `Fn<(&Foo<'_>,)>` + = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>` + found trait `Fn<(&Foo<'_>,)>` error[E0308]: mismatched types --> $DIR/rfc1623.rs:28:8 @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | f: &id, | ^^^ one type is more general than the other | - = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>` - found type `Fn<(&Foo<'_>,)>` + = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>` + found trait `Fn<(&Foo<'_>,)>` error: implementation of `FnOnce` is not general enough --> $DIR/rfc1623.rs:28:8 diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs new file mode 100644 index 00000000000..3dfbef0ee90 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs @@ -0,0 +1,31 @@ +// check-pass + +#![feature(type_changing_struct_update)] +#![allow(incomplete_features)] + +use std::borrow::Cow; +use std::marker::PhantomData; + +#[derive(Default)] +struct NonGeneric { + field1: usize, +} + +#[derive(Default)] +struct Generic<T, U> { + field1: T, + field2: U, +} + +#[derive(Default)] +struct MoreGeneric<'a, const N: usize> { + // If only `for<const N: usize> [u32; N]: Default`... + field1: PhantomData<[u32; N]>, + field2: Cow<'a, str>, +} + +fn main() { + let default1 = NonGeneric { ..Default::default() }; + let default2: Generic<i32, f32> = Generic { ..Default::default() }; + let default3: MoreGeneric<'static, 12> = MoreGeneric { ..Default::default() }; +} diff --git a/src/test/ui/span/issue-71363.rs b/src/test/ui/span/issue-71363.rs index 3e85559caf9..bbb4a93623b 100644 --- a/src/test/ui/span/issue-71363.rs +++ b/src/test/ui/span/issue-71363.rs @@ -1,6 +1,4 @@ -// compile-flags: -Z simulate-remapped-rust-src-base=/rustc/xyz -Z ui-testing=no -// only-x86_64-unknown-linux-gnu -//---^ Limiting target as the above unstable flags don't play well on some environment. +// compile-flags: -Z simulate-remapped-rust-src-base=/rustc/xyz -Z translate-remapped-path-to-local-path=no -Z ui-testing=no struct MyError; impl std::error::Error for MyError {} @@ -8,3 +6,14 @@ impl std::error::Error for MyError {} //~| ERROR: `MyError` doesn't implement `Debug` fn main() {} + +// This test relies on library/std/src/error.rs *not* being included in the error message, so that +// we can test whether a file not included in the error message affects it (more specifically +// whether the line number of the excluded file affects the indentation of the other line numbers). +// +// To test this we're simulating a remap of the rust src base (so that library/std/src/error.rs +// does not point to a local file) *and* we're disabling the code to try mapping a remapped path to +// a local file (which would defeat the purpose of the former flag). +// +// Note that this comment is at the bottom of the file intentionally, as we need the line number of +// the impl to be lower than 10. diff --git a/src/test/ui/span/issue-71363.stderr b/src/test/ui/span/issue-71363.stderr index d54f21752b8..04e2b46c317 100644 --- a/src/test/ui/span/issue-71363.stderr +++ b/src/test/ui/span/issue-71363.stderr @@ -1,7 +1,7 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` - --> $DIR/issue-71363.rs:6:6 + --> $DIR/issue-71363.rs:4:6 | -6 | impl std::error::Error for MyError {} +4 | impl std::error::Error for MyError {} | ^^^^^^^^^^^^^^^^^ `MyError` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `MyError` @@ -9,9 +9,9 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` note: required by a bound in `std::error::Error` error[E0277]: `MyError` doesn't implement `Debug` - --> $DIR/issue-71363.rs:6:6 + --> $DIR/issue-71363.rs:4:6 | -6 | impl std::error::Error for MyError {} +4 | impl std::error::Error for MyError {} | ^^^^^^^^^^^^^^^^^ `MyError` cannot be formatted using `{:?}` | = help: the trait `Debug` is not implemented for `MyError` @@ -19,7 +19,7 @@ error[E0277]: `MyError` doesn't implement `Debug` note: required by a bound in `std::error::Error` help: consider annotating `MyError` with `#[derive(Debug)]` | -5 | #[derive(Debug)] +3 | #[derive(Debug)] | error: aborting due to 2 previous errors diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr index c8e1a232887..e68260e4a09 100644 --- a/src/test/ui/span/missing-unit-argument.stderr +++ b/src/test/ui/span/missing-unit-argument.stderr @@ -4,6 +4,11 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied LL | let _: Result<(), String> = Ok(); | ^^-- an argument of type `()` is missing | +note: tuple variant defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^ help: provide the argument | LL | let _: Result<(), String> = Ok(()); diff --git a/src/test/ui/specialization/default-associated-type-bound-2.stderr b/src/test/ui/specialization/default-associated-type-bound-2.stderr index 0fd1f65b0a2..91778ed0f4c 100644 --- a/src/test/ui/specialization/default-associated-type-bound-2.stderr +++ b/src/test/ui/specialization/default-associated-type-bound-2.stderr @@ -20,7 +20,7 @@ note: required by a bound in `X::U` | LL | type U: PartialEq<T>; | ^^^^^^^^^^^^ required by this bound in `X::U` -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | impl<B: 'static, T> X<B> for T where &'static B: PartialEq<B> { | ++++++++++++++++++++++++++++++ diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr index 991dde30629..aacbe1d9efb 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -8,6 +8,11 @@ LL | let _: Option<(i32, bool)> = Some(1, 2); | = note: expected tuple `(i32, bool)` found type `{integer}` +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ help: remove the extra argument | LL | let _: Option<(i32, bool)> = Some({(i32, bool)}); @@ -39,6 +44,11 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied LL | let _: Option<(i8,)> = Some(); | ^^^^-- an argument of type `(i8,)` is missing | +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ help: provide the argument | LL | let _: Option<(i8,)> = Some({(i8,)}); @@ -54,6 +64,11 @@ LL | let _: Option<(i32,)> = Some(5_usize); | = note: expected tuple `(i32,)` found type `usize` +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ error[E0308]: mismatched types --> $DIR/args-instead-of-tuple-errors.rs:17:34 @@ -65,6 +80,11 @@ LL | let _: Option<(i32,)> = Some((5_usize)); | = note: expected tuple `(i32,)` found type `usize` +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr index 7ec10e88142..f6d158782da 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr @@ -4,6 +4,11 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied LL | let _: Result<(i32, i8), ()> = Ok(1, 2); | ^^ | +note: tuple variant defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^ help: use parentheses to construct a tuple | LL | let _: Result<(i32, i8), ()> = Ok((1, 2)); @@ -15,6 +20,11 @@ error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied LL | let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi"); | ^^^^ | +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ help: use parentheses to construct a tuple | LL | let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi")); @@ -26,6 +36,11 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied LL | let _: Option<()> = Some(); | ^^^^-- an argument of type `()` is missing | +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ help: provide the argument | LL | let _: Option<()> = Some(()); @@ -41,6 +56,11 @@ LL | let _: Option<(i32,)> = Some(3); | = note: expected tuple `(i32,)` found type `{integer}` +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ help: use a trailing comma to create a tuple with one element | LL | let _: Option<(i32,)> = Some((3,)); @@ -56,6 +76,11 @@ LL | let _: Option<(i32,)> = Some((3)); | = note: expected tuple `(i32,)` found type `{integer}` +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ help: use a trailing comma to create a tuple with one element | LL | let _: Option<(i32,)> = Some((3,)); diff --git a/src/test/ui/suggestions/derive-macro-missing-bounds.stderr b/src/test/ui/suggestions/derive-macro-missing-bounds.stderr index 75658f58c8a..501d083e2bc 100644 --- a/src/test/ui/suggestions/derive-macro-missing-bounds.stderr +++ b/src/test/ui/suggestions/derive-macro-missing-bounds.stderr @@ -13,7 +13,7 @@ help: consider annotating `a::Inner<T>` with `#[derive(Debug)]` | LL | #[derive(Debug)] | -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | struct Outer<T>(Inner<T>) where a::Inner<T>: Debug; | ++++++++++++++++++++++++ diff --git a/src/test/ui/suggestions/invalid-bin-op.stderr b/src/test/ui/suggestions/invalid-bin-op.stderr index fe5e2b5816f..94bd2d41565 100644 --- a/src/test/ui/suggestions/invalid-bin-op.stderr +++ b/src/test/ui/suggestions/invalid-bin-op.stderr @@ -15,7 +15,7 @@ help: consider annotating `S<T>` with `#[derive(PartialEq)]` | LL | #[derive(PartialEq)] | -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | pub fn foo<T>(s: S<T>, t: S<T>) where S<T>: PartialEq { | +++++++++++++++++++++ diff --git a/src/test/ui/suggestions/issue-97677.rs b/src/test/ui/suggestions/issue-97677.rs new file mode 100644 index 00000000000..a4c3b1350b8 --- /dev/null +++ b/src/test/ui/suggestions/issue-97677.rs @@ -0,0 +1,6 @@ +fn add_ten<N>(n: N) -> N { + n + 10 + //~^ ERROR cannot add `{integer}` to `N` +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-97677.stderr b/src/test/ui/suggestions/issue-97677.stderr new file mode 100644 index 00000000000..ea563ea844d --- /dev/null +++ b/src/test/ui/suggestions/issue-97677.stderr @@ -0,0 +1,16 @@ +error[E0369]: cannot add `{integer}` to `N` + --> $DIR/issue-97677.rs:2:7 + | +LL | n + 10 + | - ^ -- {integer} + | | + | N + | +help: consider restricting type parameter `N` + | +LL | fn add_ten<N: std::ops::Add<i32>>(n: N) -> N { + | ++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/suggestions/issue-97760.rs b/src/test/ui/suggestions/issue-97760.rs new file mode 100644 index 00000000000..cf9c3c58dca --- /dev/null +++ b/src/test/ui/suggestions/issue-97760.rs @@ -0,0 +1,9 @@ +pub fn print_values(values: &impl IntoIterator) +where { + for x in values.into_iter() { + println!("{x}"); + //~^ ERROR <impl IntoIterator as IntoIterator>::Item` doesn't implement `std::fmt::Display + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-97760.stderr b/src/test/ui/suggestions/issue-97760.stderr new file mode 100644 index 00000000000..459556bddae --- /dev/null +++ b/src/test/ui/suggestions/issue-97760.stderr @@ -0,0 +1,18 @@ +error[E0277]: `<impl IntoIterator as IntoIterator>::Item` doesn't implement `std::fmt::Display` + --> $DIR/issue-97760.rs:4:20 + | +LL | println!("{x}"); + | ^ `<impl IntoIterator as IntoIterator>::Item` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `<impl IntoIterator as IntoIterator>::Item` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL ~ pub fn print_values<I: IntoIterator>(values: &I) +LL ~ where <I as IntoIterator>::Item: std::fmt::Display { + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/suggest-change-mut.rs b/src/test/ui/suggestions/suggest-change-mut.rs index a2bc6fd09b5..47dc7c343da 100644 --- a/src/test/ui/suggestions/suggest-change-mut.rs +++ b/src/test/ui/suggestions/suggest-change-mut.rs @@ -2,7 +2,7 @@ use std::io::{BufRead, BufReader, Read, Write}; -fn issue_81421<T: Read + Write>(mut stream: T) { //~ HELP consider introducing a `where` bound +fn issue_81421<T: Read + Write>(mut stream: T) { //~ HELP consider introducing a `where` clause let initial_message = format!("Hello world"); let mut buffer: Vec<u8> = Vec::new(); let bytes_written = stream.write_all(initial_message.as_bytes()); diff --git a/src/test/ui/suggestions/suggest-change-mut.stderr b/src/test/ui/suggestions/suggest-change-mut.stderr index 2fa69cd5a2c..be549239e36 100644 --- a/src/test/ui/suggestions/suggest-change-mut.stderr +++ b/src/test/ui/suggestions/suggest-change-mut.stderr @@ -16,7 +16,7 @@ help: consider removing the leading `&`-reference LL - let mut stream_reader = BufReader::new(&stream); LL + let mut stream_reader = BufReader::new(stream); | -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | fn issue_81421<T: Read + Write>(mut stream: T) where &T: std::io::Read { | +++++++++++++++++++++++ diff --git a/src/test/ui/traits/resolution-in-overloaded-op.stderr b/src/test/ui/traits/resolution-in-overloaded-op.stderr index 3ae6bf130cc..34fae64e4d2 100644 --- a/src/test/ui/traits/resolution-in-overloaded-op.stderr +++ b/src/test/ui/traits/resolution-in-overloaded-op.stderr @@ -6,7 +6,7 @@ LL | a * b | | | &T | -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | fn foo<T: MyMul<f64, f64>>(a: &T, b: f64) -> f64 where &T: Mul<f64> { | ++++++++++++++++++ diff --git a/src/test/ui/traits/suggest-where-clause.stderr b/src/test/ui/traits/suggest-where-clause.stderr index e2cdd368888..520ee0b5ea7 100644 --- a/src/test/ui/traits/suggest-where-clause.stderr +++ b/src/test/ui/traits/suggest-where-clause.stderr @@ -49,7 +49,7 @@ error[E0277]: the trait bound `u64: From<T>` is not satisfied LL | <u64 as From<T>>::from; | ^^^^^^^^^^^^^^^^^^^^^^ the trait `From<T>` is not implemented for `u64` | -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | fn check<T: Iterator, U: ?Sized>() where u64: From<T> { | ++++++++++++++++++ @@ -60,7 +60,7 @@ error[E0277]: the trait bound `u64: From<<T as Iterator>::Item>` is not satisfie LL | <u64 as From<<T as Iterator>::Item>>::from; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<<T as Iterator>::Item>` is not implemented for `u64` | -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | fn check<T: Iterator, U: ?Sized>() where u64: From<<T as Iterator>::Item> { | ++++++++++++++++++++++++++++++++++++++ diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr index 559820b1b1a..ed1cf1852e7 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | |x| x | ^^^^^ one type is more general than the other | - = note: expected type `for<'r> Fn<(&'r X,)>` - found type `Fn<(&X,)>` + = note: expected trait `for<'r> Fn<(&'r X,)>` + found trait `Fn<(&X,)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-57611-trait-alias.rs:21:9 | diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr index f4d8b4509d4..198f3e26393 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr @@ -5,7 +5,7 @@ LL | (a, a) | ^ the trait `From<&A>` is not implemented for `&'static B` | = note: required because of the requirements on the impl of `Into<&'static B>` for `&A` -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) where &'static B: From<&A> { | ++++++++++++++++++++++++++ diff --git a/src/test/ui/typeck/issue-46112.stderr b/src/test/ui/typeck/issue-46112.stderr index 93461507501..91381e8ef4a 100644 --- a/src/test/ui/typeck/issue-46112.stderr +++ b/src/test/ui/typeck/issue-46112.stderr @@ -8,6 +8,11 @@ LL | fn main() { test(Ok(())); } | = note: expected enum `Option<()>` found unit type `()` +note: tuple variant defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^ help: try wrapping the expression in `Some` | LL | fn main() { test(Ok(Some(()))); } diff --git a/src/test/ui/typeck/struct-enum-wrong-args.stderr b/src/test/ui/typeck/struct-enum-wrong-args.stderr index 721b2c821ef..aafb29f25d0 100644 --- a/src/test/ui/typeck/struct-enum-wrong-args.stderr +++ b/src/test/ui/typeck/struct-enum-wrong-args.stderr @@ -4,6 +4,11 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied LL | let _ = Some(3, 2); | ^^^^ - argument unexpected | +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ help: remove the extra argument | LL | let _ = Some(3); @@ -17,6 +22,11 @@ LL | let _ = Ok(3, 6, 2); | | | argument unexpected | +note: tuple variant defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^ help: remove the extra arguments | LL | let _ = Ok(3); @@ -28,6 +38,11 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied LL | let _ = Ok(); | ^^-- an argument is missing | +note: tuple variant defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^ help: provide the argument | LL | let _ = Ok({_}); diff --git a/src/test/ui/variance/variance-contravariant-arg-object.rs b/src/test/ui/variance/variance-contravariant-arg-object.rs index e7e24e16731..701fcaf6925 100644 --- a/src/test/ui/variance/variance-contravariant-arg-object.rs +++ b/src/test/ui/variance/variance-contravariant-arg-object.rs @@ -15,8 +15,8 @@ fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) //~^ ERROR lifetime may not live long enough } -fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>) - -> Box<dyn Get<&'max i32>> +fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) + -> Box<dyn Get<&'max i32>> where 'max : 'min { // Previously OK: diff --git a/src/test/ui/variance/variance-contravariant-arg-object.stderr b/src/test/ui/variance/variance-contravariant-arg-object.stderr index 162ec3a3f1e..ab28315e11e 100644 --- a/src/test/ui/variance/variance-contravariant-arg-object.stderr +++ b/src/test/ui/variance/variance-contravariant-arg-object.stderr @@ -14,7 +14,7 @@ LL | v error: lifetime may not live long enough --> $DIR/variance-contravariant-arg-object.rs:23:5 | -LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>) +LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) | ---- ---- lifetime `'max` defined here | | | lifetime `'min` defined here diff --git a/src/test/ui/variance/variance-covariant-arg-object.rs b/src/test/ui/variance/variance-covariant-arg-object.rs index 129cf054a3c..89cf3117afe 100644 --- a/src/test/ui/variance/variance-covariant-arg-object.rs +++ b/src/test/ui/variance/variance-covariant-arg-object.rs @@ -16,8 +16,8 @@ fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) //~^ ERROR lifetime may not live long enough } -fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>) - -> Box<dyn Get<&'max i32>> +fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) + -> Box<dyn Get<&'max i32>> where 'max : 'min { v diff --git a/src/test/ui/variance/variance-covariant-arg-object.stderr b/src/test/ui/variance/variance-covariant-arg-object.stderr index f73418509ba..51f8cb3ec75 100644 --- a/src/test/ui/variance/variance-covariant-arg-object.stderr +++ b/src/test/ui/variance/variance-covariant-arg-object.stderr @@ -14,7 +14,7 @@ LL | v error: lifetime may not live long enough --> $DIR/variance-covariant-arg-object.rs:23:5 | -LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>) +LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) | ---- ---- lifetime `'max` defined here | | | lifetime `'min` defined here diff --git a/src/test/ui/variance/variance-invariant-arg-object.rs b/src/test/ui/variance/variance-invariant-arg-object.rs index 4a470cc646a..7381b4130f8 100644 --- a/src/test/ui/variance/variance-invariant-arg-object.rs +++ b/src/test/ui/variance/variance-invariant-arg-object.rs @@ -12,8 +12,8 @@ fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) //~^ ERROR lifetime may not live long enough } -fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>) - -> Box<dyn Get<&'max i32>> +fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) + -> Box<dyn Get<&'max i32>> where 'max : 'min { v diff --git a/src/test/ui/variance/variance-invariant-arg-object.stderr b/src/test/ui/variance/variance-invariant-arg-object.stderr index 8acd5417de7..9793a36be06 100644 --- a/src/test/ui/variance/variance-invariant-arg-object.stderr +++ b/src/test/ui/variance/variance-invariant-arg-object.stderr @@ -14,7 +14,7 @@ LL | v error: lifetime may not live long enough --> $DIR/variance-invariant-arg-object.rs:19:5 | -LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>) +LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) | ---- ---- lifetime `'max` defined here | | | lifetime `'min` defined here |
