Skip to content

Commit 5ee4db4

Browse files
Warn/error on self ctor from outer item in inner item
1 parent 685a80f commit 5ee4db4

File tree

10 files changed

+199
-83
lines changed

10 files changed

+199
-83
lines changed

compiler/rustc_hir_typeck/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ hir_typeck_rpit_change_return_type = you could change the return type to be a bo
137137
hir_typeck_rustcall_incorrect_args =
138138
functions with the "rust-call" ABI must take a single non-self tuple argument
139139
140+
hir_typeck_self_ctor_from_outer_item = can't reference `Self` constructor from outer item
141+
.label = the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
142+
.suggestion = replace `Self` with the actual type
143+
140144
hir_typeck_struct_expr_non_exhaustive =
141145
cannot create non-exhaustive {$what} using struct expression
142146

compiler/rustc_hir_typeck/src/errors.rs

+28
Original file line numberDiff line numberDiff line change
@@ -651,3 +651,31 @@ pub enum SuggestBoxingForReturnImplTrait {
651651
ends: Vec<Span>,
652652
},
653653
}
654+
655+
#[derive(Diagnostic)]
656+
#[diag(hir_typeck_self_ctor_from_outer_item, code = E0401)]
657+
pub struct SelfCtorFromOuterItem {
658+
#[primary_span]
659+
pub span: Span,
660+
#[label]
661+
pub impl_span: Span,
662+
#[subdiagnostic]
663+
pub sugg: Option<ReplaceWithName>,
664+
}
665+
666+
#[derive(LintDiagnostic)]
667+
#[diag(hir_typeck_self_ctor_from_outer_item)]
668+
pub struct SelfCtorFromOuterItemLint {
669+
#[label]
670+
pub impl_span: Span,
671+
#[subdiagnostic]
672+
pub sugg: Option<ReplaceWithName>,
673+
}
674+
675+
#[derive(Subdiagnostic)]
676+
#[suggestion(hir_typeck_suggestion, code = "{name}", applicability = "machine-applicable")]
677+
pub struct ReplaceWithName {
678+
#[primary_span]
679+
pub span: Span,
680+
pub name: String,
681+
}

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+39-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::callee::{self, DeferredCallResolution};
2-
use crate::errors::CtorIsPrivate;
2+
use crate::errors::{self, CtorIsPrivate};
33
use crate::method::{self, MethodCallee, SelfSource};
44
use crate::rvalue_scopes;
55
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy};
@@ -21,6 +21,7 @@ use rustc_hir_analysis::hir_ty_lowering::{
2121
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
2222
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
2323
use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
24+
use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
2425
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
2526
use rustc_middle::ty::error::TypeError;
2627
use rustc_middle::ty::fold::TypeFoldable;
@@ -1162,6 +1163,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11621163
span,
11631164
tcx.at(span).type_of(impl_def_id).instantiate_identity(),
11641165
);
1166+
1167+
// Firstly, check that this SelfCtor even comes from the item we're currently
1168+
// typechecking. This can happen because we never validated the resolution of
1169+
// SelfCtors, and when we started doing so, we noticed regressions. After
1170+
// sufficiently long time, we can remove this check and turn it into a hard
1171+
// error in `validate_res_from_ribs` -- it's just difficult to tell whether the
1172+
// self type has any generic types during rustc_resolve, which is what we use
1173+
// to determine if this is a hard error or warning.
1174+
if std::iter::successors(Some(self.body_id.to_def_id()), |def_id| {
1175+
self.tcx.generics_of(def_id).parent
1176+
})
1177+
.all(|def_id| def_id != impl_def_id)
1178+
{
1179+
let sugg = ty.normalized.ty_adt_def().map(|def| errors::ReplaceWithName {
1180+
span: path_span,
1181+
name: self.tcx.item_name(def.did()).to_ident_string(),
1182+
});
1183+
if ty.raw.has_param() {
1184+
let guar = self.tcx.dcx().emit_err(errors::SelfCtorFromOuterItem {
1185+
span: path_span,
1186+
impl_span: tcx.def_span(impl_def_id),
1187+
sugg,
1188+
});
1189+
return (Ty::new_error(self.tcx, guar), res);
1190+
} else {
1191+
self.tcx.emit_node_span_lint(
1192+
SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
1193+
hir_id,
1194+
path_span,
1195+
errors::SelfCtorFromOuterItemLint {
1196+
impl_span: tcx.def_span(impl_def_id),
1197+
sugg,
1198+
},
1199+
);
1200+
}
1201+
}
1202+
11651203
match ty.normalized.ty_adt_def() {
11661204
Some(adt_def) if adt_def.has_ctor() => {
11671205
let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap();

compiler/rustc_lint_defs/src/builtin.rs

+42
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ declare_lint_pass! {
9090
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
9191
RUST_2021_PRELUDE_COLLISIONS,
9292
RUST_2024_INCOMPATIBLE_PAT,
93+
SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
9394
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
9495
SINGLE_USE_LIFETIMES,
9596
SOFT_UNSTABLE,
@@ -3149,6 +3150,47 @@ declare_lint! {
31493150
"detects `#[unstable]` on stable trait implementations for stable types"
31503151
}
31513152

3153+
declare_lint! {
3154+
/// The `self_constructor_from_outer_item` lint detects cases where the `Self` constructor
3155+
/// was silently allowed due to a bug in the resolver, and which may produce surprising
3156+
/// and unintended behavior.
3157+
///
3158+
/// Using a `Self` type alias from an outer item was never intended, but was silently allowed.
3159+
/// This is deprecated -- and is a hard error when the `Self` type alias references generics
3160+
/// that are not in scope.
3161+
///
3162+
/// ### Example
3163+
///
3164+
/// ```rust,compile_fail
3165+
/// #![deny(self_constructor_from_outer_item)]
3166+
///
3167+
/// struct S0(usize);
3168+
///
3169+
/// impl S0 {
3170+
/// fn foo() {
3171+
/// const C: S0 = Self(0);
3172+
/// fn bar() -> S0 {
3173+
/// Self(0)
3174+
/// }
3175+
/// }
3176+
/// }
3177+
/// ```
3178+
///
3179+
/// {{produces}}
3180+
///
3181+
/// ### Explanation
3182+
///
3183+
/// The `Self` type alias should not be reachable because nested items are not associated with
3184+
/// the scope of the parameters from the parent item.
3185+
pub SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
3186+
Warn,
3187+
"detect unsupported use of `Self` from outer item",
3188+
@future_incompatible = FutureIncompatibleInfo {
3189+
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
3190+
reference: "issue #124186 <https://github.com/rust-lang/rust/issues/124186>",
3191+
};
3192+
}
3193+
31523194
declare_lint! {
31533195
/// The `semicolon_in_expressions_from_macros` lint detects trailing semicolons
31543196
/// in macro bodies when the macro is invoked in expression position.
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
struct A<B>(B);
2-
impl<B>A<B>{fn d(){fn d(){Self(1)}}}
3-
//~^ ERROR the size for values of type `B` cannot be known at compilation time
4-
//~| ERROR the size for values of type `B` cannot be known at compilation time
5-
//~| ERROR mismatched types
6-
//~| ERROR mismatched types
7-
//~| ERROR `main` function not found in crate
2+
3+
impl<B> A<B> {
4+
fn d() {
5+
fn d() {
6+
Self(1)
7+
//~^ ERROR can't reference `Self` constructor from outer item
8+
}
9+
}
10+
}
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,12 @@
1-
error[E0601]: `main` function not found in crate `do_not_ice_on_note_and_explain`
2-
--> $DIR/do-not-ice-on-note_and_explain.rs:2:37
1+
error[E0401]: can't reference `Self` constructor from outer item
2+
--> $DIR/do-not-ice-on-note_and_explain.rs:6:13
33
|
4-
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
5-
| ^ consider adding a `main` function to `$DIR/do-not-ice-on-note_and_explain.rs`
4+
LL | impl<B> A<B> {
5+
| ------------ the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
6+
...
7+
LL | Self(1)
8+
| ^^^^ help: replace `Self` with the actual type: `A`
69

7-
error[E0277]: the size for values of type `B` cannot be known at compilation time
8-
--> $DIR/do-not-ice-on-note_and_explain.rs:2:32
9-
|
10-
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
11-
| - ---- ^ doesn't have a size known at compile-time
12-
| | |
13-
| | required by a bound introduced by this call
14-
| this type parameter needs to be `Sized`
15-
|
16-
note: required by a bound in `A`
17-
--> $DIR/do-not-ice-on-note_and_explain.rs:1:10
18-
|
19-
LL | struct A<B>(B);
20-
| ^ required by this bound in `A`
21-
22-
error[E0308]: mismatched types
23-
--> $DIR/do-not-ice-on-note_and_explain.rs:2:32
24-
|
25-
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
26-
| ---- ^ expected type parameter `B`, found integer
27-
| |
28-
| arguments to this function are incorrect
29-
|
30-
= note: expected type parameter `B`
31-
found type `{integer}`
32-
note: tuple struct defined here
33-
--> $DIR/do-not-ice-on-note_and_explain.rs:1:8
34-
|
35-
LL | struct A<B>(B);
36-
| ^
37-
38-
error[E0308]: mismatched types
39-
--> $DIR/do-not-ice-on-note_and_explain.rs:2:27
40-
|
41-
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
42-
| ^^^^^^^ expected `()`, found `A<B>`
43-
|
44-
= note: expected unit type `()`
45-
found struct `A<B>`
46-
help: consider using a semicolon here
47-
|
48-
LL | impl<B>A<B>{fn d(){fn d(){Self(1);}}}
49-
| +
50-
help: try adding a return type
51-
|
52-
LL | impl<B>A<B>{fn d(){fn d() -> A<B>{Self(1)}}}
53-
| +++++++
54-
55-
error[E0277]: the size for values of type `B` cannot be known at compilation time
56-
--> $DIR/do-not-ice-on-note_and_explain.rs:2:27
57-
|
58-
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
59-
| - ^^^^^^^ doesn't have a size known at compile-time
60-
| |
61-
| this type parameter needs to be `Sized`
62-
|
63-
note: required by an implicit `Sized` bound in `A`
64-
--> $DIR/do-not-ice-on-note_and_explain.rs:1:10
65-
|
66-
LL | struct A<B>(B);
67-
| ^ required by the implicit `Sized` requirement on this type parameter in `A`
68-
help: you could relax the implicit `Sized` bound on `B` if it were used through indirection like `&B` or `Box<B>`
69-
--> $DIR/do-not-ice-on-note_and_explain.rs:1:10
70-
|
71-
LL | struct A<B>(B);
72-
| ^ - ...if indirection were used here: `Box<B>`
73-
| |
74-
| this could be changed to `B: ?Sized`...
75-
76-
error: aborting due to 5 previous errors
10+
error: aborting due to 1 previous error
7711

78-
Some errors have detailed explanations: E0277, E0308, E0601.
79-
For more information about an error, try `rustc --explain E0277`.
12+
For more information about this error, try `rustc --explain E0401`.

tests/ui/self/self-ctor-nongeneric.rs

+4
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ struct S0(usize);
66
impl S0 {
77
fn foo() {
88
const C: S0 = Self(0);
9+
//~^ WARN can't reference `Self` constructor from outer item
10+
//~| WARN this was previously accepted by the compiler but is being phased out
911
fn bar() -> S0 {
1012
Self(0)
13+
//~^ WARN can't reference `Self` constructor from outer item
14+
//~| WARN this was previously accepted by the compiler but is being phased out
1115
}
1216
}
1317
}
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
warning: can't reference `Self` constructor from outer item
2+
--> $DIR/self-ctor-nongeneric.rs:8:23
3+
|
4+
LL | impl S0 {
5+
| ------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
6+
LL | fn foo() {
7+
LL | const C: S0 = Self(0);
8+
| ^^^^ help: replace `Self` with the actual type: `S0`
9+
|
10+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
11+
= note: for more information, see issue #124186 <https://github.com/rust-lang/rust/issues/124186>
12+
= note: `#[warn(self_constructor_from_outer_item)]` on by default
13+
14+
warning: can't reference `Self` constructor from outer item
15+
--> $DIR/self-ctor-nongeneric.rs:12:13
16+
|
17+
LL | impl S0 {
18+
| ------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
19+
...
20+
LL | Self(0)
21+
| ^^^^ help: replace `Self` with the actual type: `S0`
22+
|
23+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
24+
= note: for more information, see issue #124186 <https://github.com/rust-lang/rust/issues/124186>
25+
26+
warning: 2 warnings emitted
27+

tests/ui/self/self-ctor.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
struct S0<T>(T);
2+
3+
impl<T> S0<T> {
4+
fn foo() {
5+
const C: S0<i32> = Self(0);
6+
//~^ ERROR can't reference `Self` constructor from outer item
7+
fn bar() -> S0<i32> {
8+
Self(0)
9+
//~^ ERROR can't reference `Self` constructor from outer item
10+
}
11+
}
12+
}
13+
14+
fn main() {}

tests/ui/self/self-ctor.stderr

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0401]: can't reference `Self` constructor from outer item
2+
--> $DIR/self-ctor.rs:5:28
3+
|
4+
LL | impl<T> S0<T> {
5+
| ------------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
6+
LL | fn foo() {
7+
LL | const C: S0<i32> = Self(0);
8+
| ^^^^ help: replace `Self` with the actual type: `S0`
9+
10+
error[E0401]: can't reference `Self` constructor from outer item
11+
--> $DIR/self-ctor.rs:8:13
12+
|
13+
LL | impl<T> S0<T> {
14+
| ------------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
15+
...
16+
LL | Self(0)
17+
| ^^^^ help: replace `Self` with the actual type: `S0`
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0401`.

0 commit comments

Comments
 (0)