From 8449d10a29b09c0852660ee168a77083d8179cf2 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Thu, 27 Jun 2024 14:11:54 +0800 Subject: [PATCH 01/21] Extend rules of dead code analysis for impls for adts to impls for types refer to adts --- compiler/rustc_passes/src/dead.rs | 32 ++++++++----- .../dead-code/unused-impl-for-non-adts.rs | 45 +++++++++++++++++++ .../dead-code/unused-impl-for-non-adts.stderr | 20 +++++++++ 3 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 tests/ui/lint/dead-code/unused-impl-for-non-adts.rs create mode 100644 tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index bbd586386dd..0a3b6ae06df 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -54,7 +54,24 @@ impl Publicness { } } -fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool { +fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> { + match ty.kind { + TyKind::Path(hir::QPath::Resolved(_, path)) => { + if let Res::Def(def_kind, def_id) = path.res + && let Some(local_def_id) = def_id.as_local() + { + Some((local_def_id, def_kind)) + } else { + None + } + } + TyKind::Slice(ty) | TyKind::Array(ty, _) => adt_of(ty), + TyKind::Ptr(ty) | TyKind::Ref(_, ty) => adt_of(ty.ty), + _ => None, + } +} + +fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> bool { // treat PhantomData and positional ZST as public, // we don't want to lint types which only have them, // cause it's a common way to use such types to check things like well-formedness @@ -79,10 +96,7 @@ fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool { /// for enum and union, just check they are public, /// and doesn't solve types like &T for now, just skip them fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness { - if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind - && let Res::Def(def_kind, def_id) = path.res - && def_id.is_local() - { + if let Some((def_id, def_kind)) = adt_of(ty) { return match def_kind { DefKind::Enum | DefKind::Union => { let ty_is_public = tcx.visibility(def_id).is_public(); @@ -584,10 +598,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId, impl_item_id: LocalDefId) -> bool { - if let TyKind::Path(hir::QPath::Resolved(_, path)) = - self.tcx.hir().item(impl_id).expect_impl().self_ty.kind - && let Res::Def(def_kind, def_id) = path.res - && let Some(local_def_id) = def_id.as_local() + if let Some((local_def_id, def_kind)) = + adt_of(self.tcx.hir().item(impl_id).expect_impl().self_ty) && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) { if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id @@ -931,7 +943,7 @@ fn create_and_seed_worklist( match tcx.def_kind(id) { DefKind::Impl { .. } => false, DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), - DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), + DefKind::Struct => struct_all_fields_are_public(tcx, id) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), _ => true }) .map(|id| (id, ComesFromAllowExpect::No)) diff --git a/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs b/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs new file mode 100644 index 00000000000..46065dcee81 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs @@ -0,0 +1,45 @@ +#![deny(dead_code)] + +struct Foo; //~ ERROR struct `Foo` is never constructed + +trait Trait { //~ ERROR trait `Trait` is never used + fn foo(&self) {} +} + +impl Trait for Foo {} + +impl Trait for [Foo] {} +impl Trait for [Foo; N] {} + +impl Trait for *const Foo {} +impl Trait for *mut Foo {} + +impl Trait for &Foo {} +impl Trait for &&Foo {} +impl Trait for &mut Foo {} + +impl Trait for [&Foo] {} +impl Trait for &[Foo] {} +impl Trait for &*const Foo {} + +pub trait Trait2 { + fn foo(&self) {} +} + +impl Trait2 for Foo {} + +impl Trait2 for [Foo] {} +impl Trait2 for [Foo; N] {} + +impl Trait2 for *const Foo {} +impl Trait2 for *mut Foo {} + +impl Trait2 for &Foo {} +impl Trait2 for &&Foo {} +impl Trait2 for &mut Foo {} + +impl Trait2 for [&Foo] {} +impl Trait2 for &[Foo] {} +impl Trait2 for &*const Foo {} + +fn main() {} diff --git a/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr b/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr new file mode 100644 index 00000000000..e61fc403e81 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr @@ -0,0 +1,20 @@ +error: struct `Foo` is never constructed + --> $DIR/unused-impl-for-non-adts.rs:3:8 + | +LL | struct Foo; + | ^^^ + | +note: the lint level is defined here + --> $DIR/unused-impl-for-non-adts.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: trait `Trait` is never used + --> $DIR/unused-impl-for-non-adts.rs:5:7 + | +LL | trait Trait { + | ^^^^^ + +error: aborting due to 2 previous errors + From ef121f28d8684d32306becb7577b4e36d7c0ff08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 10 Jun 2024 03:38:09 +0200 Subject: [PATCH 02/21] Suggesting an available assoc item is always maybe-incorrect --- compiler/rustc_hir_analysis/src/errors.rs | 8 +++++--- .../rustc_hir_analysis/src/hir_ty_lowering/errors.rs | 12 +----------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c83788928a9..d1f9ad9d58b 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -126,12 +126,14 @@ pub enum AssocItemNotFoundSugg<'a> { assoc_kind: &'static str, suggested_name: Symbol, }, - #[suggestion(hir_analysis_assoc_item_not_found_other_sugg, code = "{suggested_name}")] + #[suggestion( + hir_analysis_assoc_item_not_found_other_sugg, + code = "{suggested_name}", + applicability = "maybe-incorrect" + )] Other { #[primary_span] span: Span, - #[applicability] - applicability: Applicability, ty_param_name: &'a str, assoc_kind: &'static str, suggested_name: Symbol, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 8ff6ced8b39..40675a1edba 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -269,20 +269,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // If we still couldn't find any associated item, and only one associated item exists, - // suggests using it. + // suggest using it. if let [candidate_name] = all_candidate_names.as_slice() { - // This should still compile, except on `#![feature(associated_type_defaults)]` - // where it could suggests `type A = Self::A`, thus recursing infinitely. - let applicability = - if assoc_kind == ty::AssocKind::Type && tcx.features().associated_type_defaults { - Applicability::Unspecified - } else { - Applicability::MaybeIncorrect - }; - err.sugg = Some(errors::AssocItemNotFoundSugg::Other { span: assoc_name.span, - applicability, ty_param_name, assoc_kind: assoc_kind_str, suggested_name: *candidate_name, From 898448ca5872aed82920dbb8342096e25e50aa5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 14 Jun 2024 12:28:23 +0200 Subject: [PATCH 03/21] HIR ty lowering: Refactor the way the projectee ("QSelf") gets passed to diagnostics --- compiler/rustc_hir_analysis/messages.ftl | 6 +- compiler/rustc_hir_analysis/src/errors.rs | 6 +- .../src/hir_ty_lowering/bounds.rs | 9 +-- .../src/hir_ty_lowering/errors.rs | 59 +++++++++------ .../src/hir_ty_lowering/mod.rs | 75 ++++++++++--------- 5 files changed, 86 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index cc404daa51f..c209bf20c43 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -1,4 +1,4 @@ -hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$ty_param_name}` +hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$qself}` .label = ambiguous associated {$assoc_kind} `{$assoc_name}` hir_analysis_ambiguous_lifetime_bound = @@ -12,14 +12,14 @@ hir_analysis_assoc_item_is_private = {$kind} `{$name}` is private .label = private {$kind} .defined_here_label = the {$kind} is defined here -hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}` +hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$qself}` hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identically_named -> [true] an *[false] a similarly named } associated {$assoc_kind} `{$suggested_name}` in the trait `{$trait_name}` hir_analysis_assoc_item_not_found_label = associated {$assoc_kind} `{$assoc_name}` not found -hir_analysis_assoc_item_not_found_other_sugg = `{$ty_param_name}` has the following associated {$assoc_kind} +hir_analysis_assoc_item_not_found_other_sugg = `{$qself}` has the following associated {$assoc_kind} hir_analysis_assoc_item_not_found_similar_in_other_trait_sugg = change the associated {$assoc_kind} name to use `{$suggested_name}` from `{$trait_name}` hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg = and also change the associated {$assoc_kind} name hir_analysis_assoc_item_not_found_similar_sugg = there is an associated {$assoc_kind} with a similar name diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index d1f9ad9d58b..8e8b3b3d32a 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -22,7 +22,7 @@ pub struct AmbiguousAssocItem<'a> { pub span: Span, pub assoc_kind: &'static str, pub assoc_name: Ident, - pub ty_param_name: &'a str, + pub qself: &'a str, } #[derive(Diagnostic)] @@ -75,7 +75,7 @@ pub struct AssocItemNotFound<'a> { pub span: Span, pub assoc_name: Ident, pub assoc_kind: &'static str, - pub ty_param_name: &'a str, + pub qself: &'a str, #[subdiagnostic] pub label: Option>, #[subdiagnostic] @@ -134,7 +134,7 @@ pub enum AssocItemNotFoundSugg<'a> { Other { #[primary_span] span: Span, - ty_param_name: &'a str, + qself: &'a str, assoc_kind: &'static str, suggested_name: Symbol, }, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 6f9c481650b..214eb6b2f06 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -6,7 +6,6 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; -use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; use rustc_span::symbol::Ident; use rustc_span::{ErrorGuaranteed, Span, Symbol}; @@ -16,9 +15,8 @@ use smallvec::SmallVec; use crate::bounds::Bounds; use crate::errors; -use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter}; - -use super::RegionInferReason; +use crate::hir_ty_lowering::HirTyLowerer; +use crate::hir_ty_lowering::{AssocItemQSelf, OnlySelfBounds, PredicateFilter, RegionInferReason}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Add a `Sized` bound to the `bounds` if appropriate. @@ -288,8 +286,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // one that does define it. self.probe_single_bound_for_assoc_item( || traits::supertraits(tcx, trait_ref), - trait_ref.skip_binder().print_only_trait_name(), - None, + AssocItemQSelf::Trait(trait_ref.def_id()), assoc_kind, constraint.ident, path_span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 40675a1edba..ca741e4fbb6 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -3,7 +3,7 @@ use crate::errors::{ ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits, }; use crate::fluent_generated as fluent; -use crate::hir_ty_lowering::HirTyLowerer; +use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; @@ -11,9 +11,9 @@ use rustc_errors::MultiSpan; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, }; +use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, Node}; +use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::query::Key; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; @@ -116,8 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub(super) fn complain_about_assoc_item_not_found( &self, all_candidates: impl Fn() -> I, - ty_param_name: &str, - ty_param_def_id: Option, + qself: AssocItemQSelf, assoc_kind: ty::AssocKind, assoc_name: Ident, span: Span, @@ -139,7 +138,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } - let assoc_kind_str = super::assoc_kind_str(assoc_kind); + let assoc_kind_str = assoc_kind_str(assoc_kind); + let qself_str = qself.to_string(tcx); // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a // valid span, so we point at the whole path segment instead. @@ -149,7 +149,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: if is_dummy { span } else { assoc_name.span }, assoc_name, assoc_kind: assoc_kind_str, - ty_param_name, + qself: &qself_str, label: None, sugg: None, }; @@ -219,19 +219,28 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { suggested_name, identically_named: suggested_name == assoc_name.name, }); - let hir = tcx.hir(); - if let Some(def_id) = ty_param_def_id - && let parent = hir.get_parent_item(tcx.local_def_id_to_hir_id(def_id)) - && let Some(generics) = hir.get_generics(parent.def_id) + if let AssocItemQSelf::TyParam(ty_param_def_id) = qself + // Not using `self.item_def_id()` here as that would yield the opaque type itself if we're + // inside an opaque type while we're interested in the overarching type alias (TAIT). + // FIXME: However, for trait aliases, this incorrectly returns the enclosing module... + && let item_def_id = + tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(ty_param_def_id)) + // FIXME: ...which obviously won't have any generics. + && let Some(generics) = tcx.hir().get_generics(item_def_id.def_id) { - if generics.bounds_for_param(def_id).flat_map(|pred| pred.bounds.iter()).any( - |b| match b { + // FIXME: Suggest adding supertrait bounds if we have a `Self` type param. + // FIXME(trait_alias): Suggest adding `Self: Trait` to + // `trait Alias = where Self::Proj:;` with `trait Trait { type Proj; }`. + if generics + .bounds_for_param(ty_param_def_id) + .flat_map(|pred| pred.bounds.iter()) + .any(|b| match b { hir::GenericBound::Trait(t, ..) => { t.trait_ref.trait_def_id() == Some(best_trait) } _ => false, - }, - ) { + }) + { // The type param already has a bound for `trait_name`, we just need to // change the associated item. err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait { @@ -247,7 +256,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx, generics, &mut err, - &ty_param_name, + &qself_str, &trait_name, None, None, @@ -273,7 +282,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let [candidate_name] = all_candidate_names.as_slice() { err.sugg = Some(errors::AssocItemNotFoundSugg::Other { span: assoc_name.span, - ty_param_name, + qself: &qself_str, assoc_kind: assoc_kind_str, suggested_name: *candidate_name, }); @@ -339,10 +348,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.dcx().emit_err(errors::AssocKindMismatch { span, - expected: super::assoc_kind_str(expected), - got: super::assoc_kind_str(got), + expected: assoc_kind_str(expected), + got: assoc_kind_str(got), expected_because_label, - assoc_kind: super::assoc_kind_str(assoc_item.kind), + assoc_kind: assoc_kind_str(assoc_item.kind), def_span: tcx.def_span(assoc_item.def_id), bound_on_assoc_const_label, wrap_in_braces_sugg, @@ -736,7 +745,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id)); in_expr_or_pat = match grandparent { - Node::Expr(_) | Node::Pat(_) => true, + hir::Node::Expr(_) | hir::Node::Pat(_) => true, _ => false, }; match bound.trait_ref.path.segments { @@ -1602,3 +1611,11 @@ fn generics_args_err_extend<'a>( _ => {} } } + +pub(super) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str { + match kind { + ty::AssocKind::Fn => "function", + ty::AssocKind::Const => "constant", + ty::AssocKind::Type => "type", + } +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d6eb1a66902..8d9055076a3 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -55,7 +55,6 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; -use std::fmt::Display; use std::slice; /// A path segment that is semantically allowed to have generic arguments. @@ -193,6 +192,25 @@ pub trait HirTyLowerer<'tcx> { } } +/// The "qualified self" of an associated item path. +/// +/// For diagnostic purposes only. +enum AssocItemQSelf { + Trait(DefId), + TyParam(LocalDefId), + SelfTyAlias, +} + +impl AssocItemQSelf { + fn to_string(&self, tcx: TyCtxt<'_>) -> String { + match *self { + Self::Trait(def_id) => tcx.def_path_str(def_id), + Self::TyParam(def_id) => tcx.hir().ty_param_name(def_id).to_string(), + Self::SelfTyAlias => kw::SelfUpper.to_string(), + } + } +} + /// New-typed boolean indicating whether explicit late-bound lifetimes /// are present in a set of generic arguments. /// @@ -811,19 +829,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let predicates = &self.probe_ty_param_bounds(span, ty_param_def_id, assoc_name).predicates; debug!("predicates={:#?}", predicates); - let param_name = tcx.hir().ty_param_name(ty_param_def_id); self.probe_single_bound_for_assoc_item( || { - traits::transitive_bounds_that_define_assoc_item( - tcx, - predicates - .iter() - .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))), - assoc_name, - ) + let trait_refs = predicates + .iter() + .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))); + traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_name) }, - param_name, - Some(ty_param_def_id), + AssocItemQSelf::TyParam(ty_param_def_id), ty::AssocKind::Type, assoc_name, span, @@ -835,12 +848,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// This fails if there is no such bound in the list of candidates or if there are multiple /// candidates in which case it reports ambiguity. - #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, constraint), ret)] + #[instrument(level = "debug", skip(self, all_candidates, qself, constraint), ret)] fn probe_single_bound_for_assoc_item( &self, all_candidates: impl Fn() -> I, - ty_param_name: impl Display, - ty_param_def_id: Option, + qself: AssocItemQSelf, assoc_kind: ty::AssocKind, assoc_name: Ident, span: Span, @@ -858,8 +870,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let Some(bound) = matching_candidates.next() else { let reported = self.complain_about_assoc_item_not_found( all_candidates, - &ty_param_name.to_string(), - ty_param_def_id, + qself, assoc_kind, assoc_name, span, @@ -872,13 +883,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let Some(bound2) = matching_candidates.next() { debug!(?bound2); - let assoc_kind_str = assoc_kind_str(assoc_kind); - let ty_param_name = &ty_param_name.to_string(); + let assoc_kind_str = errors::assoc_kind_str(assoc_kind); + let qself_str = qself.to_string(tcx); let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem { span, assoc_kind: assoc_kind_str, assoc_name, - ty_param_name, + qself: &qself_str, }); // Provide a more specific error code index entry for equality bindings. err.code( @@ -929,7 +940,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.span_suggestion_verbose( span.with_hi(assoc_name.span.lo()), "use fully-qualified syntax to disambiguate", - format!("<{ty_param_name} as {}>::", bound.print_only_trait_path()), + format!("<{qself_str} as {}>::", bound.print_only_trait_path()), Applicability::MaybeIncorrect, ); } @@ -943,7 +954,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if !where_bounds.is_empty() { err.help(format!( "consider introducing a new type parameter `T` and adding `where` constraints:\ - \n where\n T: {ty_param_name},\n{}", + \n where\n T: {qself_str},\n{}", where_bounds.join(",\n"), )); } @@ -997,11 +1008,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); let assoc_ident = assoc_segment.ident; - let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind { - path.res - } else { - Res::Err - }; // Check if we have an enum variant or an inherent associated type. let mut variant_resolution = None; @@ -1038,6 +1044,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind { + path.res + } else { + Res::Err + }; + // Find the type of the associated item, and the trait where the associated // item is declared. let bound = match (&qself_ty.kind(), qself_res) { @@ -1056,8 +1068,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Binder::dummy(trait_ref.instantiate_identity()), ) }, - kw::SelfUpper, - None, + AssocItemQSelf::SelfTyAlias, ty::AssocKind::Type, assoc_ident, span, @@ -2522,11 +2533,3 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(r) } } - -fn assoc_kind_str(kind: ty::AssocKind) -> &'static str { - match kind { - ty::AssocKind::Fn => "function", - ty::AssocKind::Const => "constant", - ty::AssocKind::Type => "type", - } -} From 3c8b1085127b64de64cb6d880b59b55c1d6fc8e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 14 Jun 2024 12:38:21 +0200 Subject: [PATCH 04/21] Inside eager ty aliases on unresolved assoc tys suggest fully qualifying instead of restricting their self ty --- compiler/rustc_hir_analysis/messages.ftl | 7 ++- compiler/rustc_hir_analysis/src/errors.rs | 16 ++++++ .../src/hir_ty_lowering/errors.rs | 55 ++++++++++++------- .../src/hir_ty_lowering/mod.rs | 8 ++- tests/ui/resolve/issue-55673.stderr | 2 +- ...solved-assoc-ty-suggest-trait.eager.stderr | 25 +++++++++ ...esolved-assoc-ty-suggest-trait.lazy.stderr | 29 ++++++++++ .../unresolved-assoc-ty-suggest-trait.rs | 20 +++++++ 8 files changed, 138 insertions(+), 24 deletions(-) create mode 100644 tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.eager.stderr create mode 100644 tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr create mode 100644 tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.rs diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index c209bf20c43..367f6e17e7f 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -20,8 +20,13 @@ hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identi } associated {$assoc_kind} `{$suggested_name}` in the trait `{$trait_name}` hir_analysis_assoc_item_not_found_label = associated {$assoc_kind} `{$assoc_name}` not found hir_analysis_assoc_item_not_found_other_sugg = `{$qself}` has the following associated {$assoc_kind} +hir_analysis_assoc_item_not_found_similar_in_other_trait_qpath_sugg = + consider fully qualifying{$identically_named -> + [true] {""} + *[false] {" "}and renaming + } the associated {$assoc_kind} hir_analysis_assoc_item_not_found_similar_in_other_trait_sugg = change the associated {$assoc_kind} name to use `{$suggested_name}` from `{$trait_name}` -hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg = and also change the associated {$assoc_kind} name +hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg = ...and changing the associated {$assoc_kind} name hir_analysis_assoc_item_not_found_similar_sugg = there is an associated {$assoc_kind} with a similar name hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got} diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 8e8b3b3d32a..90861ba1ff8 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -126,6 +126,22 @@ pub enum AssocItemNotFoundSugg<'a> { assoc_kind: &'static str, suggested_name: Symbol, }, + #[multipart_suggestion( + hir_analysis_assoc_item_not_found_similar_in_other_trait_qpath_sugg, + style = "verbose", + applicability = "maybe-incorrect" + )] + SimilarInOtherTraitQPath { + #[suggestion_part(code = "<")] + lo: Span, + #[suggestion_part(code = " as {trait_}>")] + mi: Span, + #[suggestion_part(code = "{suggested_name}")] + hi: Option, + trait_: &'a str, + suggested_name: Symbol, + identically_named: bool, + }, #[suggestion( hir_analysis_assoc_item_not_found_other_sugg, code = "{suggested_name}", diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index ca741e4fbb6..fd2bbabe779 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -219,7 +219,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { suggested_name, identically_named: suggested_name == assoc_name.name, }); - if let AssocItemQSelf::TyParam(ty_param_def_id) = qself + if let AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span) = qself // Not using `self.item_def_id()` here as that would yield the opaque type itself if we're // inside an opaque type while we're interested in the overarching type alias (TAIT). // FIXME: However, for trait aliases, this incorrectly returns the enclosing module... @@ -251,27 +251,44 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return self.dcx().emit_err(err); } - let mut err = self.dcx().create_err(err); - if suggest_constraining_type_param( - tcx, - generics, - &mut err, - &qself_str, - &trait_name, - None, - None, - ) && suggested_name != assoc_name.name + let identically_named = suggested_name == assoc_name.name; + + if let DefKind::TyAlias = tcx.def_kind(item_def_id) + && !tcx.type_alias_is_lazy(item_def_id) { - // We suggested constraining a type parameter, but the associated item on it - // was also not an exact match, so we also suggest changing it. - err.span_suggestion_verbose( - assoc_name.span, - fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg, + err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTraitQPath { + lo: ty_param_span.shrink_to_lo(), + mi: ty_param_span.shrink_to_hi(), + hi: (!identically_named).then_some(assoc_name.span), + // FIXME(fmease): Use a full trait ref here (with placeholders). + trait_: &trait_name, + identically_named, suggested_name, - Applicability::MaybeIncorrect, - ); + }); + } else { + let mut err = self.dcx().create_err(err); + if suggest_constraining_type_param( + tcx, + generics, + &mut err, + &qself_str, + // FIXME(fmease): Use a full trait ref here (with placeholders). + &trait_name, + None, + None, + ) && !identically_named + { + // We suggested constraining a type parameter, but the associated item on it + // was also not an exact match, so we also suggest changing it. + err.span_suggestion_verbose( + assoc_name.span, + fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg, + suggested_name, + Applicability::MaybeIncorrect, + ); + } + return err.emit(); } - return err.emit(); } return self.dcx().emit_err(err); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 8d9055076a3..ce298641e60 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -197,7 +197,7 @@ pub trait HirTyLowerer<'tcx> { /// For diagnostic purposes only. enum AssocItemQSelf { Trait(DefId), - TyParam(LocalDefId), + TyParam(LocalDefId, Span), SelfTyAlias, } @@ -205,7 +205,7 @@ impl AssocItemQSelf { fn to_string(&self, tcx: TyCtxt<'_>) -> String { match *self { Self::Trait(def_id) => tcx.def_path_str(def_id), - Self::TyParam(def_id) => tcx.hir().ty_param_name(def_id).to_string(), + Self::TyParam(def_id, _) => tcx.hir().ty_param_name(def_id).to_string(), Self::SelfTyAlias => kw::SelfUpper.to_string(), } } @@ -820,6 +820,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn probe_single_ty_param_bound_for_assoc_ty( &self, ty_param_def_id: LocalDefId, + ty_param_span: Span, assoc_name: Ident, span: Span, ) -> Result, ErrorGuaranteed> { @@ -836,7 +837,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))); traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_name) }, - AssocItemQSelf::TyParam(ty_param_def_id), + AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span), ty::AssocKind::Type, assoc_name, span, @@ -1080,6 +1081,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), ) => self.probe_single_ty_param_bound_for_assoc_ty( param_did.expect_local(), + qself.span, assoc_ident, span, )?, diff --git a/tests/ui/resolve/issue-55673.stderr b/tests/ui/resolve/issue-55673.stderr index ffc3252230a..4069b35a998 100644 --- a/tests/ui/resolve/issue-55673.stderr +++ b/tests/ui/resolve/issue-55673.stderr @@ -19,7 +19,7 @@ help: consider further restricting type parameter `T` | LL | T::Baa: std::fmt::Debug, T: Foo | ~~~~~~~~ -help: and also change the associated type name +help: ...and changing the associated type name | LL | T::Bar: std::fmt::Debug, | ~~~ diff --git a/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.eager.stderr b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.eager.stderr new file mode 100644 index 00000000000..8e6490c548d --- /dev/null +++ b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.eager.stderr @@ -0,0 +1,25 @@ +error[E0220]: associated type `Assoc` not found for `T` + --> $DIR/unresolved-assoc-ty-suggest-trait.rs:11:22 + | +LL | type AssocOf = T::Assoc; + | ^^^^^ there is an associated type `Assoc` in the trait `Trait` + | +help: consider fully qualifying the associated type + | +LL | type AssocOf = ::Assoc; + | + +++++++++ + +error[E0220]: associated type `Assok` not found for `T` + --> $DIR/unresolved-assoc-ty-suggest-trait.rs:15:22 + | +LL | type AssokOf = T::Assok; + | ^^^^^ there is a similarly named associated type `Assoc` in the trait `Trait` + | +help: consider fully qualifying and renaming the associated type + | +LL | type AssokOf = ::Assoc; + | + +++++++++ ~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr new file mode 100644 index 00000000000..051f181cb6f --- /dev/null +++ b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr @@ -0,0 +1,29 @@ +error[E0220]: associated type `Assoc` not found for `T` + --> $DIR/unresolved-assoc-ty-suggest-trait.rs:11:22 + | +LL | type AssocOf = T::Assoc; + | ^^^^^ there is an associated type `Assoc` in the trait `Trait` + | +help: consider restricting type parameter `T` + | +LL | type AssocOf = T::Assoc; + | +++++++ + +error[E0220]: associated type `Assok` not found for `T` + --> $DIR/unresolved-assoc-ty-suggest-trait.rs:15:22 + | +LL | type AssokOf = T::Assok; + | ^^^^^ there is a similarly named associated type `Assoc` in the trait `Trait` + | +help: consider restricting type parameter `T` + | +LL | type AssokOf = T::Assok; + | +++++++ +help: ...and changing the associated type name + | +LL | type AssokOf = T::Assoc; + | ~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.rs b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.rs new file mode 100644 index 00000000000..75e4eb496b4 --- /dev/null +++ b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.rs @@ -0,0 +1,20 @@ +// Ensure that we don't suggest *type alias bounds* for **eager** type aliases. +// issue: rust-lang/rust#125789 + +//@ revisions: eager lazy +#![cfg_attr(lazy, feature(lazy_type_alias), allow(incomplete_features))] + +// FIXME(fmease): Suggest a full trait ref (with placeholders) instead of just a trait name. + +trait Trait { type Assoc; } + +type AssocOf = T::Assoc; //~ ERROR associated type `Assoc` not found for `T` +//[eager]~^ HELP consider fully qualifying the associated type +//[lazy]~| HELP consider restricting type parameter `T` + +type AssokOf = T::Assok; //~ ERROR associated type `Assok` not found for `T` +//[eager]~^ HELP consider fully qualifying and renaming the associated type +//[lazy]~| HELP consider restricting type parameter `T` +//[lazy]~| HELP and changing the associated type name + +fn main() {} From 02a2f0272736c65b51996b0c6e7cbd991ac21d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 15 Jun 2024 11:08:12 +0200 Subject: [PATCH 05/21] Suggest full trait ref (with placeholders) on unresolved assoc tys --- compiler/rustc_hir_analysis/src/errors.rs | 9 ++++--- .../src/hir_ty_lowering/errors.rs | 25 +++++++++++-------- ...solved-assoc-ty-suggest-trait.eager.stderr | 17 ++++++++++--- ...esolved-assoc-ty-suggest-trait.lazy.stderr | 17 ++++++++++--- .../unresolved-assoc-ty-suggest-trait.rs | 12 ++++++--- 5 files changed, 57 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 90861ba1ff8..c364a561631 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -128,19 +128,20 @@ pub enum AssocItemNotFoundSugg<'a> { }, #[multipart_suggestion( hir_analysis_assoc_item_not_found_similar_in_other_trait_qpath_sugg, - style = "verbose", - applicability = "maybe-incorrect" + style = "verbose" )] SimilarInOtherTraitQPath { #[suggestion_part(code = "<")] lo: Span, - #[suggestion_part(code = " as {trait_}>")] + #[suggestion_part(code = " as {trait_ref}>")] mi: Span, #[suggestion_part(code = "{suggested_name}")] hi: Option, - trait_: &'a str, + trait_ref: String, suggested_name: Symbol, identically_named: bool, + #[applicability] + applicability: Applicability, }, #[suggestion( hir_analysis_assoc_item_not_found_other_sugg, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index fd2bbabe779..56f508a2d43 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -251,6 +251,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return self.dcx().emit_err(err); } + let trait_args = &ty::GenericArgs::identity_for_item(tcx, best_trait)[1..]; + let mut trait_ref = trait_name.clone(); + let applicability = if let [arg, args @ ..] = trait_args { + use std::fmt::Write; + write!(trait_ref, ""; + Applicability::HasPlaceholders + } else { + Applicability::MaybeIncorrect + }; + let identically_named = suggested_name == assoc_name.name; if let DefKind::TyAlias = tcx.def_kind(item_def_id) @@ -260,22 +272,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { lo: ty_param_span.shrink_to_lo(), mi: ty_param_span.shrink_to_hi(), hi: (!identically_named).then_some(assoc_name.span), - // FIXME(fmease): Use a full trait ref here (with placeholders). - trait_: &trait_name, + trait_ref, identically_named, suggested_name, + applicability, }); } else { let mut err = self.dcx().create_err(err); if suggest_constraining_type_param( - tcx, - generics, - &mut err, - &qself_str, - // FIXME(fmease): Use a full trait ref here (with placeholders). - &trait_name, - None, - None, + tcx, generics, &mut err, &qself_str, &trait_ref, None, None, ) && !identically_named { // We suggested constraining a type parameter, but the associated item on it diff --git a/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.eager.stderr b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.eager.stderr index 8e6490c548d..e891ff10fda 100644 --- a/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.eager.stderr +++ b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.eager.stderr @@ -1,5 +1,5 @@ error[E0220]: associated type `Assoc` not found for `T` - --> $DIR/unresolved-assoc-ty-suggest-trait.rs:11:22 + --> $DIR/unresolved-assoc-ty-suggest-trait.rs:9:22 | LL | type AssocOf = T::Assoc; | ^^^^^ there is an associated type `Assoc` in the trait `Trait` @@ -10,7 +10,7 @@ LL | type AssocOf = ::Assoc; | + +++++++++ error[E0220]: associated type `Assok` not found for `T` - --> $DIR/unresolved-assoc-ty-suggest-trait.rs:15:22 + --> $DIR/unresolved-assoc-ty-suggest-trait.rs:13:22 | LL | type AssokOf = T::Assok; | ^^^^^ there is a similarly named associated type `Assoc` in the trait `Trait` @@ -20,6 +20,17 @@ help: consider fully qualifying and renaming the associated type LL | type AssokOf = ::Assoc; | + +++++++++ ~~~~~ -error: aborting due to 2 previous errors +error[E0220]: associated type `Proj` not found for `T` + --> $DIR/unresolved-assoc-ty-suggest-trait.rs:22:21 + | +LL | type ProjOf = T::Proj; + | ^^^^ there is an associated type `Proj` in the trait `Parametrized` + | +help: consider fully qualifying the associated type + | +LL | type ProjOf = >::Proj; + | + ++++++++++++++++++++++++++++++++ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr index 051f181cb6f..96179a7b484 100644 --- a/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr +++ b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr @@ -1,5 +1,5 @@ error[E0220]: associated type `Assoc` not found for `T` - --> $DIR/unresolved-assoc-ty-suggest-trait.rs:11:22 + --> $DIR/unresolved-assoc-ty-suggest-trait.rs:9:22 | LL | type AssocOf = T::Assoc; | ^^^^^ there is an associated type `Assoc` in the trait `Trait` @@ -10,7 +10,7 @@ LL | type AssocOf = T::Assoc; | +++++++ error[E0220]: associated type `Assok` not found for `T` - --> $DIR/unresolved-assoc-ty-suggest-trait.rs:15:22 + --> $DIR/unresolved-assoc-ty-suggest-trait.rs:13:22 | LL | type AssokOf = T::Assok; | ^^^^^ there is a similarly named associated type `Assoc` in the trait `Trait` @@ -24,6 +24,17 @@ help: ...and changing the associated type name LL | type AssokOf = T::Assoc; | ~~~~~ -error: aborting due to 2 previous errors +error[E0220]: associated type `Proj` not found for `T` + --> $DIR/unresolved-assoc-ty-suggest-trait.rs:22:21 + | +LL | type ProjOf = T::Proj; + | ^^^^ there is an associated type `Proj` in the trait `Parametrized` + | +help: consider restricting type parameter `T` + | +LL | type ProjOf> = T::Proj; + | ++++++++++++++++++++++++++++++ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.rs b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.rs index 75e4eb496b4..2c8d448f308 100644 --- a/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.rs +++ b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.rs @@ -4,9 +4,7 @@ //@ revisions: eager lazy #![cfg_attr(lazy, feature(lazy_type_alias), allow(incomplete_features))] -// FIXME(fmease): Suggest a full trait ref (with placeholders) instead of just a trait name. - -trait Trait { type Assoc; } +trait Trait { type Assoc; } type AssocOf = T::Assoc; //~ ERROR associated type `Assoc` not found for `T` //[eager]~^ HELP consider fully qualifying the associated type @@ -17,4 +15,12 @@ type AssokOf = T::Assok; //~ ERROR associated type `Assok` not found for `T` //[lazy]~| HELP consider restricting type parameter `T` //[lazy]~| HELP and changing the associated type name +trait Parametrized<'a, T, const N: usize> { + type Proj; +} + +type ProjOf = T::Proj; //~ ERROR associated type `Proj` not found for `T` +//[eager]~^ HELP consider fully qualifying the associated type +//[lazy]~| HELP consider restricting type parameter `T` + fn main() {} From 63a54d93be33bb1c0357c48532df778f6f2a416b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 14 Jun 2024 15:30:11 +0200 Subject: [PATCH 06/21] Don't suppress lint type_alias_bounds for ty aliases containing inherent assoc tys --- compiler/rustc_lint/src/builtin.rs | 30 ++++++++----------- compiler/rustc_type_ir/src/visit.rs | 4 --- .../type-alias-bounds-are-enforced.rs | 20 ------------- .../type-alias-bounds.rs | 29 ++++++++++++++++++ .../type-alias-bounds.stderr | 15 ++++++++++ 5 files changed, 56 insertions(+), 42 deletions(-) delete mode 100644 tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs create mode 100644 tests/ui/associated-inherent-types/type-alias-bounds.rs create mode 100644 tests/ui/associated-inherent-types/type-alias-bounds.stderr diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 9ebada0fff3..40b336cd5ea 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1425,30 +1425,27 @@ impl TypeAliasBounds { impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - let hir::ItemKind::TyAlias(hir_ty, type_alias_generics) = &item.kind else { return }; + let hir::ItemKind::TyAlias(hir_ty, generics) = &item.kind else { return }; + + // There must not be a where clause. + if generics.predicates.is_empty() { + return; + } // Bounds of lazy type aliases and TAITs are respected. if cx.tcx.type_alias_is_lazy(item.owner_id) { return; } - let ty = cx.tcx.type_of(item.owner_id).skip_binder(); - if ty.has_inherent_projections() { - // Bounds of type aliases that contain opaque types or inherent projections are - // respected. E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`, `type X = - // Type::Inherent;`. - return; - } - - // There must not be a where clause - if type_alias_generics.predicates.is_empty() { - return; - } + // NOTE(inherent_associated_types): While we currently do take some bounds in type + // aliases into consideration during IAT *selection*, we don't perform full use+def + // site wfchecking for such type aliases. Therefore TAB should still trigger. + // See also `tests/ui/associated-inherent-types/type-alias-bounds.rs`. let mut where_spans = Vec::new(); let mut inline_spans = Vec::new(); let mut inline_sugg = Vec::new(); - for p in type_alias_generics.predicates { + for p in generics.predicates { let span = p.span(); if p.in_where_clause() { where_spans.push(span); @@ -1469,10 +1466,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { cx.emit_span_lint( TYPE_ALIAS_BOUNDS, where_spans, - BuiltinTypeAliasWhereClause { - suggestion: type_alias_generics.where_clause_span, - sub, - }, + BuiltinTypeAliasWhereClause { suggestion: generics.where_clause_span, sub }, ); } diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 6ec38b78fc2..d5e114b2175 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -241,10 +241,6 @@ pub trait TypeVisitableExt: TypeVisitable { self.has_type_flags(TypeFlags::HAS_ALIAS) } - fn has_inherent_projections(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INHERENT) - } - fn has_opaque_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) } diff --git a/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs deleted file mode 100644 index 5ac7e1e58b8..00000000000 --- a/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ compile-flags: --crate-type=lib -//@ check-pass - -#![feature(inherent_associated_types)] -#![allow(incomplete_features)] - -// Bounds on the self type play a major role in the resolution of inherent associated types (*). -// As a result of that, if a type alias contains any then its bounds have to be respected and the -// lint `type_alias_bounds` should not fire. - -#![deny(type_alias_bounds)] - -pub type Alias = (Source::Assoc,); - -pub struct Source(T); -pub trait Bound {} - -impl Source { - pub type Assoc = (); -} diff --git a/tests/ui/associated-inherent-types/type-alias-bounds.rs b/tests/ui/associated-inherent-types/type-alias-bounds.rs new file mode 100644 index 00000000000..c27bcbed43a --- /dev/null +++ b/tests/ui/associated-inherent-types/type-alias-bounds.rs @@ -0,0 +1,29 @@ +//@ compile-flags: --crate-type=lib +//@ check-pass + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +// FIXME(inherent_associated_types): +// While we currently do take some clauses of the ParamEnv into consideration +// when performing IAT selection, we do not perform full well-formedness checking +// for (eager) type alias definition and usage sites. +// +// Therefore it's *correct* for lint `type_alias_bounds` to fire here despite the +// fact that removing `Bound` from `T` in `Alias` would lead to an error! +// +// Obviously, the present situation isn't ideal and we should fix it in one way +// or another. Either we somehow delay IAT selection until after HIR ty lowering +// to avoid the need to specify any bounds inside (eager) type aliases or we +// force the overarching type alias to be *lazy* (similar to TAITs) which would +// automatically lead to full wfchecking and lint TAB getting suppressed. + +pub type Alias = (Source::Assoc,); +//~^ WARN bounds on generic parameters are not enforced in type aliases + +pub struct Source(T); +pub trait Bound {} + +impl Source { + pub type Assoc = (); +} diff --git a/tests/ui/associated-inherent-types/type-alias-bounds.stderr b/tests/ui/associated-inherent-types/type-alias-bounds.stderr new file mode 100644 index 00000000000..c5d0e9e5041 --- /dev/null +++ b/tests/ui/associated-inherent-types/type-alias-bounds.stderr @@ -0,0 +1,15 @@ +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias-bounds.rs:21:19 + | +LL | pub type Alias = (Source::Assoc,); + | ^^^^^ + | + = note: `#[warn(type_alias_bounds)]` on by default +help: the bound will not be checked when the type alias is used, and should be removed + | +LL - pub type Alias = (Source::Assoc,); +LL + pub type Alias = (Source::Assoc,); + | + +warning: 1 warning emitted + From a8b3dfd25336dc12f17da23a0ed7004a4ebee234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 14 Jun 2024 16:18:32 +0200 Subject: [PATCH 07/21] Suppress lint type_alias_bounds for ty aliases containing const projections under GCE --- compiler/rustc_lint/src/builtin.rs | 10 +++ .../type-alias-bounds.neg.stderr | 63 ++++++++++++++++ .../generic_const_exprs/type-alias-bounds.rs | 71 +++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 tests/ui/const-generics/generic_const_exprs/type-alias-bounds.neg.stderr create mode 100644 tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 40b336cd5ea..90555007607 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1437,6 +1437,16 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { return; } + + // FIXME(generic_const_exprs): Revisit this before stabilization. + // See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`. + let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); + if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) + && cx.tcx.features().generic_const_exprs + { + return; + } + // NOTE(inherent_associated_types): While we currently do take some bounds in type // aliases into consideration during IAT *selection*, we don't perform full use+def // site wfchecking for such type aliases. Therefore TAB should still trigger. diff --git a/tests/ui/const-generics/generic_const_exprs/type-alias-bounds.neg.stderr b/tests/ui/const-generics/generic_const_exprs/type-alias-bounds.neg.stderr new file mode 100644 index 00000000000..fa12dd14753 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/type-alias-bounds.neg.stderr @@ -0,0 +1,63 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/type-alias-bounds.rs:23:12 + | +LL | let _: AliasConstUnused; + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `ct_unused_0::AliasConstUnused` + --> $DIR/type-alias-bounds.rs:20:30 + | +LL | type AliasConstUnused = (T, I32<{ DATA }>); + | ^^^^ required by this bound in `AliasConstUnused` + +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/type-alias-bounds.rs:31:12 + | +LL | let _: AliasConstUnused; + | ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `ct_unused_1::AliasConstUnused` + --> $DIR/type-alias-bounds.rs:29:41 + | +LL | type AliasConstUnused where String: Copy = I32<{ 0; 0 }>; + | ^^^^ required by this bound in `AliasConstUnused` + +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/type-alias-bounds.rs:39:12 + | +LL | let _: AliasFnUnused; + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `AliasFnUnused` + --> $DIR/type-alias-bounds.rs:36:27 + | +LL | type AliasFnUnused = (T, I32<{ code() }>); + | ^^^^ required by this bound in `AliasFnUnused` + +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/type-alias-bounds.rs:57:12 + | +LL | let _: AliasAssocConstUsed; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `AliasAssocConstUsed` + --> $DIR/type-alias-bounds.rs:55:41 + | +LL | type AliasAssocConstUsed = I32<{ T::DATA }>; + | ^^^^ required by this bound in `AliasAssocConstUsed` + +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/type-alias-bounds.rs:65:12 + | +LL | let _: AliasFnUsed; + | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `AliasFnUsed` + --> $DIR/type-alias-bounds.rs:62:33 + | +LL | type AliasFnUsed = I32<{ code::() }>; + | ^^^^ required by this bound in `AliasFnUsed` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs b/tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs new file mode 100644 index 00000000000..f16e646129c --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs @@ -0,0 +1,71 @@ +//@ revisions: pos neg +//@[pos] check-pass + +#![feature(generic_const_exprs)] +#![feature(trivial_bounds)] // only used in test case `ct_unused_1` +#![allow(incomplete_features)] + +// FIXME(generic_const_exprs): Revisit this before stabilization. +// Check that we don't emit the lint `type_alias_bounds` for (eager) type aliases +// whose RHS contains a const projection (aka uneval'ed const). +// Since anon consts inherit the parent generics and predicates and we effectively +// check them before and after instantiaton for well-formedness, the type alias +// bounds are in every sense "enforced". +// Note that the test cases whose name ends in "unused" just demonstrate that this +// holds even if the const projections don't "visibly" capture any generics and/or +// predicates. +#![deny(type_alias_bounds)] + +fn ct_unused_0() { + type AliasConstUnused = (T, I32<{ DATA }>); + const DATA: i32 = 0; + #[cfg(neg)] + let _: AliasConstUnused; + //[neg]~^ ERROR the trait bound `String: Copy` is not satisfied +} + +fn ct_unused_1() { + #[allow(trivial_bounds)] + type AliasConstUnused where String: Copy = I32<{ 0; 0 }>; + #[cfg(neg)] + let _: AliasConstUnused; + //[neg]~^ ERROR the trait bound `String: Copy` is not satisfied +} + +fn fn_unused() { + type AliasFnUnused = (T, I32<{ code() }>); + const fn code() -> i32 { 0 } + #[cfg(neg)] + let _: AliasFnUnused; + //[neg]~^ ERROR the trait bound `String: Copy` is not satisfied +} + +trait Trait { + type Proj; + const DATA: i32; +} + +impl Trait for String { + type Proj = i32; + const DATA: i32 = 0; +} + +// Regression test for issue #94398. +fn assoc_ct_used() { + type AliasAssocConstUsed = I32<{ T::DATA }>; + #[cfg(neg)] + let _: AliasAssocConstUsed; + //[neg]~^ ERROR the trait bound `String: Copy` is not satisfied +} + +fn fn_used() { + type AliasFnUsed = I32<{ code::() }>; + const fn code() -> i32 { T::DATA } + #[cfg(neg)] + let _: AliasFnUsed; + //[neg]~^ ERROR the trait bound `String: Copy` is not satisfied +} + +struct I32; + +fn main() {} From fdf8f024ad71c6e9c46867fb31b74df0fcaaf3f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 15 Jun 2024 21:34:44 +0200 Subject: [PATCH 08/21] Improve the impl and diag output of lint type_alias_bounds --- compiler/rustc_lint/messages.ftl | 19 +- compiler/rustc_lint/src/builtin.rs | 92 +++++---- compiler/rustc_lint/src/lints.rs | 154 ++++++++------- .../type-alias-bounds.rs | 2 +- .../type-alias-bounds.stderr | 15 +- .../associated-type-bounds/type-alias.stderr | 180 ++++++++++-------- tests/ui/privacy/private-in-public-warn.rs | 4 +- .../ui/privacy/private-in-public-warn.stderr | 30 +-- .../trivial-bounds-inconsistent.stderr | 15 +- ...67690-type-alias-bound-diagnostic-crash.rs | 2 +- ...0-type-alias-bound-diagnostic-crash.stderr | 15 +- tests/ui/type/type-alias-bounds.rs | 21 +- tests/ui/type/type-alias-bounds.stderr | 155 ++++++++------- 13 files changed, 385 insertions(+), 319 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7d7b97e2eb1..ce99c8686ba 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -139,13 +139,18 @@ lint_builtin_special_module_name_used_main = found module declaration for main.r lint_builtin_trivial_bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters -lint_builtin_type_alias_bounds_help = use fully disambiguated paths (i.e., `::Assoc`) to refer to associated types in type aliases - -lint_builtin_type_alias_generic_bounds = bounds on generic parameters are not enforced in type aliases - .suggestion = the bound will not be checked when the type alias is used, and should be removed - -lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases - .suggestion = the clause will not be checked when the type alias is used, and should be removed +lint_builtin_type_alias_bounds_enable_feat_help = add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics +lint_builtin_type_alias_bounds_label = will not be checked at usage sites of the type alias +lint_builtin_type_alias_bounds_limitation_note = this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information +lint_builtin_type_alias_bounds_param_bounds = bounds on generic parameters in type aliases are not enforced + .suggestion = remove {$count -> + [one] this bound + *[other] these bounds + } +lint_builtin_type_alias_bounds_qualify_assoc_tys_sugg = fully qualify this associated type +lint_builtin_type_alias_bounds_where_clause = where clauses on type aliases are not enforced + .suggestion = remove this where clause lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 90555007607..a8c8c71927a 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -31,12 +31,12 @@ use crate::{ BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, - BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds, - BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause, - BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, - BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, - BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, - BuiltinWhileTrue, InvalidAsmLabel, SuggestChangingAssocTypes, + BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasBounds, + BuiltinTypeAliasParamBoundsSuggestion, BuiltinUngatedAsyncFnTrackCaller, + BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, + BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, + BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel, + TypeAliasBoundsQualifyAssocTysSugg, }, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, }; @@ -1406,23 +1406,6 @@ declare_lint_pass!( TypeAliasBounds => [TYPE_ALIAS_BOUNDS] ); -impl TypeAliasBounds { - pub(crate) fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool { - match *qpath { - hir::QPath::TypeRelative(ty, _) => { - // If this is a type variable, we found a `T::Assoc`. - match ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(None, path)) => { - matches!(path.res, Res::Def(DefKind::TyParam, _)) - } - _ => false, - } - } - hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false, - } - } -} - impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { let hir::ItemKind::TyAlias(hir_ty, generics) = &item.kind else { return }; @@ -1437,7 +1420,6 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { return; } - // FIXME(generic_const_exprs): Revisit this before stabilization. // See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`. let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); @@ -1455,6 +1437,8 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { let mut where_spans = Vec::new(); let mut inline_spans = Vec::new(); let mut inline_sugg = Vec::new(); + let mut affects_object_lifetime_defaults = false; + for p in generics.predicates { let span = p.span(); if p.in_where_clause() { @@ -1465,31 +1449,61 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { } inline_sugg.push((span, String::new())); } + + // FIXME(fmease): Move this into a "diagnostic decorator" for increased laziness + // Bounds of the form `T: 'a` where `T` is a type param of + // the type alias affect object lifetime defaults. + if !affects_object_lifetime_defaults + && let hir::WherePredicate::BoundPredicate(pred) = p + && pred.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Outlives(_))) + && pred.bound_generic_params.is_empty() + && let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = pred.bounded_ty.kind + && let Res::Def(DefKind::TyParam, _) = path.res + { + affects_object_lifetime_defaults = true; + } } - let mut suggested_changing_assoc_types = false; - if !where_spans.is_empty() { - let sub = (!suggested_changing_assoc_types).then(|| { - suggested_changing_assoc_types = true; - SuggestChangingAssocTypes { ty: hir_ty } - }); + // FIXME(fmease): Add a disclaimer (in the form of a multi-span note) that the removal of + // type-param-outlives-bounds affects OLDs and explicit object lifetime + // bounds might be required [...]. + // FIXME(fmease): The applicability should also depend on the outcome of the HIR walker + // inside of `TypeAliasBoundsQualifyAssocTysSugg`: Whether it found a + // shorthand projection or not. + let applicability = if affects_object_lifetime_defaults { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; + + let mut qualify_assoc_tys_sugg = Some(TypeAliasBoundsQualifyAssocTysSugg { ty: hir_ty }); + let enable_feat_help = cx.tcx.sess.is_nightly_build().then_some(()); + + if let [.., label_sp] = *where_spans { cx.emit_span_lint( TYPE_ALIAS_BOUNDS, where_spans, - BuiltinTypeAliasWhereClause { suggestion: generics.where_clause_span, sub }, + BuiltinTypeAliasBounds::WhereClause { + label: label_sp, + enable_feat_help, + suggestion: (generics.where_clause_span, applicability), + qualify_assoc_tys_sugg: qualify_assoc_tys_sugg.take(), + }, ); } - - if !inline_spans.is_empty() { - let suggestion = BuiltinTypeAliasGenericBoundsSuggestion { suggestions: inline_sugg }; - let sub = (!suggested_changing_assoc_types).then(|| { - suggested_changing_assoc_types = true; - SuggestChangingAssocTypes { ty: hir_ty } - }); + if let [.., label_sp] = *inline_spans { cx.emit_span_lint( TYPE_ALIAS_BOUNDS, inline_spans, - BuiltinTypeAliasGenericBounds { suggestion, sub }, + BuiltinTypeAliasBounds::ParamBounds { + label: label_sp, + enable_feat_help, + suggestion: BuiltinTypeAliasParamBoundsSuggestion { + suggestions: inline_sugg, + applicability, + }, + qualify_assoc_tys_sugg, + }, ); } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 6c5f366727f..6cf8b9330fc 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -9,7 +9,7 @@ use rustc_errors::{ ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, }; -use rustc_hir::{def::Namespace, def_id::DefId}; +use rustc_hir::{self as hir, def::Namespace, def_id::DefId}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{ inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt, @@ -22,9 +22,7 @@ use rustc_span::{ Span, Symbol, }; -use crate::{ - builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext, -}; +use crate::{builtin::InitError, errors::OverruledAttributeSub, LateContext}; // array_into_iter.rs #[derive(LintDiagnostic)] @@ -263,62 +261,6 @@ pub struct BuiltinUnreachablePub<'a> { pub help: Option<()>, } -pub struct SuggestChangingAssocTypes<'a, 'b> { - pub ty: &'a rustc_hir::Ty<'b>, -} - -impl<'a, 'b> Subdiagnostic for SuggestChangingAssocTypes<'a, 'b> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - // Access to associates types should use `::Assoc`, which does not need a - // bound. Let's see if this type does that. - - // We use a HIR visitor to walk the type. - use rustc_hir::intravisit::{self, Visitor}; - struct WalkAssocTypes<'a, 'b, G: EmissionGuarantee> { - err: &'a mut Diag<'b, G>, - } - impl<'a, 'b, G: EmissionGuarantee> Visitor<'_> for WalkAssocTypes<'a, 'b, G> { - fn visit_qpath( - &mut self, - qpath: &rustc_hir::QPath<'_>, - id: rustc_hir::HirId, - span: Span, - ) { - if TypeAliasBounds::is_type_variable_assoc(qpath) { - self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help); - } - intravisit::walk_qpath(self, qpath, id) - } - } - - // Let's go for a walk! - let mut visitor = WalkAssocTypes { err: diag }; - visitor.visit_ty(self.ty); - } -} - -#[derive(LintDiagnostic)] -#[diag(lint_builtin_type_alias_where_clause)] -pub struct BuiltinTypeAliasWhereClause<'a, 'b> { - #[suggestion(code = "", applicability = "machine-applicable")] - pub suggestion: Span, - #[subdiagnostic] - pub sub: Option>, -} - -#[derive(LintDiagnostic)] -#[diag(lint_builtin_type_alias_generic_bounds)] -pub struct BuiltinTypeAliasGenericBounds<'a, 'b> { - #[subdiagnostic] - pub suggestion: BuiltinTypeAliasGenericBoundsSuggestion, - #[subdiagnostic] - pub sub: Option>, -} - #[derive(LintDiagnostic)] #[diag(lint_macro_expr_fragment_specifier_2024_migration)] pub struct MacroExprFragment2024 { @@ -326,21 +268,97 @@ pub struct MacroExprFragment2024 { pub suggestion: Span, } -pub struct BuiltinTypeAliasGenericBoundsSuggestion { - pub suggestions: Vec<(Span, String)>, +#[derive(LintDiagnostic)] +pub enum BuiltinTypeAliasBounds<'a, 'hir> { + #[diag(lint_builtin_type_alias_bounds_where_clause)] + #[note(lint_builtin_type_alias_bounds_limitation_note)] + WhereClause { + #[label(lint_builtin_type_alias_bounds_label)] + label: Span, + #[help(lint_builtin_type_alias_bounds_enable_feat_help)] + enable_feat_help: Option<()>, + #[suggestion(code = "")] + suggestion: (Span, Applicability), + #[subdiagnostic] + qualify_assoc_tys_sugg: Option>, + }, + #[diag(lint_builtin_type_alias_bounds_param_bounds)] + #[note(lint_builtin_type_alias_bounds_limitation_note)] + ParamBounds { + #[label(lint_builtin_type_alias_bounds_label)] + label: Span, + #[help(lint_builtin_type_alias_bounds_enable_feat_help)] + enable_feat_help: Option<()>, + #[subdiagnostic] + suggestion: BuiltinTypeAliasParamBoundsSuggestion, + #[subdiagnostic] + qualify_assoc_tys_sugg: Option>, + }, } -impl Subdiagnostic for BuiltinTypeAliasGenericBoundsSuggestion { +pub struct BuiltinTypeAliasParamBoundsSuggestion { + pub suggestions: Vec<(Span, String)>, + pub applicability: Applicability, +} + +impl Subdiagnostic for BuiltinTypeAliasParamBoundsSuggestion { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, _f: &F, ) { - diag.multipart_suggestion( - fluent::lint_suggestion, - self.suggestions, - Applicability::MachineApplicable, - ); + diag.arg("count", self.suggestions.len()); + diag.multipart_suggestion(fluent::lint_suggestion, self.suggestions, self.applicability); + } +} + +pub struct TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir> { + pub ty: &'a hir::Ty<'hir>, +} + +impl<'a, 'hir> Subdiagnostic for TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir> { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + // We perform the walk in here instead of in `` to + // avoid doing throwaway work in case the lint ends up getting suppressed. + + use hir::intravisit::Visitor; + struct ProbeShorthandAssocTys<'a, 'b, G: EmissionGuarantee> { + diag: &'a mut Diag<'b, G>, + } + impl<'a, 'b, G: EmissionGuarantee> Visitor<'_> for ProbeShorthandAssocTys<'a, 'b, G> { + fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, _: Span) { + // Look for "type-parameter shorthand-associated-types". I.e., paths of the + // form `T::Assoc` with `T` type param. These are reliant on trait bounds. + // Suggest fully qualifying them via `::Assoc`. + // + // Instead of attempting to figure out the necessary trait ref, just use a + // placeholder. Since we don't record type-dependent resolutions for non-body + // items like type aliases, we can't simply deduce the corresp. trait from + // the HIR path alone without rerunning parts of HIR ty lowering here + // (namely `probe_single_ty_param_bound_for_assoc_ty`) which is infeasible. + // + // (We could employ some simple heuristics but that's likely not worth it). + if let hir::QPath::TypeRelative(qself, _) = qpath + && let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind + && let hir::def::Res::Def(hir::def::DefKind::TyParam, _) = path.res + { + self.diag.multipart_suggestion( + fluent::lint_builtin_type_alias_bounds_qualify_assoc_tys_sugg, + vec![ + (qself.span.shrink_to_lo(), "<".into()), + (qself.span.shrink_to_hi(), " as /* Trait */>".into()), + ], + Applicability::HasPlaceholders, + ); + } + hir::intravisit::walk_qpath(self, qpath, id) + } + } + ProbeShorthandAssocTys { diag }.visit_ty(self.ty); } } diff --git a/tests/ui/associated-inherent-types/type-alias-bounds.rs b/tests/ui/associated-inherent-types/type-alias-bounds.rs index c27bcbed43a..61641a83994 100644 --- a/tests/ui/associated-inherent-types/type-alias-bounds.rs +++ b/tests/ui/associated-inherent-types/type-alias-bounds.rs @@ -19,7 +19,7 @@ // automatically lead to full wfchecking and lint TAB getting suppressed. pub type Alias = (Source::Assoc,); -//~^ WARN bounds on generic parameters are not enforced in type aliases +//~^ WARN bounds on generic parameters in type aliases are not enforced pub struct Source(T); pub trait Bound {} diff --git a/tests/ui/associated-inherent-types/type-alias-bounds.stderr b/tests/ui/associated-inherent-types/type-alias-bounds.stderr index c5d0e9e5041..c56dd498f77 100644 --- a/tests/ui/associated-inherent-types/type-alias-bounds.stderr +++ b/tests/ui/associated-inherent-types/type-alias-bounds.stderr @@ -1,15 +1,16 @@ -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/type-alias-bounds.rs:21:19 | LL | pub type Alias = (Source::Assoc,); - | ^^^^^ + | --^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics = note: `#[warn(type_alias_bounds)]` on by default -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - pub type Alias = (Source::Assoc,); -LL + pub type Alias = (Source::Assoc,); - | warning: 1 warning emitted diff --git a/tests/ui/associated-type-bounds/type-alias.stderr b/tests/ui/associated-type-bounds/type-alias.stderr index 072c471467c..d59952b4a14 100644 --- a/tests/ui/associated-type-bounds/type-alias.stderr +++ b/tests/ui/associated-type-bounds/type-alias.stderr @@ -1,147 +1,159 @@ -warning: where clauses are not enforced in type aliases +warning: where clauses on type aliases are not enforced --> $DIR/type-alias.rs:3:25 | LL | type _TaWhere1 where T: Iterator = T; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ------^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this where clause | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics = note: `#[warn(type_alias_bounds)]` on by default -help: the clause will not be checked when the type alias is used, and should be removed - | -LL - type _TaWhere1 where T: Iterator = T; -LL + type _TaWhere1 = T; - | -warning: where clauses are not enforced in type aliases +warning: where clauses on type aliases are not enforced --> $DIR/type-alias.rs:4:25 | LL | type _TaWhere2 where T: Iterator = T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the clause will not be checked when the type alias is used, and should be removed - | -LL - type _TaWhere2 where T: Iterator = T; -LL + type _TaWhere2 = T; + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this where clause | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: where clauses are not enforced in type aliases +warning: where clauses on type aliases are not enforced --> $DIR/type-alias.rs:5:25 | LL | type _TaWhere3 where T: Iterator = T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the clause will not be checked when the type alias is used, and should be removed - | -LL - type _TaWhere3 where T: Iterator = T; -LL + type _TaWhere3 = T; + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this where clause | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: where clauses are not enforced in type aliases +warning: where clauses on type aliases are not enforced --> $DIR/type-alias.rs:6:25 | LL | type _TaWhere4 where T: Iterator = T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the clause will not be checked when the type alias is used, and should be removed - | -LL - type _TaWhere4 where T: Iterator = T; -LL + type _TaWhere4 = T; + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this where clause | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: where clauses are not enforced in type aliases +warning: where clauses on type aliases are not enforced --> $DIR/type-alias.rs:7:25 | LL | type _TaWhere5 where T: Iterator Into<&'a u8>> = T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the clause will not be checked when the type alias is used, and should be removed - | -LL - type _TaWhere5 where T: Iterator Into<&'a u8>> = T; -LL + type _TaWhere5 = T; + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this where clause | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: where clauses are not enforced in type aliases +warning: where clauses on type aliases are not enforced --> $DIR/type-alias.rs:8:25 | LL | type _TaWhere6 where T: Iterator> = T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the clause will not be checked when the type alias is used, and should be removed - | -LL - type _TaWhere6 where T: Iterator> = T; -LL + type _TaWhere6 = T; + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this where clause | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/type-alias.rs:10:20 | LL | type _TaInline1> = T; - | ^^^^^^^^^^^^^^^^^^^^ - | -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - type _TaInline1> = T; -LL + type _TaInline1 = T; + | --^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/type-alias.rs:11:20 | LL | type _TaInline2> = T; - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - type _TaInline2> = T; -LL + type _TaInline2 = T; + | --^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/type-alias.rs:12:20 | LL | type _TaInline3> = T; - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - type _TaInline3> = T; -LL + type _TaInline3 = T; + | --^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/type-alias.rs:13:20 | LL | type _TaInline4> = T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - type _TaInline4> = T; -LL + type _TaInline4 = T; + | --^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/type-alias.rs:14:20 | LL | type _TaInline5 Into<&'a u8>>> = T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - type _TaInline5 Into<&'a u8>>> = T; -LL + type _TaInline5 = T; + | --^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/type-alias.rs:15:20 | LL | type _TaInline6>> = T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - type _TaInline6>> = T; -LL + type _TaInline6 = T; + | --^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics warning: 12 warnings emitted diff --git a/tests/ui/privacy/private-in-public-warn.rs b/tests/ui/privacy/private-in-public-warn.rs index 99d318e36be..746b98fbd07 100644 --- a/tests/ui/privacy/private-in-public-warn.rs +++ b/tests/ui/privacy/private-in-public-warn.rs @@ -39,7 +39,7 @@ mod traits { pub trait PubTr {} pub type Alias = T; //~ ERROR trait `traits::PrivTr` is more private than the item `traits::Alias` - //~^ WARNING bounds on generic parameters are not enforced in type aliases + //~^ WARNING bounds on generic parameters in type aliases are not enforced pub trait Tr1: PrivTr {} //~ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr1` pub trait Tr2 {} //~ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr2` pub trait Tr3 { @@ -58,7 +58,7 @@ mod traits_where { pub type Alias where T: PrivTr = T; //~^ ERROR trait `traits_where::PrivTr` is more private than the item `traits_where::Alias` - //~| WARNING where clauses are not enforced in type aliases + //~| WARNING where clauses on type aliases are not enforced pub trait Tr2 where T: PrivTr {} //~^ ERROR trait `traits_where::PrivTr` is more private than the item `traits_where::Tr2` pub trait Tr3 { diff --git a/tests/ui/privacy/private-in-public-warn.stderr b/tests/ui/privacy/private-in-public-warn.stderr index ac7e5547de9..3f7b8c281e7 100644 --- a/tests/ui/privacy/private-in-public-warn.stderr +++ b/tests/ui/privacy/private-in-public-warn.stderr @@ -395,30 +395,32 @@ note: but type `Priv2` is only usable at visibility `pub(self)` LL | struct Priv2; | ^^^^^^^^^^^^ -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/private-in-public-warn.rs:41:23 | LL | pub type Alias = T; - | ^^^^^^ + | --^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics = note: `#[warn(type_alias_bounds)]` on by default -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - pub type Alias = T; -LL + pub type Alias = T; - | -warning: where clauses are not enforced in type aliases +warning: where clauses on type aliases are not enforced --> $DIR/private-in-public-warn.rs:59:29 | LL | pub type Alias where T: PrivTr = T; - | ^^^^^^^^^ - | -help: the clause will not be checked when the type alias is used, and should be removed - | -LL - pub type Alias where T: PrivTr = T; -LL + pub type Alias = T; + | ------^^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this where clause | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics error: aborting due to 34 previous errors; 2 warnings emitted diff --git a/tests/ui/trivial-bounds/trivial-bounds-inconsistent.stderr b/tests/ui/trivial-bounds/trivial-bounds-inconsistent.stderr index d66e468873b..0eae68bfcf0 100644 --- a/tests/ui/trivial-bounds/trivial-bounds-inconsistent.stderr +++ b/tests/ui/trivial-bounds/trivial-bounds-inconsistent.stderr @@ -24,18 +24,19 @@ warning: trait bound i32: Foo does not depend on any type or lifetime parameters LL | union U where i32: Foo { f: i32 } | ^^^ -warning: where clauses are not enforced in type aliases +warning: where clauses on type aliases are not enforced --> $DIR/trivial-bounds-inconsistent.rs:22:14 | LL | type Y where i32: Foo = (); - | ^^^^^^^^ + | ------^^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this where clause | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics = note: `#[warn(type_alias_bounds)]` on by default -help: the clause will not be checked when the type alias is used, and should be removed - | -LL - type Y where i32: Foo = (); -LL + type Y = (); - | warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:22:19 diff --git a/tests/ui/type/issue-67690-type-alias-bound-diagnostic-crash.rs b/tests/ui/type/issue-67690-type-alias-bound-diagnostic-crash.rs index 5ee3c027f40..52e0887175d 100644 --- a/tests/ui/type/issue-67690-type-alias-bound-diagnostic-crash.rs +++ b/tests/ui/type/issue-67690-type-alias-bound-diagnostic-crash.rs @@ -3,6 +3,6 @@ //@ check-pass pub type T = P; -//~^ WARN bounds on generic parameters are not enforced in type aliases +//~^ WARN bounds on generic parameters in type aliases are not enforced fn main() {} diff --git a/tests/ui/type/issue-67690-type-alias-bound-diagnostic-crash.stderr b/tests/ui/type/issue-67690-type-alias-bound-diagnostic-crash.stderr index 125ffbbb417..9fd0fe4913b 100644 --- a/tests/ui/type/issue-67690-type-alias-bound-diagnostic-crash.stderr +++ b/tests/ui/type/issue-67690-type-alias-bound-diagnostic-crash.stderr @@ -1,15 +1,16 @@ -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/issue-67690-type-alias-bound-diagnostic-crash.rs:5:15 | LL | pub type T = P; - | ^^^^ ^^^^ ^^^^ + | --^^^^---^^^^---^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics = note: `#[warn(type_alias_bounds)]` on by default -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - pub type T = P; -LL + pub type T

= P; - | warning: 1 warning emitted diff --git a/tests/ui/type/type-alias-bounds.rs b/tests/ui/type/type-alias-bounds.rs index 6d63c0c7e1b..37c073fe1f9 100644 --- a/tests/ui/type/type-alias-bounds.rs +++ b/tests/ui/type/type-alias-bounds.rs @@ -6,15 +6,15 @@ use std::rc::Rc; type SVec = Vec; -//~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds] +//~^ WARN bounds on generic parameters in type aliases are not enforced [type_alias_bounds] type S2Vec where T: Send = Vec; -//~^ WARN where clauses are not enforced in type aliases [type_alias_bounds] +//~^ WARN where clauses on type aliases are not enforced [type_alias_bounds] type VVec<'b, 'a: 'b + 'b> = (&'b u32, Vec<&'a i32>); -//~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds] +//~^ WARN bounds on generic parameters in type aliases are not enforced [type_alias_bounds] type WVec<'b, T: 'b + 'b> = (&'b u32, Vec); -//~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds] +//~^ WARN bounds on generic parameters in type aliases are not enforced [type_alias_bounds] type W2Vec<'b, T> where T: 'b, T: 'b = (&'b u32, Vec); -//~^ WARN where clauses are not enforced in type aliases [type_alias_bounds] +//~^ WARN where clauses on type aliases are not enforced [type_alias_bounds] static STATIC: u32 = 0; @@ -42,10 +42,11 @@ fn foo<'a>(y: &'a i32) { struct Sendable(T); type MySendable = Sendable; // no error here! -// However, bounds *are* taken into account when accessing associated types +// Bounds on type params do enable shorthand type alias paths. +// However, that doesn't actually mean that they are properly enforced. trait Bound { type Assoc; } -type T1 = U::Assoc; //~ WARN not enforced in type aliases -type T2 where U: Bound = U::Assoc; //~ WARN not enforced in type aliases +type T1 = U::Assoc; //~ WARN are not enforced +type T2 where U: Bound = U::Assoc; //~ WARN are not enforced // This errors: // `type T3 = U::Assoc;` @@ -53,7 +54,7 @@ type T2 where U: Bound = U::Assoc; //~ WARN not enforced in type aliases type T4 = ::Assoc; // Make sure the help about associated types is not shown incorrectly -type T5 = ::Assoc; //~ WARN not enforced in type aliases -type T6 = ::std::vec::Vec; //~ WARN not enforced in type aliases +type T5 = ::Assoc; //~ WARN are not enforced +type T6 = ::std::vec::Vec; //~ WARN are not enforced fn main() {} diff --git a/tests/ui/type/type-alias-bounds.stderr b/tests/ui/type/type-alias-bounds.stderr index 92e573393c9..15c00901066 100644 --- a/tests/ui/type/type-alias-bounds.stderr +++ b/tests/ui/type/type-alias-bounds.stderr @@ -1,121 +1,132 @@ -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/type-alias-bounds.rs:8:14 | LL | type SVec = Vec; - | ^^^^ ^^^^ + | --^^^^---^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics = note: `#[warn(type_alias_bounds)]` on by default -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - type SVec = Vec; -LL + type SVec = Vec; - | -warning: where clauses are not enforced in type aliases +warning: where clauses on type aliases are not enforced --> $DIR/type-alias-bounds.rs:10:21 | LL | type S2Vec where T: Send = Vec; - | ^^^^^^^ - | -help: the clause will not be checked when the type alias is used, and should be removed - | -LL - type S2Vec where T: Send = Vec; -LL + type S2Vec = Vec; + | ------^^^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this where clause | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/type-alias-bounds.rs:12:19 | LL | type VVec<'b, 'a: 'b + 'b> = (&'b u32, Vec<&'a i32>); - | ^^ ^^ - | -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - type VVec<'b, 'a: 'b + 'b> = (&'b u32, Vec<&'a i32>); -LL + type VVec<'b, 'a> = (&'b u32, Vec<&'a i32>); + | --^^---^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/type-alias-bounds.rs:14:18 | LL | type WVec<'b, T: 'b + 'b> = (&'b u32, Vec); - | ^^ ^^ - | -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - type WVec<'b, T: 'b + 'b> = (&'b u32, Vec); -LL + type WVec<'b, T> = (&'b u32, Vec); + | --^^---^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: where clauses are not enforced in type aliases +warning: where clauses on type aliases are not enforced --> $DIR/type-alias-bounds.rs:16:25 | LL | type W2Vec<'b, T> where T: 'b, T: 'b = (&'b u32, Vec); - | ^^^^^ ^^^^^ - | -help: the clause will not be checked when the type alias is used, and should be removed - | -LL - type W2Vec<'b, T> where T: 'b, T: 'b = (&'b u32, Vec); -LL + type W2Vec<'b, T> = (&'b u32, Vec); + | ------^^^^^--^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this where clause | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics -warning: bounds on generic parameters are not enforced in type aliases - --> $DIR/type-alias-bounds.rs:47:12 +warning: bounds on generic parameters in type aliases are not enforced + --> $DIR/type-alias-bounds.rs:48:12 | LL | type T1 = U::Assoc; - | ^^^^^ + | ^^^^^ will not be checked at usage sites of the type alias | -help: use fully disambiguated paths (i.e., `::Assoc`) to refer to associated types in type aliases - --> $DIR/type-alias-bounds.rs:47:21 - | -LL | type T1 = U::Assoc; - | ^^^^^^^^ -help: the bound will not be checked when the type alias is used, and should be removed + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics +help: remove this bound | LL - type T1 = U::Assoc; LL + type T1 = U::Assoc; | +help: fully qualify this associated type + | +LL | type T1 = ::Assoc; + | + +++++++++++++++ -warning: where clauses are not enforced in type aliases - --> $DIR/type-alias-bounds.rs:48:18 +warning: where clauses on type aliases are not enforced + --> $DIR/type-alias-bounds.rs:49:18 | LL | type T2 where U: Bound = U::Assoc; - | ^^^^^^^^ + | ^^^^^^^^ will not be checked at usage sites of the type alias | -help: use fully disambiguated paths (i.e., `::Assoc`) to refer to associated types in type aliases - --> $DIR/type-alias-bounds.rs:48:29 - | -LL | type T2 where U: Bound = U::Assoc; - | ^^^^^^^^ -help: the clause will not be checked when the type alias is used, and should be removed + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics +help: remove this where clause | LL - type T2 where U: Bound = U::Assoc; LL + type T2 = U::Assoc; | +help: fully qualify this associated type + | +LL | type T2 where U: Bound = ::Assoc; + | + +++++++++++++++ -warning: bounds on generic parameters are not enforced in type aliases - --> $DIR/type-alias-bounds.rs:56:12 - | -LL | type T5 = ::Assoc; - | ^^^^^ - | -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - type T5 = ::Assoc; -LL + type T5 = ::Assoc; - | - -warning: bounds on generic parameters are not enforced in type aliases +warning: bounds on generic parameters in type aliases are not enforced --> $DIR/type-alias-bounds.rs:57:12 | +LL | type T5 = ::Assoc; + | --^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound + | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics + +warning: bounds on generic parameters in type aliases are not enforced + --> $DIR/type-alias-bounds.rs:58:12 + | LL | type T6 = ::std::vec::Vec; - | ^^^^^ - | -help: the bound will not be checked when the type alias is used, and should be removed - | -LL - type T6 = ::std::vec::Vec; -LL + type T6 = ::std::vec::Vec; + | --^^^^^ + | | | + | | will not be checked at usage sites of the type alias + | help: remove this bound | + = note: this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics warning: 9 warnings emitted From d67b61637e96e6e72b5a676b2f02d1a01b3a94a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 16 Jun 2024 12:22:12 +0200 Subject: [PATCH 09/21] Make lint type_alias_bounds's removal sugg maybe-incorrect if the RHS contains shorthand assoc tys --- compiler/rustc_lint/src/builtin.rs | 91 +++++++++--------- compiler/rustc_lint/src/lints.rs | 147 ++++++++++++----------------- 2 files changed, 109 insertions(+), 129 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index a8c8c71927a..4e1e19e522e 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -32,11 +32,10 @@ use crate::{ BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasBounds, - BuiltinTypeAliasParamBoundsSuggestion, BuiltinUngatedAsyncFnTrackCaller, - BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, - BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, - BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel, - TypeAliasBoundsQualifyAssocTysSugg, + BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, + BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, + BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, + BuiltinWhileTrue, InvalidAsmLabel, }, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, }; @@ -1406,9 +1405,23 @@ declare_lint_pass!( TypeAliasBounds => [TYPE_ALIAS_BOUNDS] ); +impl TypeAliasBounds { + pub(crate) fn affects_object_lifetime_defaults(pred: &hir::WherePredicate<'_>) -> bool { + // Bounds of the form `T: 'a` with `T` type param affect object lifetime defaults. + if let hir::WherePredicate::BoundPredicate(pred) = pred + && pred.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Outlives(_))) + && pred.bound_generic_params.is_empty() // indeed, even if absent from the RHS + && pred.bounded_ty.as_generic_param().is_some() + { + return true; + } + false + } +} + impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - let hir::ItemKind::TyAlias(hir_ty, generics) = &item.kind else { return }; + let hir::ItemKind::TyAlias(hir_ty, generics) = item.kind else { return }; // There must not be a where clause. if generics.predicates.is_empty() { @@ -1437,7 +1450,6 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { let mut where_spans = Vec::new(); let mut inline_spans = Vec::new(); let mut inline_sugg = Vec::new(); - let mut affects_object_lifetime_defaults = false; for p in generics.predicates { let span = p.span(); @@ -1449,45 +1461,22 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { } inline_sugg.push((span, String::new())); } - - // FIXME(fmease): Move this into a "diagnostic decorator" for increased laziness - // Bounds of the form `T: 'a` where `T` is a type param of - // the type alias affect object lifetime defaults. - if !affects_object_lifetime_defaults - && let hir::WherePredicate::BoundPredicate(pred) = p - && pred.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Outlives(_))) - && pred.bound_generic_params.is_empty() - && let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = pred.bounded_ty.kind - && let Res::Def(DefKind::TyParam, _) = path.res - { - affects_object_lifetime_defaults = true; - } } - // FIXME(fmease): Add a disclaimer (in the form of a multi-span note) that the removal of - // type-param-outlives-bounds affects OLDs and explicit object lifetime - // bounds might be required [...]. - // FIXME(fmease): The applicability should also depend on the outcome of the HIR walker - // inside of `TypeAliasBoundsQualifyAssocTysSugg`: Whether it found a - // shorthand projection or not. - let applicability = if affects_object_lifetime_defaults { - Applicability::MaybeIncorrect - } else { - Applicability::MachineApplicable - }; - - let mut qualify_assoc_tys_sugg = Some(TypeAliasBoundsQualifyAssocTysSugg { ty: hir_ty }); - let enable_feat_help = cx.tcx.sess.is_nightly_build().then_some(()); + let mut ty = Some(hir_ty); + let enable_feat_help = cx.tcx.sess.is_nightly_build(); if let [.., label_sp] = *where_spans { cx.emit_span_lint( TYPE_ALIAS_BOUNDS, where_spans, - BuiltinTypeAliasBounds::WhereClause { + BuiltinTypeAliasBounds { + in_where_clause: true, label: label_sp, enable_feat_help, - suggestion: (generics.where_clause_span, applicability), - qualify_assoc_tys_sugg: qualify_assoc_tys_sugg.take(), + suggestions: vec![(generics.where_clause_span, String::new())], + preds: generics.predicates, + ty: ty.take(), }, ); } @@ -1495,20 +1484,36 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { cx.emit_span_lint( TYPE_ALIAS_BOUNDS, inline_spans, - BuiltinTypeAliasBounds::ParamBounds { + BuiltinTypeAliasBounds { + in_where_clause: false, label: label_sp, enable_feat_help, - suggestion: BuiltinTypeAliasParamBoundsSuggestion { - suggestions: inline_sugg, - applicability, - }, - qualify_assoc_tys_sugg, + suggestions: inline_sugg, + preds: generics.predicates, + ty, }, ); } } } +pub(crate) struct ShorthandAssocTyCollector { + pub(crate) qselves: Vec, +} + +impl hir::intravisit::Visitor<'_> for ShorthandAssocTyCollector { + fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, _: Span) { + // Look for "type-parameter shorthand-associated-types". I.e., paths of the + // form `T::Assoc` with `T` type param. These are reliant on trait bounds. + if let hir::QPath::TypeRelative(qself, _) = qpath + && qself.as_generic_param().is_some() + { + self.qselves.push(qself.span); + } + hir::intravisit::walk_qpath(self, qpath, id) + } +} + declare_lint! { /// The `trivial_bounds` lint detects trait bounds that don't depend on /// any type parameters. diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 6cf8b9330fc..b833d56c9bc 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2,8 +2,10 @@ #![allow(rustc::untranslatable_diagnostic)] use std::num::NonZero; -use crate::errors::RequestedLevel; +use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds}; +use crate::errors::{OverruledAttributeSub, RequestedLevel}; use crate::fluent_generated as fluent; +use crate::LateContext; use rustc_errors::{ codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, @@ -22,8 +24,6 @@ use rustc_span::{ Span, Symbol, }; -use crate::{builtin::InitError, errors::OverruledAttributeSub, LateContext}; - // array_into_iter.rs #[derive(LintDiagnostic)] #[diag(lint_shadowed_into_iter)] @@ -268,97 +268,72 @@ pub struct MacroExprFragment2024 { pub suggestion: Span, } -#[derive(LintDiagnostic)] -pub enum BuiltinTypeAliasBounds<'a, 'hir> { - #[diag(lint_builtin_type_alias_bounds_where_clause)] - #[note(lint_builtin_type_alias_bounds_limitation_note)] - WhereClause { - #[label(lint_builtin_type_alias_bounds_label)] - label: Span, - #[help(lint_builtin_type_alias_bounds_enable_feat_help)] - enable_feat_help: Option<()>, - #[suggestion(code = "")] - suggestion: (Span, Applicability), - #[subdiagnostic] - qualify_assoc_tys_sugg: Option>, - }, - #[diag(lint_builtin_type_alias_bounds_param_bounds)] - #[note(lint_builtin_type_alias_bounds_limitation_note)] - ParamBounds { - #[label(lint_builtin_type_alias_bounds_label)] - label: Span, - #[help(lint_builtin_type_alias_bounds_enable_feat_help)] - enable_feat_help: Option<()>, - #[subdiagnostic] - suggestion: BuiltinTypeAliasParamBoundsSuggestion, - #[subdiagnostic] - qualify_assoc_tys_sugg: Option>, - }, -} - -pub struct BuiltinTypeAliasParamBoundsSuggestion { +pub struct BuiltinTypeAliasBounds<'a, 'hir> { + pub in_where_clause: bool, + pub label: Span, + pub enable_feat_help: bool, pub suggestions: Vec<(Span, String)>, - pub applicability: Applicability, + pub preds: &'hir [hir::WherePredicate<'hir>], + pub ty: Option<&'a hir::Ty<'hir>>, } -impl Subdiagnostic for BuiltinTypeAliasParamBoundsSuggestion { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - diag.arg("count", self.suggestions.len()); - diag.multipart_suggestion(fluent::lint_suggestion, self.suggestions, self.applicability); - } -} +impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_, '_> { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(if self.in_where_clause { + fluent::lint_builtin_type_alias_bounds_where_clause + } else { + fluent::lint_builtin_type_alias_bounds_param_bounds + }); + diag.span_label(self.label, fluent::lint_builtin_type_alias_bounds_label); + diag.note(fluent::lint_builtin_type_alias_bounds_limitation_note); + if self.enable_feat_help { + diag.help(fluent::lint_builtin_type_alias_bounds_enable_feat_help); + } -pub struct TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir> { - pub ty: &'a hir::Ty<'hir>, -} - -impl<'a, 'hir> Subdiagnostic for TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { // We perform the walk in here instead of in `` to // avoid doing throwaway work in case the lint ends up getting suppressed. + let mut collector = ShorthandAssocTyCollector { qselves: Vec::new() }; + if let Some(ty) = self.ty { + hir::intravisit::Visitor::visit_ty(&mut collector, ty); + } - use hir::intravisit::Visitor; - struct ProbeShorthandAssocTys<'a, 'b, G: EmissionGuarantee> { - diag: &'a mut Diag<'b, G>, + let affect_object_lifetime_defaults = self + .preds + .iter() + .filter(|pred| pred.in_where_clause() == self.in_where_clause) + .any(|pred| TypeAliasBounds::affects_object_lifetime_defaults(pred)); + + // If there are any shorthand assoc tys, then the bounds can't be removed automatically. + // The user first needs to fully qualify the assoc tys. + let applicability = if !collector.qselves.is_empty() || affect_object_lifetime_defaults { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; + + diag.arg("count", self.suggestions.len()); + diag.multipart_suggestion(fluent::lint_suggestion, self.suggestions, applicability); + + // Suggest fully qualifying paths of the form `T::Assoc` with `T` type param via + // `::Assoc` to remove their reliance on any type param bounds. + // + // Instead of attempting to figure out the necessary trait ref, just use a + // placeholder. Since we don't record type-dependent resolutions for non-body + // items like type aliases, we can't simply deduce the corresp. trait from + // the HIR path alone without rerunning parts of HIR ty lowering here + // (namely `probe_single_ty_param_bound_for_assoc_ty`) which is infeasible. + // + // (We could employ some simple heuristics but that's likely not worth it). + for qself in collector.qselves { + diag.multipart_suggestion( + fluent::lint_builtin_type_alias_bounds_qualify_assoc_tys_sugg, + vec![ + (qself.shrink_to_lo(), "<".into()), + (qself.shrink_to_hi(), " as /* Trait */>".into()), + ], + Applicability::HasPlaceholders, + ); } - impl<'a, 'b, G: EmissionGuarantee> Visitor<'_> for ProbeShorthandAssocTys<'a, 'b, G> { - fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, _: Span) { - // Look for "type-parameter shorthand-associated-types". I.e., paths of the - // form `T::Assoc` with `T` type param. These are reliant on trait bounds. - // Suggest fully qualifying them via `::Assoc`. - // - // Instead of attempting to figure out the necessary trait ref, just use a - // placeholder. Since we don't record type-dependent resolutions for non-body - // items like type aliases, we can't simply deduce the corresp. trait from - // the HIR path alone without rerunning parts of HIR ty lowering here - // (namely `probe_single_ty_param_bound_for_assoc_ty`) which is infeasible. - // - // (We could employ some simple heuristics but that's likely not worth it). - if let hir::QPath::TypeRelative(qself, _) = qpath - && let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind - && let hir::def::Res::Def(hir::def::DefKind::TyParam, _) = path.res - { - self.diag.multipart_suggestion( - fluent::lint_builtin_type_alias_bounds_qualify_assoc_tys_sugg, - vec![ - (qself.span.shrink_to_lo(), "<".into()), - (qself.span.shrink_to_hi(), " as /* Trait */>".into()), - ], - Applicability::HasPlaceholders, - ); - } - hir::intravisit::walk_qpath(self, qpath, id) - } - } - ProbeShorthandAssocTys { diag }.visit_ty(self.ty); } } From 5859dff7429436498aed7fc7efed88a73b3eaf4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 16 Jun 2024 15:53:01 +0200 Subject: [PATCH 10/21] Update the description of lint type_alias_bounds --- compiler/rustc_lint/src/builtin.rs | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 4e1e19e522e..ab0b47d48e5 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1390,20 +1390,32 @@ declare_lint! { /// /// ### Explanation /// - /// The trait bounds in a type alias are currently ignored, and should not - /// be included to avoid confusion. This was previously allowed - /// unintentionally; this may become a hard error in the future. + /// Trait and lifetime bounds on generic parameters and in where clauses of + /// type aliases are not checked at usage sites of the type alias. Moreover, + /// they are not thoroughly checked for correctness at their definition site + /// either similar to the aliased type. + /// + /// This is a known limitation of the type checker that may be lifted in a + /// future edition. Permitting such bounds in light of this was unintentional. + /// + /// While these bounds may have secondary effects such as enabling the use of + /// "shorthand" associated type paths[^1] and affecting the default trait + /// object lifetime[^2] of trait object types passed to the type alias, this + /// should not have been allowed until the aforementioned restrictions of the + /// type checker have been lifted. + /// + /// Using such bounds is highly discouraged as they are actively misleading. + /// + /// [^1]: I.e., paths of the form `T::Assoc` where `T` is a type parameter + /// bounded by trait `Trait` which defines an associated type called `Assoc` + /// as opposed to a fully qualified path of the form `::Assoc`. + /// [^2]: TYPE_ALIAS_BOUNDS, Warn, "bounds in type aliases are not enforced" } -declare_lint_pass!( - /// Lint for trait and lifetime bounds in type aliases being mostly ignored. - /// They are relevant when using associated types, but otherwise neither checked - /// at definition site nor enforced at use site. - TypeAliasBounds => [TYPE_ALIAS_BOUNDS] -); +declare_lint_pass!(TypeAliasBounds => [TYPE_ALIAS_BOUNDS]); impl TypeAliasBounds { pub(crate) fn affects_object_lifetime_defaults(pred: &hir::WherePredicate<'_>) -> bool { From 4dad2a332bfd2dcbd20e99cd70c6cd63f9c92be0 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 19 Jul 2024 15:24:52 -0400 Subject: [PATCH 11/21] rewrite interdependent-c-libraries to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../interdependent-c-libraries/Makefile | 15 --------------- .../interdependent-c-libraries/rmake.rs | 19 +++++++++++++++++++ 3 files changed, 19 insertions(+), 16 deletions(-) delete mode 100644 tests/run-make/interdependent-c-libraries/Makefile create mode 100644 tests/run-make/interdependent-c-libraries/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 36f7f68ef7b..dc1b0906278 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -21,7 +21,6 @@ run-make/foreign-exceptions/Makefile run-make/foreign-rust-exceptions/Makefile run-make/incr-add-rust-src-component/Makefile run-make/incr-foreign-head-span/Makefile -run-make/interdependent-c-libraries/Makefile run-make/issue-35164/Makefile run-make/issue-36710/Makefile run-make/issue-47551/Makefile diff --git a/tests/run-make/interdependent-c-libraries/Makefile b/tests/run-make/interdependent-c-libraries/Makefile deleted file mode 100644 index 53a696d82bf..00000000000 --- a/tests/run-make/interdependent-c-libraries/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# The rust crate foo will link to the native library foo, while the rust crate -# bar will link to the native library bar. There is also a dependency between -# the native library bar to the natibe library foo. -# -# This test ensures that the ordering of -lfoo and -lbar on the command line is -# correct to complete the linkage. If passed as "-lfoo -lbar", then the 'foo' -# library will be stripped out, and the linkage will fail. - -all: $(call NATIVE_STATICLIB,foo) $(call NATIVE_STATICLIB,bar) - $(RUSTC) foo.rs - $(RUSTC) bar.rs - $(RUSTC) main.rs --print link-args diff --git a/tests/run-make/interdependent-c-libraries/rmake.rs b/tests/run-make/interdependent-c-libraries/rmake.rs new file mode 100644 index 00000000000..cd3759d2d71 --- /dev/null +++ b/tests/run-make/interdependent-c-libraries/rmake.rs @@ -0,0 +1,19 @@ +// The rust crate foo will link to the native library foo, while the rust crate +// bar will link to the native library bar. There is also a dependency between +// the native library bar to the natibe library foo. +// This test ensures that the ordering of -lfoo and -lbar on the command line is +// correct to complete the linkage. If passed as "-lfoo -lbar", then the 'foo' +// library will be stripped out, and the linkage will fail. +// See https://github.com/rust-lang/rust/commit/e6072fa0c4c22d62acf3dcb78c8ee260a1368bd7 + +// FIXME(Oneirical): test-various + +use run_make_support::{build_native_static_lib, rustc}; + +fn main() { + build_native_static_lib("foo"); + build_native_static_lib("bar"); + rustc().input("foo.rs").run(); + rustc().input("bar.rs").run(); + rustc().input("main.rs").print("link-args").run(); +} From c424bc61bfe5836b4dc78526001b402592256e0f Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 19 Jul 2024 15:51:49 -0400 Subject: [PATCH 12/21] rewrite compiler-rt-works-on-mingw to rmake --- .../run-make-support/src/external_deps/cc.rs | 21 +++++++++++++++++++ src/tools/run-make-support/src/lib.rs | 2 +- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../compiler-rt-works-on-mingw/Makefile | 9 -------- .../compiler-rt-works-on-mingw/rmake.rs | 15 +++++++++++++ 5 files changed, 37 insertions(+), 11 deletions(-) delete mode 100644 tests/run-make/compiler-rt-works-on-mingw/Makefile create mode 100644 tests/run-make/compiler-rt-works-on-mingw/rmake.rs diff --git a/src/tools/run-make-support/src/external_deps/cc.rs b/src/tools/run-make-support/src/external_deps/cc.rs index 840bfa0d2b4..5eeeb887444 100644 --- a/src/tools/run-make-support/src/external_deps/cc.rs +++ b/src/tools/run-make-support/src/external_deps/cc.rs @@ -15,6 +15,12 @@ pub fn cc() -> Cc { Cc::new() } +/// Construct a new platform-specific CXX compiler invocation. +#[track_caller] +pub fn cxx() -> Cc { + Cc::new_cxx() +} + /// A platform-specific C compiler invocation builder. The specific C compiler used is /// passed down from compiletest. #[derive(Debug)] @@ -44,6 +50,21 @@ impl Cc { Self { cmd } } + /// Construct a new platform-specific CXX compiler invocation. + #[track_caller] + pub fn new_cxx() -> Self { + let compiler = env_var("CXX"); + + let mut cmd = Command::new(compiler); + + let default_cflags = env_var("CXX_DEFAULT_FLAGS"); + for flag in default_cflags.split(char::is_whitespace) { + cmd.arg(flag); + } + + Self { cmd } + } + /// Specify path of the input file. pub fn input>(&mut self, path: P) -> &mut Self { self.cmd.arg(path.as_ref()); diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index a4bb9056346..085120764b4 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -44,7 +44,7 @@ pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rust // These rely on external dependencies. pub use c_build::{build_native_dynamic_lib, build_native_static_lib}; -pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; +pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc}; pub use clang::{clang, Clang}; pub use htmldocck::htmldocck; pub use llvm::{ diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index dc1b0906278..114709cc300 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -2,7 +2,6 @@ run-make/branch-protection-check-IBT/Makefile run-make/c-unwind-abi-catch-lib-panic/Makefile run-make/cat-and-grep-sanity-check/Makefile run-make/cdylib-dylib-linkage/Makefile -run-make/compiler-rt-works-on-mingw/Makefile run-make/cross-lang-lto-clang/Makefile run-make/cross-lang-lto-pgo-smoketest/Makefile run-make/cross-lang-lto-upstream-rlibs/Makefile diff --git a/tests/run-make/compiler-rt-works-on-mingw/Makefile b/tests/run-make/compiler-rt-works-on-mingw/Makefile deleted file mode 100644 index 74917570a01..00000000000 --- a/tests/run-make/compiler-rt-works-on-mingw/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../tools.mk - -# only-windows-gnu - -all: - $(CXX) foo.cpp -c -o $(TMPDIR)/foo.o - $(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o - $(RUSTC) foo.rs -lfoo -lstdc++ - $(call RUN,foo) diff --git a/tests/run-make/compiler-rt-works-on-mingw/rmake.rs b/tests/run-make/compiler-rt-works-on-mingw/rmake.rs new file mode 100644 index 00000000000..9bee91232ce --- /dev/null +++ b/tests/run-make/compiler-rt-works-on-mingw/rmake.rs @@ -0,0 +1,15 @@ +// `compiler-rt` ("runtime") is a suite of LLVM features compatible with rustc. +// After building it was enabled on Windows-gnu in #29874, this test checks +// that compilation and execution with it are successful. +// See https://github.com/rust-lang/rust/pull/29478 + +//@ only-windows-gnu + +use run_make_support::{cxx, is_msvc, llvm_ar, run, rustc, static_lib_name}; + +fn main() { + cxx().input("foo.cpp").arg("-c").out_exe("foo.o").run(); + llvm_ar().obj_to_ar().output_input(static_lib_name("foo"), "foo.o").run(); + rustc().input("foo.rs").arg("-lfoo").arg("-lstdc++").run(); + run("foo"); +} From e175b83fd55e9901eb659a7acd7a8add830eef12 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 19 Jul 2024 16:01:06 -0400 Subject: [PATCH 13/21] rewrite incr-foreign-head-span to rmake --- src/tools/compiletest/src/command-list.rs | 1 + .../run-make-support/src/external_deps/cc.rs | 2 ++ .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../compiler-rt-works-on-mingw/rmake.rs | 4 +-- .../run-make/incr-foreign-head-span/Makefile | 21 ---------------- .../run-make/incr-foreign-head-span/rmake.rs | 25 +++++++++++++++++++ .../interdependent-c-libraries/rmake.rs | 4 ++- 7 files changed, 33 insertions(+), 25 deletions(-) delete mode 100644 tests/run-make/incr-foreign-head-span/Makefile create mode 100644 tests/run-make/incr-foreign-head-span/rmake.rs diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs index 6735e9faa7a..c356f4266f0 100644 --- a/src/tools/compiletest/src/command-list.rs +++ b/src/tools/compiletest/src/command-list.rs @@ -201,6 +201,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-wasm32-wasip1", "only-watchos", "only-windows", + "only-windows-gnu", "only-x86", "only-x86_64", "only-x86_64-fortanix-unknown-sgx", diff --git a/src/tools/run-make-support/src/external_deps/cc.rs b/src/tools/run-make-support/src/external_deps/cc.rs index 5eeeb887444..19a89705acc 100644 --- a/src/tools/run-make-support/src/external_deps/cc.rs +++ b/src/tools/run-make-support/src/external_deps/cc.rs @@ -16,6 +16,7 @@ pub fn cc() -> Cc { } /// Construct a new platform-specific CXX compiler invocation. +/// CXX_DEFAULT_FLAGS is passed from compiletest. #[track_caller] pub fn cxx() -> Cc { Cc::new_cxx() @@ -51,6 +52,7 @@ impl Cc { } /// Construct a new platform-specific CXX compiler invocation. + /// CXX_DEFAULT_FLAGS is passed from compiletest. #[track_caller] pub fn new_cxx() -> Self { let compiler = env_var("CXX"); diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 114709cc300..14e9a83b4c0 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -19,7 +19,6 @@ run-make/foreign-double-unwind/Makefile run-make/foreign-exceptions/Makefile run-make/foreign-rust-exceptions/Makefile run-make/incr-add-rust-src-component/Makefile -run-make/incr-foreign-head-span/Makefile run-make/issue-35164/Makefile run-make/issue-36710/Makefile run-make/issue-47551/Makefile diff --git a/tests/run-make/compiler-rt-works-on-mingw/rmake.rs b/tests/run-make/compiler-rt-works-on-mingw/rmake.rs index 9bee91232ce..f1b41f96312 100644 --- a/tests/run-make/compiler-rt-works-on-mingw/rmake.rs +++ b/tests/run-make/compiler-rt-works-on-mingw/rmake.rs @@ -1,6 +1,6 @@ // `compiler-rt` ("runtime") is a suite of LLVM features compatible with rustc. -// After building it was enabled on Windows-gnu in #29874, this test checks -// that compilation and execution with it are successful. +// After building it was enabled on Windows-gnu in #29874, this test is a basic smoke test to +// check if building and linking to it can work at all. // See https://github.com/rust-lang/rust/pull/29478 //@ only-windows-gnu diff --git a/tests/run-make/incr-foreign-head-span/Makefile b/tests/run-make/incr-foreign-head-span/Makefile deleted file mode 100644 index 9be4b0f601c..00000000000 --- a/tests/run-make/incr-foreign-head-span/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -include ../tools.mk - -# ignore-none no-std is not supported -# ignore-nvptx64-nvidia-cuda FIXME: can't find crate for 'std' - -# Ensure that modifying a crate on disk (without recompiling it) -# does not cause ICEs in downstream crates. -# Previously, we would call `SourceMap.guess_head_span` on a span -# from an external crate, which would cause us to read an upstream -# source file from disk during compilation of a downstream crate -# See #86480 for more details - -INCR=$(TMPDIR)/incr - -all: - cp first_crate.rs second_crate.rs $(TMPDIR) - $(RUSTC) $(TMPDIR)/first_crate.rs -C incremental=$(INCR) --target $(TARGET) --crate-type lib - $(RUSTC) $(TMPDIR)/second_crate.rs -C incremental=$(INCR) --target $(TARGET) --extern first_crate=$(TMPDIR)/libfirst_crate.rlib --crate-type lib - rm $(TMPDIR)/first_crate.rs - $(RUSTC) $(TMPDIR)/second_crate.rs -C incremental=$(INCR) --target $(TARGET) --cfg second_run --crate-type lib - diff --git a/tests/run-make/incr-foreign-head-span/rmake.rs b/tests/run-make/incr-foreign-head-span/rmake.rs new file mode 100644 index 00000000000..92e2ed5f879 --- /dev/null +++ b/tests/run-make/incr-foreign-head-span/rmake.rs @@ -0,0 +1,25 @@ +// Ensure that modifying a crate on disk (without recompiling it) +// does not cause ICEs (internal compiler errors) in downstream crates. +// Previously, we would call `SourceMap.guess_head_span` on a span +// from an external crate, which would cause us to read an upstream +// source file from disk during compilation of a downstream crate. +// See https://github.com/rust-lang/rust/issues/86480 + +//@ ignore-none +// Reason: no-std is not supported +//@ ignore-nvptx64-nvidia-cuda +// Reason: can't find crate for 'std' + +use run_make_support::{rfs, rust_lib_name, rustc}; + +fn main() { + rustc().input("first_crate.rs").incremental("incr").crate_type("lib").run(); + rustc() + .input("second_crate.rs") + .incremental("incr") + .extern_("first_crate", rust_lib_name("first_crate")) + .crate_type("lib") + .run(); + rfs::remove_file("first_crate.rs"); + rustc().input("second_crate.rs").incremental("incr").cfg("second_run").crate_type("lib").run(); +} diff --git a/tests/run-make/interdependent-c-libraries/rmake.rs b/tests/run-make/interdependent-c-libraries/rmake.rs index cd3759d2d71..ee8cc76c9cc 100644 --- a/tests/run-make/interdependent-c-libraries/rmake.rs +++ b/tests/run-make/interdependent-c-libraries/rmake.rs @@ -6,7 +6,9 @@ // library will be stripped out, and the linkage will fail. // See https://github.com/rust-lang/rust/commit/e6072fa0c4c22d62acf3dcb78c8ee260a1368bd7 -// FIXME(Oneirical): test-various +//@ ignore-cross-compile +// Reason: linkage still fails as the object files produced are not in the correct +// format in the `build_native_static_lib` step use run_make_support::{build_native_static_lib, rustc}; From 0d52289b5eeb71ec82f21c273985a1647da038c4 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 9 Jul 2024 11:40:02 -0400 Subject: [PATCH 14/21] rewrite dump-ice-to-disk to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/dump-ice-to-disk/Makefile | 10 --- tests/run-make/dump-ice-to-disk/check.sh | 64 ------------------- .../dump-ice-to-disk/{src => }/lib.rs | 0 tests/run-make/dump-ice-to-disk/rmake.rs | 64 +++++++++++++++++++ 5 files changed, 64 insertions(+), 75 deletions(-) delete mode 100644 tests/run-make/dump-ice-to-disk/Makefile delete mode 100644 tests/run-make/dump-ice-to-disk/check.sh rename tests/run-make/dump-ice-to-disk/{src => }/lib.rs (100%) create mode 100644 tests/run-make/dump-ice-to-disk/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 36f7f68ef7b..08a6bbfe0e7 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -10,7 +10,6 @@ run-make/cross-lang-lto/Makefile run-make/dep-info-doesnt-run-much/Makefile run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile -run-make/dump-ice-to-disk/Makefile run-make/emit-to-stdout/Makefile run-make/export-executable-symbols/Makefile run-make/extern-flag-disambiguates/Makefile diff --git a/tests/run-make/dump-ice-to-disk/Makefile b/tests/run-make/dump-ice-to-disk/Makefile deleted file mode 100644 index 23006fc09e2..00000000000 --- a/tests/run-make/dump-ice-to-disk/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -include ../tools.mk - -# ignore-windows - -export RUSTC := $(RUSTC_ORIGINAL) -export LD_LIBRARY_PATH := $(HOST_RPATH_DIR) -export TMPDIR := $(TMPDIR) - -all: - bash check.sh diff --git a/tests/run-make/dump-ice-to-disk/check.sh b/tests/run-make/dump-ice-to-disk/check.sh deleted file mode 100644 index ff6e4be35af..00000000000 --- a/tests/run-make/dump-ice-to-disk/check.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/sh - -# Default nightly behavior (write ICE to current directory) -# FIXME(estebank): these are failing on CI, but passing locally. -# $RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-default.log 2>&1 -# default=$(cat ./rustc-ice-*.txt | wc -l) -# rm ./rustc-ice-*.txt - -# Explicit directory set -export RUSTC_ICE=$TMPDIR -$RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-default-set.log 2>&1 -default_set=$(cat $TMPDIR/rustc-ice-*.txt | wc -l) -content=$(cat $TMPDIR/rustc-ice-*.txt) -# Ensure that the ICE dump path doesn't contain `:` because they cause problems on Windows -windows_safe=$(echo rustc-ice-*.txt | grep ':') -if [ ! -z "$windows_safe" ]; then - exit 1 -fi - -rm $TMPDIR/rustc-ice-*.txt -RUST_BACKTRACE=short $RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-short.log 2>&1 -short=$(cat $TMPDIR/rustc-ice-*.txt | wc -l) -rm $TMPDIR/rustc-ice-*.txt -RUST_BACKTRACE=full $RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-full.log 2>&1 -full=$(cat $TMPDIR/rustc-ice-*.txt | wc -l) -rm $TMPDIR/rustc-ice-*.txt - -# Explicitly disabling ICE dump -export RUSTC_ICE=0 -$RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-disabled.log 2>&1 -should_be_empty_tmp=$(ls -l $TMPDIR/rustc-ice-*.txt 2>/dev/null | wc -l) -should_be_empty_dot=$(ls -l ./rustc-ice-*.txt 2>/dev/null | wc -l) - -echo "#### ICE Dump content:" -echo $content -echo "#### default length:" -echo $default -echo "#### short length:" -echo $short -echo "#### default_set length:" -echo $default_set -echo "#### full length:" -echo $full -echo "#### should_be_empty_dot length:" -echo $should_be_empty_dot -echo "#### should_be_empty_tmp length:" -echo $should_be_empty_tmp - -## Verify that a the ICE dump file is created in the appropriate directories, that -## their lengths are the same regardless of other backtrace configuration options, -## that the file is not created when asked to (RUSTC_ICE=0) and that the file -## contains at least part of the expected content. -if [ $short -eq $default_set ] && - #[ $default -eq $short ] && - [ $default_set -eq $full ] && - [[ $content == *"thread 'rustc' panicked at "* ]] && - [[ $content == *"stack backtrace:"* ]] && - #[ $default -gt 0 ] && - [ $should_be_empty_dot -eq 0 ] && - [ $should_be_empty_tmp -eq 0 ]; then - exit 0 -else - exit 1 -fi diff --git a/tests/run-make/dump-ice-to-disk/src/lib.rs b/tests/run-make/dump-ice-to-disk/lib.rs similarity index 100% rename from tests/run-make/dump-ice-to-disk/src/lib.rs rename to tests/run-make/dump-ice-to-disk/lib.rs diff --git a/tests/run-make/dump-ice-to-disk/rmake.rs b/tests/run-make/dump-ice-to-disk/rmake.rs new file mode 100644 index 00000000000..95f9223452c --- /dev/null +++ b/tests/run-make/dump-ice-to-disk/rmake.rs @@ -0,0 +1,64 @@ +// This test checks if internal compilation error (ICE) log files work as expected. +// - Get the number of lines from the log files without any configuration options, +// then check that the line count doesn't change if the backtrace gets configured to be short +// or full. +// - Check that disabling ICE logging results in zero files created. +// - Check that the ICE files contain some of the expected strings. +// See https://github.com/rust-lang/rust/pull/108714 + +// FIXME(Oneirical): try it on Windows! + +use run_make_support::{cwd, fs_wrapper, has_extension, has_prefix, rustc, shallow_find_files}; + +fn main() { + rustc().input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail(); + let ice_text = get_text_from_ice(); + let default_set = ice_text.lines().count(); + let content = ice_text; + // Ensure that the ICE files don't contain `:` in their filename because + // this causes problems on Windows. + for file in shallow_find_files(cwd(), |path| { + has_prefix(path, "rustc-ice") && has_extension(path, "txt") + }) { + assert!(!file.display().to_string().contains(":")); + } + + clear_ice_files(); + rustc().input("lib.rs").env("RUST_BACKTRACE", "short").arg("-Ztreat-err-as-bug=1").run_fail(); + let short = get_text_from_ice().lines().count(); + clear_ice_files(); + rustc().input("lib.rs").env("RUST_BACKTRACE", "full").arg("-Ztreat-err-as-bug=1").run_fail(); + let full = get_text_from_ice().lines().count(); + clear_ice_files(); + + // The ICE dump is explicitely disabled. Therefore, this should produce no files. + rustc().env("RUSTC_ICE", "0").input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail(); + assert!(get_text_from_ice().is_empty()); + + // The line count should not change. + assert_eq!(short, default_set); + assert_eq!(full, default_set); + // Some of the expected strings in an ICE file should appear. + assert!(content.contains("thread 'rustc' panicked at")); + assert!(content.contains("stack backtrace:")); +} + +fn clear_ice_files() { + let ice_files = shallow_find_files(cwd(), |path| { + has_prefix(path, "rustc-ice") && has_extension(path, "txt") + }); + for file in ice_files { + fs_wrapper::remove_file(file); + } +} + +fn get_text_from_ice() -> String { + let ice_files = shallow_find_files(cwd(), |path| { + has_prefix(path, "rustc-ice") && has_extension(path, "txt") + }); + let mut output = String::new(); + for file in ice_files { + output.push_str(&fs_wrapper::read_to_string(file)); + } + output +} From f72bf8ba345d6fdb3946bc121e31077cde14c7e2 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 9 Jul 2024 11:55:54 -0400 Subject: [PATCH 15/21] rewrite panic-abort-eh_frame to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/dump-ice-to-disk/rmake.rs | 67 ++++++++++++------- tests/run-make/panic-abort-eh_frame/Makefile | 10 --- tests/run-make/panic-abort-eh_frame/rmake.rs | 24 +++++++ 4 files changed, 66 insertions(+), 36 deletions(-) delete mode 100644 tests/run-make/panic-abort-eh_frame/Makefile create mode 100644 tests/run-make/panic-abort-eh_frame/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 08a6bbfe0e7..13079486aaf 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -41,7 +41,6 @@ run-make/native-link-modifier-bundle/Makefile run-make/native-link-modifier-whole-archive/Makefile run-make/no-alloc-shim/Makefile run-make/no-builtins-attribute/Makefile -run-make/panic-abort-eh_frame/Makefile run-make/pdb-buildinfo-cl-cmd/Makefile run-make/pgo-gen-lto/Makefile run-make/pgo-indirect-call-promotion/Makefile diff --git a/tests/run-make/dump-ice-to-disk/rmake.rs b/tests/run-make/dump-ice-to-disk/rmake.rs index 95f9223452c..2fb5c825064 100644 --- a/tests/run-make/dump-ice-to-disk/rmake.rs +++ b/tests/run-make/dump-ice-to-disk/rmake.rs @@ -6,38 +6,56 @@ // - Check that the ICE files contain some of the expected strings. // See https://github.com/rust-lang/rust/pull/108714 -// FIXME(Oneirical): try it on Windows! - -use run_make_support::{cwd, fs_wrapper, has_extension, has_prefix, rustc, shallow_find_files}; +use run_make_support::{cwd, has_extension, has_prefix, rfs, rustc, shallow_find_files}; fn main() { rustc().input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail(); - let ice_text = get_text_from_ice(); + let default = get_text_from_ice(".").lines().count(); + clear_ice_files(); + + rustc().env("RUSTC_ICE", cwd()).input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail(); + let ice_text = get_text_from_ice(cwd()); let default_set = ice_text.lines().count(); let content = ice_text; - // Ensure that the ICE files don't contain `:` in their filename because - // this causes problems on Windows. - for file in shallow_find_files(cwd(), |path| { + let ice_files = shallow_find_files(cwd(), |path| { has_prefix(path, "rustc-ice") && has_extension(path, "txt") - }) { - assert!(!file.display().to_string().contains(":")); - } + }); + assert_eq!(ice_files.len(), 1); // There should only be 1 ICE file. + let ice_file_name = + ice_files.first().and_then(|f| f.file_name()).and_then(|n| n.to_str()).unwrap(); + // Ensure that the ICE dump path doesn't contain `:`, because they cause problems on Windows. + assert!(!ice_file_name.contains(":"), "{ice_file_name}"); clear_ice_files(); - rustc().input("lib.rs").env("RUST_BACKTRACE", "short").arg("-Ztreat-err-as-bug=1").run_fail(); - let short = get_text_from_ice().lines().count(); + rustc() + .env("RUSTC_ICE", cwd()) + .input("lib.rs") + .env("RUST_BACKTRACE", "short") + .arg("-Ztreat-err-as-bug=1") + .run_fail(); + let short = get_text_from_ice(cwd()).lines().count(); clear_ice_files(); - rustc().input("lib.rs").env("RUST_BACKTRACE", "full").arg("-Ztreat-err-as-bug=1").run_fail(); - let full = get_text_from_ice().lines().count(); + rustc() + .env("RUSTC_ICE", cwd()) + .input("lib.rs") + .env("RUST_BACKTRACE", "full") + .arg("-Ztreat-err-as-bug=1") + .run_fail(); + let full = get_text_from_ice(cwd()).lines().count(); clear_ice_files(); - // The ICE dump is explicitely disabled. Therefore, this should produce no files. + // The ICE dump is explicitly disabled. Therefore, this should produce no files. rustc().env("RUSTC_ICE", "0").input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail(); - assert!(get_text_from_ice().is_empty()); + let ice_files = shallow_find_files(cwd(), |path| { + has_prefix(path, "rustc-ice") && has_extension(path, "txt") + }); + assert!(ice_files.is_empty()); // There should be 0 ICE files. // The line count should not change. assert_eq!(short, default_set); + assert_eq!(short, default); assert_eq!(full, default_set); + assert!(default > 0); // Some of the expected strings in an ICE file should appear. assert!(content.contains("thread 'rustc' panicked at")); assert!(content.contains("stack backtrace:")); @@ -48,17 +66,16 @@ fn clear_ice_files() { has_prefix(path, "rustc-ice") && has_extension(path, "txt") }); for file in ice_files { - fs_wrapper::remove_file(file); + rfs::remove_file(file); } } -fn get_text_from_ice() -> String { - let ice_files = shallow_find_files(cwd(), |path| { - has_prefix(path, "rustc-ice") && has_extension(path, "txt") - }); - let mut output = String::new(); - for file in ice_files { - output.push_str(&fs_wrapper::read_to_string(file)); - } +#[track_caller] +fn get_text_from_ice(dir: impl AsRef) -> String { + let ice_files = + shallow_find_files(dir, |path| has_prefix(path, "rustc-ice") && has_extension(path, "txt")); + assert_eq!(ice_files.len(), 1); // There should only be 1 ICE file. + let ice_file = ice_files.get(0).unwrap(); + let output = rfs::read_to_string(ice_file); output } diff --git a/tests/run-make/panic-abort-eh_frame/Makefile b/tests/run-make/panic-abort-eh_frame/Makefile deleted file mode 100644 index 7020455b742..00000000000 --- a/tests/run-make/panic-abort-eh_frame/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# only-linux -# -# This test ensures that `panic=abort` code (without `C-unwind`, that is) should not have any -# unwinding related `.eh_frame` sections emitted. - -include ../tools.mk - -all: - $(RUSTC) foo.rs --crate-type=lib --emit=obj=$(TMPDIR)/foo.o -Cpanic=abort --edition 2021 -Z validate-mir - objdump --dwarf=frames $(TMPDIR)/foo.o | $(CGREP) -v 'DW_CFA' diff --git a/tests/run-make/panic-abort-eh_frame/rmake.rs b/tests/run-make/panic-abort-eh_frame/rmake.rs new file mode 100644 index 00000000000..23d95dc5774 --- /dev/null +++ b/tests/run-make/panic-abort-eh_frame/rmake.rs @@ -0,0 +1,24 @@ +// An `.eh_frame` section in an object file is a symptom of an UnwindAction::Terminate +// being inserted, useful for determining whether or not unwinding is necessary. +// This is useless when panics would NEVER unwind due to -C panic=abort. This section should +// therefore never appear in the emit file of a -C panic=abort compilation, and this test +// checks that this is respected. +// See https://github.com/rust-lang/rust/pull/112403 + +//@ only-linux +// FIXME(Oneirical): the DW_CFA symbol appears on Windows-gnu, because uwtable +// is forced to true on Windows targets (see #128136). + +use run_make_support::{llvm_objdump, rustc}; + +fn main() { + rustc() + .input("foo.rs") + .crate_type("lib") + .emit("obj=foo.o") + .panic("abort") + .edition("2021") + .arg("-Zvalidate-mir") + .run(); + llvm_objdump().arg("--dwarf=frames").input("foo.o").run().assert_stdout_not_contains("DW_CFA"); +} From bade1428eebc2f477549c6c025cb9b51f6fe1f9d Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 23 Jul 2024 11:32:00 -0400 Subject: [PATCH 16/21] migrate tests/run-make/extern-flag-disambiguates to rmake --- .../extern-flag-disambiguates/Makefile | 26 ---------------- .../extern-flag-disambiguates/rmake.rs | 30 +++++++++++++++++++ 2 files changed, 30 insertions(+), 26 deletions(-) delete mode 100644 tests/run-make/extern-flag-disambiguates/Makefile create mode 100644 tests/run-make/extern-flag-disambiguates/rmake.rs diff --git a/tests/run-make/extern-flag-disambiguates/Makefile b/tests/run-make/extern-flag-disambiguates/Makefile deleted file mode 100644 index e54a537ecd0..00000000000 --- a/tests/run-make/extern-flag-disambiguates/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Attempt to build this dependency tree: -# -# A.1 A.2 -# |\ | -# | \ | -# B \ C -# \ | / -# \|/ -# D -# -# Note that A.1 and A.2 are crates with the same name. - -all: - $(RUSTC) -C metadata=1 -C extra-filename=-1 a.rs - $(RUSTC) -C metadata=2 -C extra-filename=-2 a.rs - $(RUSTC) b.rs --extern a=$(TMPDIR)/liba-1.rlib - $(RUSTC) c.rs --extern a=$(TMPDIR)/liba-2.rlib - @echo before - $(RUSTC) --cfg before d.rs --extern a=$(TMPDIR)/liba-1.rlib - $(call RUN,d) - @echo after - $(RUSTC) --cfg after d.rs --extern a=$(TMPDIR)/liba-1.rlib - $(call RUN,d) diff --git a/tests/run-make/extern-flag-disambiguates/rmake.rs b/tests/run-make/extern-flag-disambiguates/rmake.rs new file mode 100644 index 00000000000..8e84b06713e --- /dev/null +++ b/tests/run-make/extern-flag-disambiguates/rmake.rs @@ -0,0 +1,30 @@ +//@ ignore-cross-compile + +use run_make_support::{cwd, run, run_in_tmpdir, rustc}; + +// Attempt to build this dependency tree: +// +// A.1 A.2 +// |\ | +// | \ | +// B \ C +// \ | / +// \|/ +// D +// +// Note that A.1 and A.2 are crates with the same name. + +fn main() { + run_in_tmpdir(|| { + rustc().metadata("1").extra_filename("-1").input("a.rs").run(); + rustc().metadata("2").extra_filename("-2").input("a.rs").run(); + rustc().input("b.rs").extern_("a", "liba-1.rlib").run(); + rustc().input("c.rs").extern_("a", "liba-2.rlib").run(); + println!("before"); + rustc().cfg("before").input("d.rs").extern_("a", "liba-1.rlib").run(); + run("d"); + println!("after"); + rustc().cfg("after").input("d.rs").extern_("a", "liba-1.rlib").run(); + run("d"); + }); +} From 20c67131c6b8dd19057da25b61db66f554060f9c Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 23 Jul 2024 11:34:22 -0400 Subject: [PATCH 17/21] note that rmake.rs files are not subject to automatic formatting --- tests/run-make/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/run-make/README.md b/tests/run-make/README.md index a6c1b4b7db7..40359903473 100644 --- a/tests/run-make/README.md +++ b/tests/run-make/README.md @@ -41,3 +41,8 @@ The setup for the `rmake.rs` version is a 3-stage process: [`run_make_support`]: ../../src/tools/run-make-support [extern_prelude]: https://doc.rust-lang.org/reference/names/preludes.html#extern-prelude + +### Formatting + +Note that files under `tests/` are not formatted by `./x fmt`, +use `rustfmt tests/path/to/file.rs` to format a specific file if desired. From 7638889f418a88f596806ffeb59e9345fd156b46 Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 23 Jul 2024 14:50:00 -0400 Subject: [PATCH 18/21] clean up rmake test --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../extern-flag-disambiguates/rmake.rs | 40 +++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 36f7f68ef7b..229dc87574a 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -13,7 +13,6 @@ run-make/dep-info/Makefile run-make/dump-ice-to-disk/Makefile run-make/emit-to-stdout/Makefile run-make/export-executable-symbols/Makefile -run-make/extern-flag-disambiguates/Makefile run-make/extern-fn-reachable/Makefile run-make/fmt-write-bloat/Makefile run-make/foreign-double-unwind/Makefile diff --git a/tests/run-make/extern-flag-disambiguates/rmake.rs b/tests/run-make/extern-flag-disambiguates/rmake.rs index 8e84b06713e..af00da856b9 100644 --- a/tests/run-make/extern-flag-disambiguates/rmake.rs +++ b/tests/run-make/extern-flag-disambiguates/rmake.rs @@ -1,30 +1,30 @@ //@ ignore-cross-compile -use run_make_support::{cwd, run, run_in_tmpdir, rustc}; +use run_make_support::{cwd, run, rustc}; // Attempt to build this dependency tree: // -// A.1 A.2 -// |\ | -// | \ | -// B \ C -// \ | / -// \|/ -// D +// A.1 A.2 +// |\ | +// | \ | +// B \ C +// \ | / +// \|/ +// D // // Note that A.1 and A.2 are crates with the same name. +// original Makefile at https://github.com/rust-lang/rust/commit/cc3c8bbfaf5af19caf3deb131a995a65ca4674f9#diff-23d3f6bcee0c974ae7c793ab6f87c454cffd1f5c9ec17ce86aaf2cf8bc6e5397 + fn main() { - run_in_tmpdir(|| { - rustc().metadata("1").extra_filename("-1").input("a.rs").run(); - rustc().metadata("2").extra_filename("-2").input("a.rs").run(); - rustc().input("b.rs").extern_("a", "liba-1.rlib").run(); - rustc().input("c.rs").extern_("a", "liba-2.rlib").run(); - println!("before"); - rustc().cfg("before").input("d.rs").extern_("a", "liba-1.rlib").run(); - run("d"); - println!("after"); - rustc().cfg("after").input("d.rs").extern_("a", "liba-1.rlib").run(); - run("d"); - }); + rustc().metadata("1").extra_filename("-1").input("a.rs").run(); + rustc().metadata("2").extra_filename("-2").input("a.rs").run(); + rustc().input("b.rs").extern_("a", "liba-1.rlib").run(); + rustc().input("c.rs").extern_("a", "liba-2.rlib").run(); + println!("before"); + rustc().cfg("before").input("d.rs").extern_("a", "liba-1.rlib").run(); + run("d"); + println!("after"); + rustc().cfg("after").input("d.rs").extern_("a", "liba-1.rlib").run(); + run("d"); } From 62dff66a6c2b13a962743b62122a2945766485ed Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 23 Jul 2024 18:38:42 -0400 Subject: [PATCH 19/21] use shorter link and remove entries wrongly added in rebase --- tests/run-make/extern-flag-disambiguates/rmake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-make/extern-flag-disambiguates/rmake.rs b/tests/run-make/extern-flag-disambiguates/rmake.rs index af00da856b9..2d7d7f69f66 100644 --- a/tests/run-make/extern-flag-disambiguates/rmake.rs +++ b/tests/run-make/extern-flag-disambiguates/rmake.rs @@ -14,7 +14,7 @@ use run_make_support::{cwd, run, rustc}; // // Note that A.1 and A.2 are crates with the same name. -// original Makefile at https://github.com/rust-lang/rust/commit/cc3c8bbfaf5af19caf3deb131a995a65ca4674f9#diff-23d3f6bcee0c974ae7c793ab6f87c454cffd1f5c9ec17ce86aaf2cf8bc6e5397 +// original Makefile at https://github.com/rust-lang/rust/issues/14469 fn main() { rustc().metadata("1").extra_filename("-1").input("a.rs").run(); From f4f57bfccb98522f4aaa2942baaa5a381c7d952d Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 24 Jul 2024 22:43:12 -0400 Subject: [PATCH 20/21] Make Clone::clone a lang item --- compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_mir_transform/src/instsimplify.rs | 4 ++-- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/clone.rs | 3 +++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 58cc0f62111..1821387e85f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -162,6 +162,7 @@ language_item_table! { StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None; Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0); Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None; + CloneFn, sym::clone_fn, clone_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0); DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None; /// The associated item of the `DiscriminantKind` trait. diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 8209e5e2711..58fdc2d9e45 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -3,6 +3,7 @@ use crate::simplify::simplify_duplicate_switch_targets; use crate::take_array; use rustc_ast::attr; +use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::*; use rustc_middle::ty::layout; @@ -271,8 +272,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { return; } - let trait_def_id = self.tcx.trait_of_item(fn_def_id); - if trait_def_id.is_none() || trait_def_id != self.tcx.lang_items().clone_trait() { + if !self.tcx.is_lang_item(fn_def_id, LangItem::CloneFn) { return; } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5ae01389116..18bc514fc98 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -557,6 +557,7 @@ symbols! { clobber_abi, clone, clone_closures, + clone_fn, clone_from, closure, closure_lifetime_binder, diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 939b2be6dfa..76a89eaaff8 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -160,6 +160,9 @@ pub trait Clone: Sized { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "cloning is often expensive and is not expected to have side effects"] + // Clone::clone is special because the compiler generates MIR to implement it for some types. + // See InstanceKind::CloneShim. + #[cfg_attr(not(bootstrap), lang = "clone_fn")] fn clone(&self) -> Self; /// Performs copy-assignment from `source`. From 2fca4ea317f2f45a9a6f8272e52661807b100ca3 Mon Sep 17 00:00:00 2001 From: Lin Yihai Date: Wed, 10 Jul 2024 10:59:33 +0800 Subject: [PATCH 21/21] Add a label to point to the lacking macro name definition --- compiler/rustc_resolve/src/diagnostics.rs | 5 ++++- compiler/rustc_resolve/src/errors.rs | 2 +- tests/ui/macros/issue-118786.rs | 1 + tests/ui/macros/issue-118786.stderr | 6 +++--- tests/ui/resolve/issue-118295.rs | 6 ++++++ tests/ui/resolve/issue-118295.stderr | 18 +++++++++++++++--- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index ffd495aa985..28a3698c080 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1439,7 +1439,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ); if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules { - err.subdiagnostic(MaybeMissingMacroRulesName { span: ident.span }); + let label_span = ident.span.shrink_to_hi(); + let mut spans = MultiSpan::from_span(label_span); + spans.push_span_label(label_span, "put a macro name here"); + err.subdiagnostic(MaybeMissingMacroRulesName { spans: spans }); return; } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 0620f3d709e..5bcb2badd95 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -667,7 +667,7 @@ pub(crate) struct MacroSuggMovePosition { #[note(resolve_missing_macro_rules_name)] pub(crate) struct MaybeMissingMacroRulesName { #[primary_span] - pub(crate) span: Span, + pub(crate) spans: MultiSpan, } #[derive(Subdiagnostic)] diff --git a/tests/ui/macros/issue-118786.rs b/tests/ui/macros/issue-118786.rs index 97454c9de07..a41372e4ea8 100644 --- a/tests/ui/macros/issue-118786.rs +++ b/tests/ui/macros/issue-118786.rs @@ -7,6 +7,7 @@ macro_rules! make_macro { macro_rules! $macro_name { //~^ ERROR macro expansion ignores token `{` and any following //~| ERROR cannot find macro `macro_rules` in this scope + //~| put a macro name here () => {} } } diff --git a/tests/ui/macros/issue-118786.stderr b/tests/ui/macros/issue-118786.stderr index 03e65c94ba7..256b742ee16 100644 --- a/tests/ui/macros/issue-118786.stderr +++ b/tests/ui/macros/issue-118786.stderr @@ -1,5 +1,5 @@ error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/issue-118786.rs:15:13 + --> $DIR/issue-118786.rs:16:13 | LL | make_macro!((meow)); | ^^^^^^ @@ -34,10 +34,10 @@ LL | make_macro!((meow)); | ------------------- in this macro invocation | note: maybe you have forgotten to define a name for this `macro_rules!` - --> $DIR/issue-118786.rs:7:9 + --> $DIR/issue-118786.rs:7:20 | LL | macro_rules! $macro_name { - | ^^^^^^^^^^^ + | ^ put a macro name here ... LL | make_macro!((meow)); | ------------------- in this macro invocation diff --git a/tests/ui/resolve/issue-118295.rs b/tests/ui/resolve/issue-118295.rs index b97681d9563..37a49baee80 100644 --- a/tests/ui/resolve/issue-118295.rs +++ b/tests/ui/resolve/issue-118295.rs @@ -1,5 +1,11 @@ macro_rules! {} //~^ ERROR cannot find macro `macro_rules` in this scope //~| NOTE maybe you have forgotten to define a name for this `macro_rules!` +//~| put a macro name here + +macro_rules!{} +//~^ ERROR cannot find macro `macro_rules` in this scope +//~| NOTE maybe you have forgotten to define a name for this `macro_rules!` +//~| put a macro name here fn main() {} diff --git a/tests/ui/resolve/issue-118295.stderr b/tests/ui/resolve/issue-118295.stderr index d60d7d9185d..06a37e81d6c 100644 --- a/tests/ui/resolve/issue-118295.stderr +++ b/tests/ui/resolve/issue-118295.stderr @@ -1,3 +1,15 @@ +error: cannot find macro `macro_rules` in this scope + --> $DIR/issue-118295.rs:6:1 + | +LL | macro_rules!{} + | ^^^^^^^^^^^ + | +note: maybe you have forgotten to define a name for this `macro_rules!` + --> $DIR/issue-118295.rs:6:12 + | +LL | macro_rules!{} + | ^ put a macro name here + error: cannot find macro `macro_rules` in this scope --> $DIR/issue-118295.rs:1:1 | @@ -5,10 +17,10 @@ LL | macro_rules! {} | ^^^^^^^^^^^ | note: maybe you have forgotten to define a name for this `macro_rules!` - --> $DIR/issue-118295.rs:1:1 + --> $DIR/issue-118295.rs:1:12 | LL | macro_rules! {} - | ^^^^^^^^^^^ + | ^ put a macro name here -error: aborting due to 1 previous error +error: aborting due to 2 previous errors