Skip to content

Commit 294f0e5

Browse files
Warn/error on self ctor from outer item in inner item
1 parent f9b1614 commit 294f0e5

10 files changed

+194
-83
lines changed

compiler/rustc_hir_typeck/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ hir_typeck_rpit_change_return_type = you could change the return type to be a bo
130130
hir_typeck_rustcall_incorrect_args =
131131
functions with the "rust-call" ABI must take a single non-self tuple argument
132132
133+
hir_typeck_self_ctor_from_outer_item = can't reference `Self` constructor from outer item
134+
.label = the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
135+
.suggestion = replace `Self` with the actual type
136+
133137
hir_typeck_struct_expr_non_exhaustive =
134138
cannot create non-exhaustive {$what} using struct expression
135139

compiler/rustc_hir_typeck/src/errors.rs

+28
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,34 @@ pub enum SuggestBoxingForReturnImplTrait {
633633
},
634634
}
635635

636+
#[derive(Diagnostic)]
637+
#[diag(hir_typeck_self_ctor_from_outer_item, code = E0401)]
638+
pub struct SelfCtorFromOuterItem {
639+
#[primary_span]
640+
pub span: Span,
641+
#[label]
642+
pub impl_span: Span,
643+
#[subdiagnostic]
644+
pub sugg: Option<ReplaceWithName>,
645+
}
646+
647+
#[derive(LintDiagnostic)]
648+
#[diag(hir_typeck_self_ctor_from_outer_item)]
649+
pub struct SelfCtorFromOuterItemLint {
650+
#[label]
651+
pub impl_span: Span,
652+
#[subdiagnostic]
653+
pub sugg: Option<ReplaceWithName>,
654+
}
655+
656+
#[derive(Subdiagnostic)]
657+
#[suggestion(hir_typeck_suggestion, code = "{name}", applicability = "machine-applicable")]
658+
pub struct ReplaceWithName {
659+
#[primary_span]
660+
pub span: Span,
661+
pub name: String,
662+
}
663+
636664
#[derive(LintDiagnostic)]
637665
#[diag(hir_typeck_dereferencing_mut_binding)]
638666
pub struct DereferencingMutBinding {

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};
@@ -22,6 +22,7 @@ use rustc_hir_analysis::hir_ty_lowering::{
2222
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
2323
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
2424
use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
25+
use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
2526
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
2627
use rustc_middle::ty::error::TypeError;
2728
use rustc_middle::ty::fold::TypeFoldable;
@@ -1218,6 +1219,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12181219
span,
12191220
tcx.at(span).type_of(impl_def_id).instantiate_identity(),
12201221
);
1222+
1223+
// Firstly, check that this SelfCtor even comes from the item we're currently
1224+
// typechecking. This can happen because we never validated the resolution of
1225+
// SelfCtors, and when we started doing so, we noticed regressions. After
1226+
// sufficiently long time, we can remove this check and turn it into a hard
1227+
// error in `validate_res_from_ribs` -- it's just difficult to tell whether the
1228+
// self type has any generic types during rustc_resolve, which is what we use
1229+
// to determine if this is a hard error or warning.
1230+
if std::iter::successors(Some(self.body_id.to_def_id()), |def_id| {
1231+
self.tcx.generics_of(def_id).parent
1232+
})
1233+
.all(|def_id| def_id != impl_def_id)
1234+
{
1235+
let sugg = ty.normalized.ty_adt_def().map(|def| errors::ReplaceWithName {
1236+
span: path_span,
1237+
name: self.tcx.item_name(def.did()).to_ident_string(),
1238+
});
1239+
if ty.raw.has_param() {
1240+
let guar = self.tcx.dcx().emit_err(errors::SelfCtorFromOuterItem {
1241+
span: path_span,
1242+
impl_span: tcx.def_span(impl_def_id),
1243+
sugg,
1244+
});
1245+
return (Ty::new_error(self.tcx, guar), res);
1246+
} else {
1247+
self.tcx.emit_node_span_lint(
1248+
SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
1249+
hir_id,
1250+
path_span,
1251+
errors::SelfCtorFromOuterItemLint {
1252+
impl_span: tcx.def_span(impl_def_id),
1253+
sugg,
1254+
},
1255+
);
1256+
}
1257+
}
1258+
12211259
match ty.normalized.ty_adt_def() {
12221260
Some(adt_def) if adt_def.has_ctor() => {
12231261
let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap();

compiler/rustc_lint_defs/src/builtin.rs

+37
Original file line numberDiff line numberDiff line change
@@ -3148,6 +3148,43 @@ declare_lint! {
31483148
"detects `#[unstable]` on stable trait implementations for stable types"
31493149
}
31503150

3151+
declare_lint! {
3152+
/// Using a `Self` type alias from an outer item was never intended, but was silently allowed.
3153+
/// This is deprecated -- and is a hard error when the `Self` type alias references generics
3154+
/// that are not in scope.
3155+
///
3156+
/// ### Example
3157+
///
3158+
/// ```rust,compile_fail
3159+
/// #![deny(SELF_CONSTRUCTOR_FROM_OUTER_ITEM)]
3160+
///
3161+
/// struct S0(usize);
3162+
///
3163+
/// impl S0 {
3164+
/// fn foo() {
3165+
/// const C: S0 = Self(0);
3166+
/// fn bar() -> S0 {
3167+
/// Self(0)
3168+
/// }
3169+
/// }
3170+
/// }
3171+
/// ```
3172+
///
3173+
/// {{produces}}
3174+
///
3175+
/// ### Explanation
3176+
///
3177+
/// The `Self` type alias should not be reachable because nested items are not associated with
3178+
/// the scope of the parameters from the parent item.
3179+
pub SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
3180+
Warn,
3181+
"detect unsupported use of `Self` from outer item",
3182+
@future_incompatible = FutureIncompatibleInfo {
3183+
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
3184+
reference: "issue #124186 <https://github.com/rust-lang/rust/issues/124186>",
3185+
};
3186+
}
3187+
31513188
declare_lint! {
31523189
/// The `semicolon_in_expressions_from_macros` lint detects trailing semicolons
31533190
/// 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)