diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b9cfc3732dc7c..687ff0fb50580 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -309,7 +309,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { )); // Check first whether the source is accessible (issue #87060) - if self.infcx.tcx.sess.source_map().span_to_snippet(deref_target).is_ok() { + if self.infcx.tcx.sess.source_map().is_span_accessible(deref_target) { err.span_note(deref_target, "deref defined here"); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index d296a1a0ac61b..9c7671eee38d0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -975,14 +975,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.fn_self_span_reported.insert(fn_span) { err.span_note( // Check whether the source is accessible - if self - .infcx - .tcx - .sess - .source_map() - .span_to_snippet(self_arg.span) - .is_ok() - { + if self.infcx.tcx.sess.source_map().is_span_accessible(self_arg.span) { self_arg.span } else { fn_call_span diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 17376e59e09cc..1d083b0bf8268 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -299,7 +299,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { err.note(&format!("attempting to deref into `{}`", deref_target_ty)); // Check first whether the source is accessible (issue #87060) - if tcx.sess.source_map().span_to_snippet(deref_target).is_ok() { + if tcx.sess.source_map().is_span_accessible(deref_target) { err.span_note(deref_target, "deref defined here"); } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 6e5a0c813ac20..0aa7b117b89ba 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -226,7 +226,7 @@ impl Qualif for CustomEq { // because that component may be part of an enum variant (e.g., // `Option::::Some`), in which case some values of this type may be // structural-match (`Option::None`). - traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some() + traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty, true).is_some() } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_error_messages/locales/en-US/expand.ftl b/compiler/rustc_error_messages/locales/en-US/expand.ftl new file mode 100644 index 0000000000000..8d506a3ea8bbc --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/expand.ftl @@ -0,0 +1,5 @@ +expand-explain-doc-comment-outer = + outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match + +expand-explain-doc-comment-inner = + inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 5a482bc5b2c39..d16171cb162d6 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -33,11 +33,12 @@ pub use unic_langid::{langid, LanguageIdentifier}; fluent_messages! { borrowck => "../locales/en-US/borrowck.ftl", builtin_macros => "../locales/en-US/builtin_macros.ftl", + const_eval => "../locales/en-US/const_eval.ftl", + expand => "../locales/en-US/expand.ftl", lint => "../locales/en-US/lint.ftl", parser => "../locales/en-US/parser.ftl", privacy => "../locales/en-US/privacy.ftl", typeck => "../locales/en-US/typeck.ftl", - const_eval => "../locales/en-US/const_eval.ftl", } pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index ffe4ecebb2e36..e59a74e380ae3 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1558,7 +1558,7 @@ pub fn add_elided_lifetime_in_path_suggestion( insertion_span: Span, ) { diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n))); - if source_map.span_to_snippet(insertion_span).is_err() { + if !source_map.is_span_accessible(insertion_span) { // Do not try to suggest anything if generated by a proc-macro. return; } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index f40c365cbcc18..3e9ddd6aec075 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_feature::Features; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, @@ -25,6 +25,7 @@ use rustc_session::parse::ParseSess; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; +use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent}; use rustc_span::Span; @@ -345,7 +346,7 @@ fn expand_macro<'cx>( if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) { err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro"); } - + annotate_doc_comment(&mut err, sess.source_map(), span); // Check whether there's a missing comma in this macro call, like `println!("{}" a);` if let Some((arg, comma_span)) = arg.add_comma() { for lhs in lhses { @@ -453,7 +454,10 @@ pub fn compile_declarative_macro( Failure(token, msg) => { let s = parse_failure_msg(&token); let sp = token.span.substitute_dummy(def.span); - sess.parse_sess.span_diagnostic.struct_span_err(sp, &s).span_label(sp, msg).emit(); + let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, &s); + err.span_label(sp, msg); + annotate_doc_comment(&mut err, sess.source_map(), sp); + err.emit(); return dummy_syn_ext(); } Error(sp, msg) => { @@ -590,6 +594,34 @@ pub fn compile_declarative_macro( (mk_syn_ext(expander), rule_spans) } +#[derive(SessionSubdiagnostic)] +enum ExplainDocComment { + #[label(expand::explain_doc_comment_inner)] + Inner { + #[primary_span] + span: Span, + }, + #[label(expand::explain_doc_comment_outer)] + Outer { + #[primary_span] + span: Span, + }, +} + +fn annotate_doc_comment( + err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + sm: &SourceMap, + span: Span, +) { + if let Ok(src) = sm.span_to_snippet(span) { + if src.starts_with("///") || src.starts_with("/**") { + err.subdiagnostic(ExplainDocComment::Outer { span }); + } else if src.starts_with("//!") || src.starts_with("/*!") { + err.subdiagnostic(ExplainDocComment::Inner { span }); + } + } +} + fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 61ac3d14e50e2..75fd156ebfdf3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -432,7 +432,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { "`let` bindings require an \"irrefutable pattern\", like a `struct` or \ an `enum` with only one variant", ); - if self.tcx.sess.source_map().span_to_snippet(span).is_ok() { + if self.tcx.sess.source_map().is_span_accessible(span) { let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1)); let start_span = span.shrink_to_lo(); let end_span = semi_span.shrink_to_lo(); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index f22f3f61a01f2..e32e0b11ba497 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -120,32 +120,37 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option { - traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| { - with_no_trimmed_paths!(match non_sm_ty.kind { - traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt), - traits::NonStructuralMatchTyKind::Dynamic => { - "trait objects cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTyKind::Opaque => { - "opaque types cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTyKind::Closure => { - "closures cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTyKind::Generator => { - "generators cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTyKind::Param => { - bug!("use of a constant whose type is a parameter inside a pattern") - } - traits::NonStructuralMatchTyKind::Projection => { - bug!("use of a constant whose type is a projection inside a pattern") - } - traits::NonStructuralMatchTyKind::Foreign => { - bug!("use of a value of a foreign type inside a pattern") - } - }) - }) + traits::search_for_structural_match_violation(self.span, self.tcx(), ty, true).map( + |non_sm_ty| { + with_no_trimmed_paths!(match non_sm_ty.kind { + traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt), + traits::NonStructuralMatchTyKind::Dynamic => { + "trait objects cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Opaque => { + "opaque types cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Closure => { + "closures cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Generator => { + "generators cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Float => { + "floating-point numbers cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Param => { + bug!("use of a constant whose type is a parameter inside a pattern") + } + traits::NonStructuralMatchTyKind::Projection => { + bug!("use of a constant whose type is a projection inside a pattern") + } + traits::NonStructuralMatchTyKind::Foreign => { + bug!("use of a value of a foreign type inside a pattern") + } + }) + }, + ) } fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b4a39982b74b0..2851b08cd934e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1647,7 +1647,7 @@ impl<'a> Resolver<'a> { fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String { let res = b.res(); - if b.span.is_dummy() || self.session.source_map().span_to_snippet(b.span).is_err() { + if b.span.is_dummy() || !self.session.source_map().is_span_accessible(b.span) { // These already contain the "built-in" prefix or look bad with it. let add_built_in = !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 227127aed50d7..afbb88e923360 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -597,6 +597,13 @@ impl SourceMap { local_begin.sf.src.is_some() && local_end.sf.src.is_some() } + pub fn is_span_accessible(&self, sp: Span) -> bool { + self.span_to_source(sp, |src, start_index, end_index| { + Ok(src.get(start_index..end_index).is_some()) + }) + .map_or(false, |is_accessible| is_accessible) + } + /// Returns the source snippet as `String` corresponding to the given `Span`. pub fn span_to_snippet(&self, sp: Span) -> Result { self.span_to_source(sp, |src, start_index, end_index| { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index aa1c91362891b..34f4a9f790266 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -673,6 +673,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if !self.report_similar_impl_candidates( impl_candidates, trait_ref, + obligation.cause.body_id, &mut err, ) { // This is *almost* equivalent to @@ -707,6 +708,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.report_similar_impl_candidates( impl_candidates, trait_ref, + obligation.cause.body_id, &mut err, ); } @@ -1353,6 +1355,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> { &self, impl_candidates: Vec>, trait_ref: ty::PolyTraitRef<'tcx>, + body_id: hir::HirId, err: &mut Diagnostic, ) -> bool; @@ -1735,6 +1738,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { &self, impl_candidates: Vec>, trait_ref: ty::PolyTraitRef<'tcx>, + body_id: hir::HirId, err: &mut Diagnostic, ) -> bool { let report = |mut candidates: Vec>, err: &mut Diagnostic| { @@ -1805,8 +1809,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { || self.tcx.is_builtin_derive(def_id) }) .filter_map(|def_id| self.tcx.impl_trait_ref(def_id)) - // Avoid mentioning type parameters. - .filter(|trait_ref| !matches!(trait_ref.self_ty().kind(), ty::Param(_))) + .filter(|trait_ref| { + let self_ty = trait_ref.self_ty(); + // Avoid mentioning type parameters. + if let ty::Param(_) = self_ty.kind() { + false + } + // Avoid mentioning types that are private to another crate + else if let ty::Adt(def, _) = self_ty.peel_refs().kind() { + // FIXME(compiler-errors): This could be generalized, both to + // be more granular, and probably look past other `#[fundamental]` + // types, too. + self.tcx + .visibility(def.did()) + .is_accessible_from(body_id.owner.to_def_id(), self.tcx) + } else { + true + } + }) .collect(); return report(normalized_impl_candidates, err); } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 94ca138b9d20d..6c0b83fbd0304 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -26,6 +26,7 @@ pub enum NonStructuralMatchTyKind<'tcx> { Closure, Generator, Projection, + Float, } /// This method traverses the structure of `ty`, trying to find an @@ -53,12 +54,16 @@ pub enum NonStructuralMatchTyKind<'tcx> { /// For more background on why Rust has this requirement, and issues /// that arose when the requirement was not enforced completely, see /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307. +/// +/// The floats_allowed flag is used to deny constants in floating point pub fn search_for_structural_match_violation<'tcx>( span: Span, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, + floats_allowed: bool, ) -> Option> { - ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default() }).break_value() + ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), floats_allowed }) + .break_value() } /// This method returns true if and only if `adt_ty` itself has been marked as @@ -119,6 +124,8 @@ struct Search<'tcx> { /// Tracks ADTs previously encountered during search, so that /// we will not recur on them again. seen: FxHashSet, + + floats_allowed: bool, } impl<'tcx> Search<'tcx> { @@ -192,13 +199,24 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { // for empty array. return ControlFlow::CONTINUE; } - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => { // These primitive types are always structural match. // // `Never` is kind of special here, but as it is not inhabitable, this should be fine. return ControlFlow::CONTINUE; } + ty::Float(_) => { + if self.floats_allowed { + return ControlFlow::CONTINUE; + } else { + return ControlFlow::Break(NonStructuralMatchTy { + ty, + kind: NonStructuralMatchTyKind::Float, + }); + } + } + ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { // First check all contained types and then tell the caller to continue searching. return ty.super_visit_with(self); diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index d111008e82c83..c873cf27e42c5 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -164,10 +164,62 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { suggested_name, Applicability::MaybeIncorrect, ); - } else { - err.span_label(span, format!("associated type `{}` not found", assoc_name)); + return err.emit(); } + // If we didn't find a good item in the supertraits (or couldn't get + // the supertraits), like in ItemCtxt, then look more generally from + // all visible traits. If there's one clear winner, just suggest that. + + let visible_traits: Vec<_> = self + .tcx() + .all_traits() + .filter(|trait_def_id| { + let viz = self.tcx().visibility(*trait_def_id); + if let Some(def_id) = self.item_def_id() { + viz.is_accessible_from(def_id, self.tcx()) + } else { + viz.is_visible_locally() + } + }) + .collect(); + + let wider_candidate_names: Vec<_> = visible_traits + .iter() + .flat_map(|trait_def_id| { + self.tcx().associated_items(*trait_def_id).in_definition_order() + }) + .filter_map( + |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None }, + ) + .collect(); + + if let (Some(suggested_name), true) = ( + find_best_match_for_name(&wider_candidate_names, assoc_name.name, None), + assoc_name.span != DUMMY_SP, + ) { + if let [best_trait] = visible_traits + .iter() + .filter(|trait_def_id| { + self.tcx() + .associated_items(*trait_def_id) + .filter_by_name_unhygienic(suggested_name) + .any(|item| item.kind == ty::AssocKind::Type) + }) + .collect::>()[..] + { + err.span_label( + assoc_name.span, + format!( + "there is a similarly named associated type `{suggested_name}` in the trait `{}`", + self.tcx().def_path_str(*best_trait) + ), + ); + return err.emit(); + } + } + + err.span_label(span, format!("associated type `{}` not found", assoc_name)); err.emit() } diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index eb7e52c5ed376..dc553d1441e53 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -760,7 +760,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(call_span) = iter::successors(Some(expr.span), |s| s.parent_callsite()) .find(|&s| sp.contains(s)) - && sm.span_to_snippet(call_span).is_ok() + && sm.is_span_accessible(call_span) { return Some(( sp.with_hi(call_span.lo()), @@ -773,7 +773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } if sp.contains(expr.span) - && sm.span_to_snippet(expr.span).is_ok() + && sm.is_span_accessible(expr.span) { return Some(( sp.with_hi(expr.span.lo()), diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index f93f567fb2054..5621cf2e1a4b5 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -824,50 +824,62 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { } if let Some(non_structural_match_ty) = - traits::search_for_structural_match_violation(param.span, tcx, ty) + traits::search_for_structural_match_violation(param.span, tcx, ty, false) { // We use the same error code in both branches, because this is really the same // issue: we just special-case the message for type parameters to make it // clearer. - if let ty::Param(_) = ty.peel_refs().kind() { - // Const parameters may not have type parameters as their types, - // because we cannot be sure that the type parameter derives `PartialEq` - // and `Eq` (just implementing them is not enough for `structural_match`). - struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \ - used as the type of a const parameter", - ty, - ) - .span_label( - hir_ty.span, - format!("`{}` may not derive both `PartialEq` and `Eq`", ty), - ) - .note( - "it is not currently possible to use a type parameter as the type of a \ - const parameter", - ) - .emit(); - } else { - let mut diag = struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \ - the type of a const parameter", - non_structural_match_ty.ty, - ); - - if ty == non_structural_match_ty.ty { - diag.span_label( + match ty.peel_refs().kind() { + ty::Param(_) => { + // Const parameters may not have type parameters as their types, + // because we cannot be sure that the type parameter derives `PartialEq` + // and `Eq` (just implementing them is not enough for `structural_match`). + struct_span_err!( + tcx.sess, hir_ty.span, - format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"), - ); + E0741, + "`{ty}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \ + used as the type of a const parameter", + ) + .span_label( + hir_ty.span, + format!("`{ty}` may not derive both `PartialEq` and `Eq`"), + ) + .note( + "it is not currently possible to use a type parameter as the type of a \ + const parameter", + ) + .emit(); + } + ty::Float(_) => { + struct_span_err!( + tcx.sess, + hir_ty.span, + E0741, + "`{ty}` is forbidden as the type of a const generic parameter", + ) + .note("floats do not derive `Eq` or `Ord`, which are required for const parameters") + .emit(); } + _ => { + let mut diag = struct_span_err!( + tcx.sess, + hir_ty.span, + E0741, + "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \ + the type of a const parameter", + non_structural_match_ty.ty, + ); - diag.emit(); + if ty == non_structural_match_ty.ty { + diag.span_label( + hir_ty.span, + format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"), + ); + } + + diag.emit(); + } } } } else { diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index 265a57c392944..469f7d1172ae6 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -812,7 +812,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// Builds the `type defined here` message. fn show_definition(&self, err: &mut Diagnostic) { let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) { - if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() { + if self.tcx.sess.source_map().is_span_accessible(def_span) { def_span.into() } else { return; diff --git a/src/test/ui/const-generics/float-generic.adt_const_params.stderr b/src/test/ui/const-generics/float-generic.adt_const_params.stderr new file mode 100644 index 0000000000000..fef5ef0d1facf --- /dev/null +++ b/src/test/ui/const-generics/float-generic.adt_const_params.stderr @@ -0,0 +1,11 @@ +error[E0741]: `f32` is forbidden as the type of a const generic parameter + --> $DIR/float-generic.rs:5:17 + | +LL | fn foo() {} + | ^^^ + | + = note: floats do not derive `Eq` or `Ord`, which are required for const parameters + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/float-generic.rs b/src/test/ui/const-generics/float-generic.rs new file mode 100644 index 0000000000000..b72059b5b1c6a --- /dev/null +++ b/src/test/ui/const-generics/float-generic.rs @@ -0,0 +1,12 @@ +// revisions: simple adt_const_params +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] + +fn foo() {} +//~^ ERROR `f32` is forbidden as the type of a const generic parameter + +const C: f32 = 1.0; + +fn main() { + foo::(); +} diff --git a/src/test/ui/const-generics/float-generic.simple.stderr b/src/test/ui/const-generics/float-generic.simple.stderr new file mode 100644 index 0000000000000..89ca36b0f6314 --- /dev/null +++ b/src/test/ui/const-generics/float-generic.simple.stderr @@ -0,0 +1,11 @@ +error: `f32` is forbidden as the type of a const generic parameter + --> $DIR/float-generic.rs:5:17 + | +LL | fn foo() {} + | ^^^ + | + = note: the only supported types are integers, `bool` and `char` + = help: more complex types are supported with `#![feature(adt_const_params)]` + +error: aborting due to previous error + diff --git a/src/test/ui/parser/macro/macro-doc-comments-1.stderr b/src/test/ui/parser/macro/macro-doc-comments-1.stderr index 96bdb9808eefd..0ebf3d52b6372 100644 --- a/src/test/ui/parser/macro/macro-doc-comments-1.stderr +++ b/src/test/ui/parser/macro/macro-doc-comments-1.stderr @@ -5,7 +5,10 @@ LL | macro_rules! outer { | ------------------ when calling this macro ... LL | //! Inner - | ^^^^^^^^^ no rules expected this token in macro call + | ^^^^^^^^^ + | | + | no rules expected this token in macro call + | inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match error: aborting due to previous error diff --git a/src/test/ui/parser/macro/macro-doc-comments-2.stderr b/src/test/ui/parser/macro/macro-doc-comments-2.stderr index 023d1a3e039f8..346d865868d99 100644 --- a/src/test/ui/parser/macro/macro-doc-comments-2.stderr +++ b/src/test/ui/parser/macro/macro-doc-comments-2.stderr @@ -5,7 +5,10 @@ LL | macro_rules! inner { | ------------------ when calling this macro ... LL | /// Outer - | ^^^^^^^^^ no rules expected this token in macro call + | ^^^^^^^^^ + | | + | no rules expected this token in macro call + | outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-55673.rs b/src/test/ui/resolve/issue-55673.rs new file mode 100644 index 0000000000000..0436bd397424c --- /dev/null +++ b/src/test/ui/resolve/issue-55673.rs @@ -0,0 +1,12 @@ +trait Foo { + type Bar; +} + +fn foo() +where + T::Baa: std::fmt::Debug, + //~^ ERROR associated type `Baa` not found for `T` +{ +} + +fn main() {} diff --git a/src/test/ui/resolve/issue-55673.stderr b/src/test/ui/resolve/issue-55673.stderr new file mode 100644 index 0000000000000..39318f959056f --- /dev/null +++ b/src/test/ui/resolve/issue-55673.stderr @@ -0,0 +1,9 @@ +error[E0220]: associated type `Baa` not found for `T` + --> $DIR/issue-55673.rs:7:8 + | +LL | T::Baa: std::fmt::Debug, + | ^^^ there is a similarly named associated type `Bar` in the trait `Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0220`. diff --git a/src/test/ui/suggestions/auxiliary/meow.rs b/src/test/ui/suggestions/auxiliary/meow.rs new file mode 100644 index 0000000000000..115df70a69060 --- /dev/null +++ b/src/test/ui/suggestions/auxiliary/meow.rs @@ -0,0 +1,11 @@ +pub trait Meow { + fn meow(&self) {} +} + +pub struct GlobalMeow; + +impl Meow for GlobalMeow {} + +pub(crate) struct PrivateMeow; + +impl Meow for PrivateMeow {} diff --git a/src/test/ui/suggestions/issue-99080.rs b/src/test/ui/suggestions/issue-99080.rs new file mode 100644 index 0000000000000..91f574f35b80b --- /dev/null +++ b/src/test/ui/suggestions/issue-99080.rs @@ -0,0 +1,16 @@ +// aux-build:meow.rs + +extern crate meow; + +use meow::Meow; + +fn needs_meow(t: T) {} + +fn main() { + needs_meow(1usize); + //~^ ERROR the trait bound `usize: Meow` is not satisfied +} + +struct LocalMeow; + +impl Meow for LocalMeow {} diff --git a/src/test/ui/suggestions/issue-99080.stderr b/src/test/ui/suggestions/issue-99080.stderr new file mode 100644 index 0000000000000..d1908dd9d0d86 --- /dev/null +++ b/src/test/ui/suggestions/issue-99080.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `usize: Meow` is not satisfied + --> $DIR/issue-99080.rs:10:16 + | +LL | needs_meow(1usize); + | ---------- ^^^^^^ the trait `Meow` is not implemented for `usize` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `Meow`: + GlobalMeow + LocalMeow +note: required by a bound in `needs_meow` + --> $DIR/issue-99080.rs:7:18 + | +LL | fn needs_meow(t: T) {} + | ^^^^ required by this bound in `needs_meow` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr index 115539a6dc28d..6ce57b6263e41 100644 --- a/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr +++ b/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr @@ -15,7 +15,6 @@ LL | s.strip_suffix(b'\n').unwrap_or(s) &'c &'b str [char; N] char - pattern::MultiCharEqPattern = note: required because of the requirements on the impl of `Pattern<'_>` for `u8` error: aborting due to previous error diff --git a/src/test/ui/traits/issue-59029-1.stderr b/src/test/ui/traits/issue-59029-1.stderr index 53cdb8b1baf4c..203a89285306d 100644 --- a/src/test/ui/traits/issue-59029-1.stderr +++ b/src/test/ui/traits/issue-59029-1.stderr @@ -2,13 +2,13 @@ error[E0220]: associated type `Res` not found for `Self` --> $DIR/issue-59029-1.rs:5:52 | LL | trait MkSvc = Svc where Self::Res: Svc; - | ^^^ associated type `Res` not found + | ^^^ there is a similarly named associated type `Res` in the trait `Svc` error[E0220]: associated type `Res` not found for `Self` --> $DIR/issue-59029-1.rs:5:52 | LL | trait MkSvc = Svc where Self::Res: Svc; - | ^^^ associated type `Res` not found + | ^^^ there is a similarly named associated type `Res` in the trait `Svc` error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/not_well_formed.stderr b/src/test/ui/type-alias-impl-trait/not_well_formed.stderr index 91c1d031e4e5e..c36b95f47e837 100644 --- a/src/test/ui/type-alias-impl-trait/not_well_formed.stderr +++ b/src/test/ui/type-alias-impl-trait/not_well_formed.stderr @@ -2,7 +2,7 @@ error[E0220]: associated type `Assoc` not found for `V` --> $DIR/not_well_formed.rs:9:29 | LL | type Foo = impl Trait; - | ^^^^^ associated type `Assoc` not found + | ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc` error: aborting due to previous error