about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-25 01:17:55 +0000
committerbors <bors@rust-lang.org>2024-05-25 01:17:55 +0000
commit21e6de7eb64c09102de3f100420a09edc1a2a8d7 (patch)
tree17960ea3626b2f0e8478be9b75a42541076f96aa
parent36153f1a4e3162f0a143c7b3e468ecb3beb0008e (diff)
parenta25bb5f4acee081295ab83a31e57b98d8d559df0 (diff)
downloadrust-21e6de7eb64c09102de3f100420a09edc1a2a8d7.tar.gz
rust-21e6de7eb64c09102de3f100420a09edc1a2a8d7.zip
Auto merge of #124187 - compiler-errors:self-ctor, r=petrochenkov
Warn (or error) when `Self` ctor from outer item is referenced in inner nested item

This implements a warning `SELF_CONSTRUCTOR_FROM_OUTER_ITEM` when a self constructor from an outer impl is referenced in an inner nested item. This is a proper fix mentioned https://github.com/rust-lang/rust/pull/117246#discussion_r1374648388.

This warning is additionally bumped to a hard error when the self type references generic parameters, since it's almost always going to ICE, and is basically *never* correct to do.

This also reverts part of https://github.com/rust-lang/rust/pull/117246, since I believe this is the proper fix and we shouldn't need the helper functions (`opt_param_at`/`opt_type_param`) any longer, since they shouldn't really ever be used in cases where we don't have this problem.
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs5
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl4
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs40
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs105
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs42
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs28
-rw-r--r--tests/ui/malformed/do-not-ice-on-note_and_explain.rs17
-rw-r--r--tests/ui/malformed/do-not-ice-on-note_and_explain.stderr85
-rw-r--r--tests/ui/self/self-ctor-nongeneric.rs4
-rw-r--r--tests/ui/self/self-ctor-nongeneric.stderr27
-rw-r--r--tests/ui/self/self-ctor.rs14
-rw-r--r--tests/ui/self/self-ctor.stderr21
13 files changed, 244 insertions, 176 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 50fe20346cf..8506b8d75f9 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 72b95a9603d..6f499947d5c 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 f250b909596..3f12f252654 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<Span>,
     },
 }
+
+#[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<ReplaceWithName>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(hir_typeck_self_ctor_from_outer_item)]
+pub struct SelfCtorFromOuterItemLint {
+    #[label]
+    pub impl_span: Span,
+    #[subdiagnostic]
+    pub sugg: Option<ReplaceWithName>,
+}
+
+#[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 77f90c0c131..074aca78933 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 f2fe43380b8..f4514c23508 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<Output = Expected>`.
@@ -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<T> Trait<T> 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<T> Trait<T> 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<T> Trait<T> 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 82f16b31a66..617fe99ef6a 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,
@@ -3150,6 +3151,47 @@ declare_lint! {
 }
 
 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 <https://github.com/rust-lang/rust/issues/124186>",
+    };
+}
+
+declare_lint! {
     /// The `semicolon_in_expressions_from_macros` lint detects trailing semicolons
     /// in macro bodies when the macro is invoked in expression position.
     /// This was previous accepted, but is being phased out.
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 870e4865aea..1c4462fc1dc 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 e65276fb738..be0b18a00d2 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>(B);
-impl<B>A<B>{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<B> A<B> {
+    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 41d0f17366b..11a8c01e490 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 | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
-   |                                     ^ consider adding a `main` function to `$DIR/do-not-ice-on-note_and_explain.rs`
+LL | impl<B> A<B> {
+   | ------------ 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 | impl<B>A<B>{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>(B);
-   |          ^ required by this bound in `A`
-
-error[E0308]: mismatched types
-  --> $DIR/do-not-ice-on-note_and_explain.rs:2:32
-   |
-LL | impl<B>A<B>{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>(B);
-   |        ^
-
-error[E0308]: mismatched types
-  --> $DIR/do-not-ice-on-note_and_explain.rs:2:27
-   |
-LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
-   |                           ^^^^^^^ expected `()`, found `A<B>`
-   |
-   = note: expected unit type `()`
-                 found struct `A<B>`
-help: consider using a semicolon here
-   |
-LL | impl<B>A<B>{fn d(){fn d(){Self(1);}}}
-   |                                  +
-help: try adding a return type
-   |
-LL | impl<B>A<B>{fn d(){fn d() -> A<B>{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 | impl<B>A<B>{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>(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<B>`
-  --> $DIR/do-not-ice-on-note_and_explain.rs:1:10
-   |
-LL | struct A<B>(B);
-   |          ^  - ...if indirection were used here: `Box<B>`
-   |          |
-   |          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 0594e87a0a4..c32cf9df694 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 00000000000..6c03c6f3e38
--- /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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 00000000000..d166499f884
--- /dev/null
+++ b/tests/ui/self/self-ctor.rs
@@ -0,0 +1,14 @@
+struct S0<T>(T);
+
+impl<T> S0<T> {
+    fn foo() {
+        const C: S0<i32> = Self(0);
+        //~^ ERROR can't reference `Self` constructor from outer item
+        fn bar() -> S0<i32> {
+            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 00000000000..0cb22baaa1a
--- /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<T> S0<T> {
+   | ------------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
+LL |     fn foo() {
+LL |         const C: S0<i32> = 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<T> S0<T> {
+   | ------------- 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`.