Skip to content

Commit 8095dd6

Browse files
committed
Also check the inner ty of arrays, slices, and tuples
1 parent d81f8d3 commit 8095dd6

File tree

9 files changed

+184
-87
lines changed

9 files changed

+184
-87
lines changed

compiler/rustc_hir_analysis/messages.ftl

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ hir_analysis_const_impl_for_non_const_trait =
7878
.note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
7979
.adding = adding a non-const method body in the future would be a breaking change
8080
81-
hir_analysis_const_param_ty_impl_on_infringing_referee =
81+
hir_analysis_const_param_ty_impl_on_infringing_inner_ty =
8282
the trait `ConstParamTy` cannot be implemented for this type
83-
.label = the trait `ConstParamTy` is not implemented for this {$def_descr}
83+
.label = this {$def_descr} does not implement `ConstParamTy`
8484
.suggestion = consider annotating this {$def_descr} with `#[derive(ConstParamTy)]`
8585
8686
hir_analysis_const_param_ty_impl_on_non_adt =

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
988988
ty_is_local(ty)
989989
}
990990
// Same as above.
991-
Err(ConstParamTyImplementationError::InfringingReferee(def_id)) => {
991+
Err(ConstParamTyImplementationError::InfringingInnerTy(def_id)) => {
992992
def_id.is_local()
993993
}
994994
// Implments `ConstParamTy`, suggest adding the feature to enable.

compiler/rustc_hir_analysis/src/coherence/builtin.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,9 @@ fn visit_implementation_of_const_param_ty(
135135
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
136136
Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
137137
}
138-
Err(ConstParamTyImplementationError::InfringingReferee(def_id)) => {
138+
Err(ConstParamTyImplementationError::InfringingInnerTy(def_id)) => {
139139
let def_span = tcx.def_span(def_id);
140-
tcx.dcx().emit_err(errors::ConstParamTyImplOnInfringingReferee {
140+
tcx.dcx().emit_err(errors::ConstParamTyImplOnInfringingInnerTy {
141141
span,
142142
def_span,
143143
def_descr: tcx.def_descr(def_id),

compiler/rustc_hir_analysis/src/errors.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,8 @@ pub struct ConstParamTyImplOnNonAdt {
228228
}
229229

230230
#[derive(Diagnostic)]
231-
#[diag(hir_analysis_const_param_ty_impl_on_infringing_referee)]
232-
pub struct ConstParamTyImplOnInfringingReferee {
231+
#[diag(hir_analysis_const_param_ty_impl_on_infringing_inner_ty)]
232+
pub struct ConstParamTyImplOnInfringingInnerTy {
233233
#[primary_span]
234234
pub span: Span,
235235
#[label]

compiler/rustc_trait_selection/src/traits/misc.rs

+33-27
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub enum CopyImplementationError<'tcx> {
2323

2424
pub enum ConstParamTyImplementationError<'tcx> {
2525
InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
26-
InfringingReferee(DefId),
26+
InfringingInnerTy(DefId),
2727
NotAnAdtOrBuiltinAllowed,
2828
}
2929

@@ -93,22 +93,21 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
9393
self_type: Ty<'tcx>,
9494
parent_cause: ObligationCause<'tcx>,
9595
) -> Result<(), ConstParamTyImplementationError<'tcx>> {
96-
let (adt, args) = match self_type.kind() {
97-
// Special case for impls like `impl ConstParamTy for &Foo`, where
98-
// Foo doesn't `impl ConstParamTy`. These kinds of impls aren't caught
99-
// by coherence checking since `core`'s impl is restricted to &T where
100-
// T: ConstParamTy.
101-
// `has_concrete_skeleton()` avoids reporting `core`'s blanket impl.
102-
&ty::Ref(.., ty, hir::Mutability::Not) if ty.peel_refs().has_concrete_skeleton() => {
103-
let ty = ty.peel_refs();
104-
type_allowed_to_implement_const_param_ty(tcx, param_env, ty, parent_cause)?;
105-
// Check the ty behind the ref impls `ConstParamTy` itself. This additional
106-
// logic is needed when checking refs because we need to check not only if
107-
// all fields implement ConstParamTy, but also that the type itself implements
108-
// ConstParamTy. Simply recursing into the ref only checks the former.
109-
if !ty.references_error()
110-
&& let &ty::Adt(adt, _) = ty.kind()
111-
{
96+
// Special case for impls like `impl ConstParamTy for &Foo`, where
97+
// Foo doesn't `impl ConstParamTy`. These kinds of impls aren't caught
98+
// by coherence checking since `core`'s impl is restricted to T: ConstParamTy.
99+
// `has_concrete_skeleton()` avoids reporting `core`'s blanket impl.
100+
let check_inner_ty = |ty: Ty<'tcx>, cause| {
101+
let ty = ty.peel_refs();
102+
if ty.has_concrete_skeleton() {
103+
type_allowed_to_implement_const_param_ty(tcx, param_env, ty, cause)?;
104+
// Check the inner tys in refs, tuples, arrays, or slices implement `ConstParamTy`.
105+
// This additional logic is needed because we need to check not only if all fields
106+
// of the type implement ConstParamTy, but also that the type itself implements
107+
// ConstParamTy. Simply recursing into the inner type only checks the former.
108+
// `type_allowed_to_implement_const_param_ty` takes care of other non-ADT types
109+
// for us.
110+
if let &ty::Adt(adt, _) = ty.kind() {
112111
let adt_did = adt.did();
113112
let adt_span = tcx.def_span(adt_did);
114113
let trait_did = tcx.require_lang_item(hir::LangItem::ConstParamTy, Some(adt_span));
@@ -130,23 +129,30 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
130129
);
131130
let errs = ocx.select_all_or_error();
132131
if !errs.is_empty() {
133-
return Err(ConstParamTyImplementationError::InfringingReferee(adt_did));
132+
return Err(ConstParamTyImplementationError::InfringingInnerTy(adt_did));
134133
}
135134
}
135+
}
136136

137+
Ok(())
138+
};
139+
140+
let (adt, args) = match self_type.kind() {
141+
// `core` provides these impls, but only where the inner type is `ConstParamTy`,
142+
// so we need to check and deny impls where the inner type is not `ConstParamTy`
143+
&ty::Ref(.., ty, hir::Mutability::Not) | &ty::Array(ty, ..) | &ty::Slice(ty) => {
144+
return check_inner_ty(ty, parent_cause);
145+
}
146+
147+
&ty::Tuple(tys) => {
148+
for ty in tys {
149+
check_inner_ty(ty, parent_cause.clone())?;
150+
}
137151
return Ok(());
138152
}
139153

140154
// `core` provides these impls.
141-
ty::Uint(_)
142-
| ty::Int(_)
143-
| ty::Bool
144-
| ty::Char
145-
| ty::Str
146-
| ty::Array(..)
147-
| ty::Slice(_)
148-
| ty::Ref(.., hir::Mutability::Not)
149-
| ty::Tuple(_) => return Ok(()),
155+
ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char | ty::Str => return Ok(()),
150156

151157
&ty::Adt(adt, args) => (adt, args),
152158

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#![feature(adt_const_params)]
2+
#![allow(incomplete_features)]
3+
4+
use std::marker::ConstParamTy;
5+
6+
// #112124
7+
8+
struct Foo;
9+
10+
impl ConstParamTy for &Foo {}
11+
//~^ ERROR the trait `ConstParamTy` cannot be implemented for this type
12+
13+
impl ConstParamTy for &[Foo] {}
14+
//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
15+
//~| ERROR the trait `ConstParamTy` cannot be implemented for this type
16+
17+
impl ConstParamTy for [Foo; 4] {}
18+
//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
19+
//~| ERROR the trait `ConstParamTy` cannot be implemented for this type
20+
21+
impl ConstParamTy for (Foo, i32, *const u8) {}
22+
//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
23+
//~| ERROR the trait `ConstParamTy` cannot be implemented for this type
24+
25+
// #119299 (ICE)
26+
27+
#[derive(Eq, PartialEq)]
28+
struct Wrapper(*const i32, usize);
29+
30+
impl ConstParamTy for &Wrapper {}
31+
//~^ ERROR the trait `ConstParamTy` cannot be implemented for this type
32+
33+
const fn foo<const S: &'static Wrapper>() {}
34+
35+
fn main() {
36+
const FOO: Wrapper = Wrapper(&42 as *const i32, 42);
37+
foo::<{ &FOO }>();
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
2+
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:13:1
3+
|
4+
LL | impl ConstParamTy for &[Foo] {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^------
6+
| | |
7+
| | this is not defined in the current crate because slices are always foreign
8+
| impl doesn't use only types from inside the current crate
9+
|
10+
= note: define and implement a trait or new type instead
11+
12+
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
13+
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:17:1
14+
|
15+
LL | impl ConstParamTy for [Foo; 4] {}
16+
| ^^^^^^^^^^^^^^^^^^^^^^--------
17+
| | |
18+
| | this is not defined in the current crate because arrays are always foreign
19+
| impl doesn't use only types from inside the current crate
20+
|
21+
= note: define and implement a trait or new type instead
22+
23+
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
24+
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:21:1
25+
|
26+
LL | impl ConstParamTy for (Foo, i32, *const u8) {}
27+
| ^^^^^^^^^^^^^^^^^^^^^^---------------------
28+
| | |
29+
| | this is not defined in the current crate because tuples are always foreign
30+
| impl doesn't use only types from inside the current crate
31+
|
32+
= note: define and implement a trait or new type instead
33+
34+
error: the trait `ConstParamTy` cannot be implemented for this type
35+
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:10:23
36+
|
37+
LL | struct Foo;
38+
| ---------- this struct does not implement `ConstParamTy`
39+
LL |
40+
LL | impl ConstParamTy for &Foo {}
41+
| ^^^^
42+
|
43+
help: consider annotating this struct with `#[derive(ConstParamTy)]`
44+
|
45+
LL + #[derive(ConstParamTy)]
46+
LL | struct Foo;
47+
|
48+
49+
error: the trait `ConstParamTy` cannot be implemented for this type
50+
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:13:23
51+
|
52+
LL | struct Foo;
53+
| ---------- this struct does not implement `ConstParamTy`
54+
...
55+
LL | impl ConstParamTy for &[Foo] {}
56+
| ^^^^^^
57+
|
58+
help: consider annotating this struct with `#[derive(ConstParamTy)]`
59+
|
60+
LL + #[derive(ConstParamTy)]
61+
LL | struct Foo;
62+
|
63+
64+
error: the trait `ConstParamTy` cannot be implemented for this type
65+
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:17:23
66+
|
67+
LL | struct Foo;
68+
| ---------- this struct does not implement `ConstParamTy`
69+
...
70+
LL | impl ConstParamTy for [Foo; 4] {}
71+
| ^^^^^^^^
72+
|
73+
help: consider annotating this struct with `#[derive(ConstParamTy)]`
74+
|
75+
LL + #[derive(ConstParamTy)]
76+
LL | struct Foo;
77+
|
78+
79+
error: the trait `ConstParamTy` cannot be implemented for this type
80+
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:21:23
81+
|
82+
LL | struct Foo;
83+
| ---------- this struct does not implement `ConstParamTy`
84+
...
85+
LL | impl ConstParamTy for (Foo, i32, *const u8) {}
86+
| ^^^^^^^^^^^^^^^^^^^^^
87+
|
88+
help: consider annotating this struct with `#[derive(ConstParamTy)]`
89+
|
90+
LL + #[derive(ConstParamTy)]
91+
LL | struct Foo;
92+
|
93+
94+
error[E0204]: the trait `ConstParamTy` cannot be implemented for this type
95+
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:30:23
96+
|
97+
LL | struct Wrapper(*const i32, usize);
98+
| ---------- this field does not implement `ConstParamTy`
99+
LL |
100+
LL | impl ConstParamTy for &Wrapper {}
101+
| ^^^^^^^^
102+
103+
error: aborting due to 8 previous errors
104+
105+
Some errors have detailed explanations: E0117, E0204.
106+
For more information about an error, try `rustc --explain E0117`.

tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_referee.rs

-26
This file was deleted.

tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_referee.stderr

-27
This file was deleted.

0 commit comments

Comments
 (0)