Skip to content

Commit

Permalink
Also check the inner ty of arrays, slices, and tuples
Browse files Browse the repository at this point in the history
  • Loading branch information
sjwang05 committed Jan 21, 2024
1 parent 4c56815 commit f98b06f
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 87 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ hir_analysis_const_impl_for_non_const_trait =
.note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
.adding = adding a non-const method body in the future would be a breaking change
hir_analysis_const_param_ty_impl_on_infringing_referee =
hir_analysis_const_param_ty_impl_on_infringing_inner_ty =
the trait `ConstParamTy` cannot be implemented for this type
.label = the trait `ConstParamTy` is not implemented for this {$def_descr}
.label = this {$def_descr} does not implement `ConstParamTy`
.suggestion = consider annotating this {$def_descr} with `#[derive(ConstParamTy)]`
hir_analysis_const_param_ty_impl_on_non_adt =
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -988,7 +988,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
ty_is_local(ty)
}
// Same as above.
Err(ConstParamTyImplementationError::InfringingReferee(def_id)) => {
Err(ConstParamTyImplementationError::InfringingInnerTy(def_id)) => {
def_id.is_local()
}
// Implments `ConstParamTy`, suggest adding the feature to enable.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId)
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span });
}
Err(ConstParamTyImplementationError::InfringingReferee(def_id)) => {
Err(ConstParamTyImplementationError::InfringingInnerTy(def_id)) => {
let def_span = tcx.def_span(def_id);
tcx.dcx().emit_err(errors::ConstParamTyImplOnInfringingReferee {
tcx.dcx().emit_err(errors::ConstParamTyImplOnInfringingInnerTy {
span,
def_span,
def_descr: tcx.def_descr(def_id),
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ pub struct ConstParamTyImplOnNonAdt {
}

#[derive(Diagnostic)]
#[diag(hir_analysis_const_param_ty_impl_on_infringing_referee)]
pub struct ConstParamTyImplOnInfringingReferee {
#[diag(hir_analysis_const_param_ty_impl_on_infringing_inner_ty)]
pub struct ConstParamTyImplOnInfringingInnerTy {
#[primary_span]
pub span: Span,
#[label]
Expand Down
60 changes: 33 additions & 27 deletions compiler/rustc_trait_selection/src/traits/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub enum CopyImplementationError<'tcx> {

pub enum ConstParamTyImplementationError<'tcx> {
InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
InfringingReferee(DefId),
InfringingInnerTy(DefId),
NotAnAdtOrBuiltinAllowed,
}

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

Ok(())
};

let (adt, args) = match self_type.kind() {
// `core` provides these impls, but only where the inner type is `ConstParamTy`,
// so we need to check and deny impls where the inner type is not `ConstParamTy`
&ty::Ref(.., ty, hir::Mutability::Not) | &ty::Array(ty, ..) | &ty::Slice(ty) => {
return check_inner_ty(ty, parent_cause);
}

&ty::Tuple(tys) => {
for ty in tys {
check_inner_ty(ty, parent_cause.clone())?;
}
return Ok(());
}

// `core` provides these impls.
ty::Uint(_)
| ty::Int(_)
| ty::Bool
| ty::Char
| ty::Str
| ty::Array(..)
| ty::Slice(_)
| ty::Ref(.., hir::Mutability::Not)
| ty::Tuple(_) => return Ok(()),
ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char | ty::Str => return Ok(()),

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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#![feature(adt_const_params)]
#![allow(incomplete_features)]

use std::marker::ConstParamTy;

// #112124

struct Foo;

impl ConstParamTy for &Foo {}
//~^ ERROR the trait `ConstParamTy` cannot be implemented for this type

impl ConstParamTy for &[Foo] {}
//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
//~| ERROR the trait `ConstParamTy` cannot be implemented for this type

impl ConstParamTy for [Foo; 4] {}
//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
//~| ERROR the trait `ConstParamTy` cannot be implemented for this type

impl ConstParamTy for (Foo, i32, *const u8) {}
//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
//~| ERROR the trait `ConstParamTy` cannot be implemented for this type

// #119299 (ICE)

#[derive(Eq, PartialEq)]
struct Wrapper(*const i32, usize);

impl ConstParamTy for &Wrapper {}
//~^ ERROR the trait `ConstParamTy` cannot be implemented for this type

const fn foo<const S: &'static Wrapper>() {}

fn main() {
const FOO: Wrapper = Wrapper(&42 as *const i32, 42);
foo::<{ &FOO }>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:13:1
|
LL | impl ConstParamTy for &[Foo] {}
| ^^^^^^^^^^^^^^^^^^^^^^------
| | |
| | this is not defined in the current crate because slices are always foreign
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:17:1
|
LL | impl ConstParamTy for [Foo; 4] {}
| ^^^^^^^^^^^^^^^^^^^^^^--------
| | |
| | this is not defined in the current crate because arrays are always foreign
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:21:1
|
LL | impl ConstParamTy for (Foo, i32, *const u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^---------------------
| | |
| | this is not defined in the current crate because tuples are always foreign
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead

error: the trait `ConstParamTy` cannot be implemented for this type
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:10:23
|
LL | struct Foo;
| ---------- this struct does not implement `ConstParamTy`
LL |
LL | impl ConstParamTy for &Foo {}
| ^^^^
|
help: consider annotating this struct with `#[derive(ConstParamTy)]`
|
LL + #[derive(ConstParamTy)]
LL | struct Foo;
|

error: the trait `ConstParamTy` cannot be implemented for this type
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:13:23
|
LL | struct Foo;
| ---------- this struct does not implement `ConstParamTy`
...
LL | impl ConstParamTy for &[Foo] {}
| ^^^^^^
|
help: consider annotating this struct with `#[derive(ConstParamTy)]`
|
LL + #[derive(ConstParamTy)]
LL | struct Foo;
|

error: the trait `ConstParamTy` cannot be implemented for this type
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:17:23
|
LL | struct Foo;
| ---------- this struct does not implement `ConstParamTy`
...
LL | impl ConstParamTy for [Foo; 4] {}
| ^^^^^^^^
|
help: consider annotating this struct with `#[derive(ConstParamTy)]`
|
LL + #[derive(ConstParamTy)]
LL | struct Foo;
|

error: the trait `ConstParamTy` cannot be implemented for this type
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:21:23
|
LL | struct Foo;
| ---------- this struct does not implement `ConstParamTy`
...
LL | impl ConstParamTy for (Foo, i32, *const u8) {}
| ^^^^^^^^^^^^^^^^^^^^^
|
help: consider annotating this struct with `#[derive(ConstParamTy)]`
|
LL + #[derive(ConstParamTy)]
LL | struct Foo;
|

error[E0204]: the trait `ConstParamTy` cannot be implemented for this type
--> $DIR/const_param_ty_impl_bad_inner_ty.rs:30:23
|
LL | struct Wrapper(*const i32, usize);
| ---------- this field does not implement `ConstParamTy`
LL |
LL | impl ConstParamTy for &Wrapper {}
| ^^^^^^^^

error: aborting due to 8 previous errors

Some errors have detailed explanations: E0117, E0204.
For more information about an error, try `rustc --explain E0117`.

This file was deleted.

This file was deleted.

0 comments on commit f98b06f

Please sign in to comment.