diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 50fe20346cf45..8506b8d75f957 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -164,9 +164,8 @@ pub fn check_intrinsic_type( ) { let generics = tcx.generics_of(intrinsic_id); let param = |n| { - if let Some(&ty::GenericParamDef { - name, kind: ty::GenericParamDefKind::Type { .. }, .. - }) = generics.opt_param_at(n as usize, tcx) + if let &ty::GenericParamDef { name, kind: ty::GenericParamDefKind::Type { .. }, .. } = + generics.param_at(n as usize, tcx) { Ty::new_param(tcx, n, name) } else { diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 72b95a9603dd0..6f499947d5cd4 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -137,6 +137,10 @@ hir_typeck_rpit_change_return_type = you could change the return type to be a bo hir_typeck_rustcall_incorrect_args = functions with the "rust-call" ABI must take a single non-self tuple argument +hir_typeck_self_ctor_from_outer_item = can't reference `Self` constructor from outer item + .label = the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference + .suggestion = replace `Self` with the actual type + hir_typeck_struct_expr_non_exhaustive = cannot create non-exhaustive {$what} using struct expression diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index f250b909596ea..3f12f25265454 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -651,3 +651,31 @@ pub enum SuggestBoxingForReturnImplTrait { ends: Vec, }, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_self_ctor_from_outer_item, code = E0401)] +pub struct SelfCtorFromOuterItem { + #[primary_span] + pub span: Span, + #[label] + pub impl_span: Span, + #[subdiagnostic] + pub sugg: Option, +} + +#[derive(LintDiagnostic)] +#[diag(hir_typeck_self_ctor_from_outer_item)] +pub struct SelfCtorFromOuterItemLint { + #[label] + pub impl_span: Span, + #[subdiagnostic] + pub sugg: Option, +} + +#[derive(Subdiagnostic)] +#[suggestion(hir_typeck_suggestion, code = "{name}", applicability = "machine-applicable")] +pub struct ReplaceWithName { + #[primary_span] + pub span: Span, + pub name: String, +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 77f90c0c1310c..074aca78933bc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,5 +1,5 @@ use crate::callee::{self, DeferredCallResolution}; -use crate::errors::CtorIsPrivate; +use crate::errors::{self, CtorIsPrivate}; use crate::method::{self, MethodCallee, SelfSource}; use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy}; @@ -21,6 +21,7 @@ use rustc_hir_analysis::hir_ty_lowering::{ use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; +use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::TypeFoldable; @@ -1156,6 +1157,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, tcx.at(span).type_of(impl_def_id).instantiate_identity(), ); + + // Firstly, check that this SelfCtor even comes from the item we're currently + // typechecking. This can happen because we never validated the resolution of + // SelfCtors, and when we started doing so, we noticed regressions. After + // sufficiently long time, we can remove this check and turn it into a hard + // error in `validate_res_from_ribs` -- it's just difficult to tell whether the + // self type has any generic types during rustc_resolve, which is what we use + // to determine if this is a hard error or warning. + if std::iter::successors(Some(self.body_id.to_def_id()), |def_id| { + self.tcx.generics_of(def_id).parent + }) + .all(|def_id| def_id != impl_def_id) + { + let sugg = ty.normalized.ty_adt_def().map(|def| errors::ReplaceWithName { + span: path_span, + name: self.tcx.item_name(def.did()).to_ident_string(), + }); + if ty.raw.has_param() { + let guar = self.tcx.dcx().emit_err(errors::SelfCtorFromOuterItem { + span: path_span, + impl_span: tcx.def_span(impl_def_id), + sugg, + }); + return (Ty::new_error(self.tcx, guar), res); + } else { + self.tcx.emit_node_span_lint( + SELF_CONSTRUCTOR_FROM_OUTER_ITEM, + hir_id, + path_span, + errors::SelfCtorFromOuterItemLint { + impl_span: tcx.def_span(impl_def_id), + sugg, + }, + ); + } + } + match ty.normalized.ty_adt_def() { Some(adt_def) if adt_def.has_ctor() => { let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index f2fe43380b80e..f4514c2350847 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -54,17 +54,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } (ty::Param(expected), ty::Param(found)) => { let generics = tcx.generics_of(body_owner_def_id); - if let Some(param) = generics.opt_type_param(expected, tcx) { - let e_span = tcx.def_span(param.def_id); - if !sp.contains(e_span) { - diag.span_label(e_span, "expected type parameter"); - } + let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id); + if !sp.contains(e_span) { + diag.span_label(e_span, "expected type parameter"); } - if let Some(param) = generics.opt_type_param(found, tcx) { - let f_span = tcx.def_span(param.def_id); - if !sp.contains(f_span) { - diag.span_label(f_span, "found type parameter"); - } + let f_span = tcx.def_span(generics.type_param(found, tcx).def_id); + if !sp.contains(f_span) { + diag.span_label(f_span, "found type parameter"); } diag.note( "a type parameter was expected, but a different one was found; \ @@ -87,29 +83,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { | (ty::Alias(ty::Projection, proj), ty::Param(p)) if !tcx.is_impl_trait_in_trait(proj.def_id) => { - let parent = tcx - .generics_of(body_owner_def_id) - .opt_type_param(p, tcx) - .and_then(|param| { - let p_def_id = param.def_id; - let p_span = tcx.def_span(p_def_id); - let expected = match (values.expected.kind(), values.found.kind()) { - (ty::Param(_), _) => "expected ", - (_, ty::Param(_)) => "found ", - _ => "", - }; - if !sp.contains(p_span) { - diag.span_label( - p_span, - format!("{expected}this type parameter"), - ); - } - p_def_id.as_local().and_then(|id| { - let local_id = tcx.local_def_id_to_hir_id(id); - let generics = tcx.parent_hir_node(local_id).generics()?; - Some((id, generics)) - }) - }); + let param = tcx.generics_of(body_owner_def_id).type_param(p, tcx); + let p_def_id = param.def_id; + let p_span = tcx.def_span(p_def_id); + let expected = match (values.expected.kind(), values.found.kind()) { + (ty::Param(_), _) => "expected ", + (_, ty::Param(_)) => "found ", + _ => "", + }; + if !sp.contains(p_span) { + diag.span_label(p_span, format!("{expected}this type parameter")); + } + let parent = p_def_id.as_local().and_then(|id| { + let local_id = tcx.local_def_id_to_hir_id(id); + let generics = tcx.parent_hir_node(local_id).generics()?; + Some((id, generics)) + }); let mut note = true; if let Some((local_id, generics)) = parent { // Synthesize the associated type restriction `Add`. @@ -183,16 +172,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..)) | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => { let generics = tcx.generics_of(body_owner_def_id); - if let Some(param) = generics.opt_type_param(p, tcx) { - let p_span = tcx.def_span(param.def_id); - let expected = match (values.expected.kind(), values.found.kind()) { - (ty::Param(_), _) => "expected ", - (_, ty::Param(_)) => "found ", - _ => "", - }; - if !sp.contains(p_span) { - diag.span_label(p_span, format!("{expected}this type parameter")); - } + let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); + let expected = match (values.expected.kind(), values.found.kind()) { + (ty::Param(_), _) => "expected ", + (_, ty::Param(_)) => "found ", + _ => "", + }; + if !sp.contains(p_span) { + diag.span_label(p_span, format!("{expected}this type parameter")); } diag.help("type parameters must be constrained to match other types"); if tcx.sess.teach(diag.code.unwrap()) { @@ -233,11 +220,9 @@ impl Trait for X { ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..), ) => { let generics = tcx.generics_of(body_owner_def_id); - if let Some(param) = generics.opt_type_param(p, tcx) { - let p_span = tcx.def_span(param.def_id); - if !sp.contains(p_span) { - diag.span_label(p_span, "expected this type parameter"); - } + let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); + if !sp.contains(p_span) { + diag.span_label(p_span, "expected this type parameter"); } diag.help(format!( "every closure has a distinct type and so could not always match the \ @@ -246,16 +231,14 @@ impl Trait for X { } (ty::Param(p), _) | (_, ty::Param(p)) => { let generics = tcx.generics_of(body_owner_def_id); - if let Some(param) = generics.opt_type_param(p, tcx) { - let p_span = tcx.def_span(param.def_id); - let expected = match (values.expected.kind(), values.found.kind()) { - (ty::Param(_), _) => "expected ", - (_, ty::Param(_)) => "found ", - _ => "", - }; - if !sp.contains(p_span) { - diag.span_label(p_span, format!("{expected}this type parameter")); - } + let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); + let expected = match (values.expected.kind(), values.found.kind()) { + (ty::Param(_), _) => "expected ", + (_, ty::Param(_)) => "found ", + _ => "", + }; + if !sp.contains(p_span) { + diag.span_label(p_span, format!("{expected}this type parameter")); } } (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) @@ -545,10 +528,8 @@ impl Trait for X { return false; }; let generics = tcx.generics_of(body_owner_def_id); - let Some(param) = generics.opt_type_param(param_ty, tcx) else { - return false; - }; - let Some(def_id) = param.def_id.as_local() else { + let def_id = generics.type_param(param_ty, tcx).def_id; + let Some(def_id) = def_id.as_local() else { return false; }; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 82f16b31a6673..617fe99ef6a75 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -90,6 +90,7 @@ declare_lint_pass! { RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2021_PRELUDE_COLLISIONS, RUST_2024_INCOMPATIBLE_PAT, + SELF_CONSTRUCTOR_FROM_OUTER_ITEM, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, SINGLE_USE_LIFETIMES, SOFT_UNSTABLE, @@ -3149,6 +3150,47 @@ declare_lint! { "detects `#[unstable]` on stable trait implementations for stable types" } +declare_lint! { + /// The `self_constructor_from_outer_item` lint detects cases where the `Self` constructor + /// was silently allowed due to a bug in the resolver, and which may produce surprising + /// and unintended behavior. + /// + /// Using a `Self` type alias from an outer item was never intended, but was silently allowed. + /// This is deprecated -- and is a hard error when the `Self` type alias references generics + /// that are not in scope. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(self_constructor_from_outer_item)] + /// + /// struct S0(usize); + /// + /// impl S0 { + /// fn foo() { + /// const C: S0 = Self(0); + /// fn bar() -> S0 { + /// Self(0) + /// } + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `Self` type alias should not be reachable because nested items are not associated with + /// the scope of the parameters from the parent item. + pub SELF_CONSTRUCTOR_FROM_OUTER_ITEM, + Warn, + "detect unsupported use of `Self` from outer item", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reference: "issue #124186 ", + }; +} + declare_lint! { /// The `semicolon_in_expressions_from_macros` lint detects trailing semicolons /// in macro bodies when the macro is invoked in expression position. diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 870e4865aeab1..1c4462fc1dcb3 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -245,20 +245,6 @@ impl<'tcx> Generics { } } - /// Returns the `GenericParamDef` with the given index if available. - pub fn opt_param_at( - &'tcx self, - param_index: usize, - tcx: TyCtxt<'tcx>, - ) -> Option<&'tcx GenericParamDef> { - if let Some(index) = param_index.checked_sub(self.parent_count) { - self.own_params.get(index) - } else { - tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?")) - .opt_param_at(param_index, tcx) - } - } - pub fn params_to(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx [GenericParamDef] { if let Some(index) = param_index.checked_sub(self.parent_count) { &self.own_params[..index] @@ -290,20 +276,6 @@ impl<'tcx> Generics { } } - /// Returns the `GenericParamDef` associated with this `ParamTy` if it belongs to this - /// `Generics`. - pub fn opt_type_param( - &'tcx self, - param: ParamTy, - tcx: TyCtxt<'tcx>, - ) -> Option<&'tcx GenericParamDef> { - let param = self.opt_param_at(param.index as usize, tcx)?; - match param.kind { - GenericParamDefKind::Type { .. } => Some(param), - _ => None, - } - } - /// Returns the `GenericParamDef` associated with this `ParamConst`. pub fn const_param(&'tcx self, param: ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef { let param = self.param_at(param.index as usize, tcx); diff --git a/tests/ui/malformed/do-not-ice-on-note_and_explain.rs b/tests/ui/malformed/do-not-ice-on-note_and_explain.rs index e65276fb738dd..be0b18a00d28f 100644 --- a/tests/ui/malformed/do-not-ice-on-note_and_explain.rs +++ b/tests/ui/malformed/do-not-ice-on-note_and_explain.rs @@ -1,7 +1,12 @@ struct A(B); -implA{fn d(){fn d(){Self(1)}}} -//~^ ERROR the size for values of type `B` cannot be known at compilation time -//~| ERROR the size for values of type `B` cannot be known at compilation time -//~| ERROR mismatched types -//~| ERROR mismatched types -//~| ERROR `main` function not found in crate + +impl A { + fn d() { + fn d() { + Self(1) + //~^ ERROR can't reference `Self` constructor from outer item + } + } +} + +fn main() {} diff --git a/tests/ui/malformed/do-not-ice-on-note_and_explain.stderr b/tests/ui/malformed/do-not-ice-on-note_and_explain.stderr index 41d0f17366b1e..11a8c01e49094 100644 --- a/tests/ui/malformed/do-not-ice-on-note_and_explain.stderr +++ b/tests/ui/malformed/do-not-ice-on-note_and_explain.stderr @@ -1,79 +1,12 @@ -error[E0601]: `main` function not found in crate `do_not_ice_on_note_and_explain` - --> $DIR/do-not-ice-on-note_and_explain.rs:2:37 +error[E0401]: can't reference `Self` constructor from outer item + --> $DIR/do-not-ice-on-note_and_explain.rs:6:13 | -LL | implA{fn d(){fn d(){Self(1)}}} - | ^ consider adding a `main` function to `$DIR/do-not-ice-on-note_and_explain.rs` +LL | impl A { + | ------------ the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference +... +LL | Self(1) + | ^^^^ help: replace `Self` with the actual type: `A` -error[E0277]: the size for values of type `B` cannot be known at compilation time - --> $DIR/do-not-ice-on-note_and_explain.rs:2:32 - | -LL | implA{fn d(){fn d(){Self(1)}}} - | - ---- ^ doesn't have a size known at compile-time - | | | - | | required by a bound introduced by this call - | this type parameter needs to be `Sized` - | -note: required by a bound in `A` - --> $DIR/do-not-ice-on-note_and_explain.rs:1:10 - | -LL | struct A(B); - | ^ required by this bound in `A` - -error[E0308]: mismatched types - --> $DIR/do-not-ice-on-note_and_explain.rs:2:32 - | -LL | implA{fn d(){fn d(){Self(1)}}} - | ---- ^ expected type parameter `B`, found integer - | | - | arguments to this function are incorrect - | - = note: expected type parameter `B` - found type `{integer}` -note: tuple struct defined here - --> $DIR/do-not-ice-on-note_and_explain.rs:1:8 - | -LL | struct A(B); - | ^ - -error[E0308]: mismatched types - --> $DIR/do-not-ice-on-note_and_explain.rs:2:27 - | -LL | implA{fn d(){fn d(){Self(1)}}} - | ^^^^^^^ expected `()`, found `A` - | - = note: expected unit type `()` - found struct `A` -help: consider using a semicolon here - | -LL | implA{fn d(){fn d(){Self(1);}}} - | + -help: try adding a return type - | -LL | implA{fn d(){fn d() -> A{Self(1)}}} - | +++++++ - -error[E0277]: the size for values of type `B` cannot be known at compilation time - --> $DIR/do-not-ice-on-note_and_explain.rs:2:27 - | -LL | implA{fn d(){fn d(){Self(1)}}} - | - ^^^^^^^ doesn't have a size known at compile-time - | | - | this type parameter needs to be `Sized` - | -note: required by an implicit `Sized` bound in `A` - --> $DIR/do-not-ice-on-note_and_explain.rs:1:10 - | -LL | struct A(B); - | ^ required by the implicit `Sized` requirement on this type parameter in `A` -help: you could relax the implicit `Sized` bound on `B` if it were used through indirection like `&B` or `Box` - --> $DIR/do-not-ice-on-note_and_explain.rs:1:10 - | -LL | struct A(B); - | ^ - ...if indirection were used here: `Box` - | | - | this could be changed to `B: ?Sized`... - -error: aborting due to 5 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0277, E0308, E0601. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0401`. diff --git a/tests/ui/self/self-ctor-nongeneric.rs b/tests/ui/self/self-ctor-nongeneric.rs index 0594e87a0a464..c32cf9df6946e 100644 --- a/tests/ui/self/self-ctor-nongeneric.rs +++ b/tests/ui/self/self-ctor-nongeneric.rs @@ -6,8 +6,12 @@ struct S0(usize); impl S0 { fn foo() { const C: S0 = Self(0); + //~^ WARN can't reference `Self` constructor from outer item + //~| WARN this was previously accepted by the compiler but is being phased out fn bar() -> S0 { Self(0) + //~^ WARN can't reference `Self` constructor from outer item + //~| WARN this was previously accepted by the compiler but is being phased out } } } diff --git a/tests/ui/self/self-ctor-nongeneric.stderr b/tests/ui/self/self-ctor-nongeneric.stderr new file mode 100644 index 0000000000000..6c03c6f3e38a4 --- /dev/null +++ b/tests/ui/self/self-ctor-nongeneric.stderr @@ -0,0 +1,27 @@ +warning: can't reference `Self` constructor from outer item + --> $DIR/self-ctor-nongeneric.rs:8:23 + | +LL | impl S0 { + | ------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference +LL | fn foo() { +LL | const C: S0 = Self(0); + | ^^^^ help: replace `Self` with the actual type: `S0` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124186 + = note: `#[warn(self_constructor_from_outer_item)]` on by default + +warning: can't reference `Self` constructor from outer item + --> $DIR/self-ctor-nongeneric.rs:12:13 + | +LL | impl S0 { + | ------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference +... +LL | Self(0) + | ^^^^ help: replace `Self` with the actual type: `S0` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124186 + +warning: 2 warnings emitted + diff --git a/tests/ui/self/self-ctor.rs b/tests/ui/self/self-ctor.rs new file mode 100644 index 0000000000000..d166499f88412 --- /dev/null +++ b/tests/ui/self/self-ctor.rs @@ -0,0 +1,14 @@ +struct S0(T); + +impl S0 { + fn foo() { + const C: S0 = Self(0); + //~^ ERROR can't reference `Self` constructor from outer item + fn bar() -> S0 { + Self(0) + //~^ ERROR can't reference `Self` constructor from outer item + } + } +} + +fn main() {} diff --git a/tests/ui/self/self-ctor.stderr b/tests/ui/self/self-ctor.stderr new file mode 100644 index 0000000000000..0cb22baaa1a05 --- /dev/null +++ b/tests/ui/self/self-ctor.stderr @@ -0,0 +1,21 @@ +error[E0401]: can't reference `Self` constructor from outer item + --> $DIR/self-ctor.rs:5:28 + | +LL | impl S0 { + | ------------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference +LL | fn foo() { +LL | const C: S0 = Self(0); + | ^^^^ help: replace `Self` with the actual type: `S0` + +error[E0401]: can't reference `Self` constructor from outer item + --> $DIR/self-ctor.rs:8:13 + | +LL | impl S0 { + | ------------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference +... +LL | Self(0) + | ^^^^ help: replace `Self` with the actual type: `S0` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0401`.