about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaybe Waffle <waffle.lapkin@gmail.com>2023-02-17 13:44:35 +0000
committerMaybe Waffle <waffle.lapkin@gmail.com>2023-04-27 15:46:21 +0000
commit9a716dafbe3deb97091c5e511c2d893e1f325b07 (patch)
tree54b22f959cd04e39669f17027ea2505e9ae128e3
parent518d348f873ac5df4ca43b36145e5556138adad3 (diff)
downloadrust-9a716dafbe3deb97091c5e511c2d893e1f325b07.tar.gz
rust-9a716dafbe3deb97091c5e511c2d893e1f325b07.zip
Add a `ConstParamTy` trait
-rw-r--r--compiler/rustc_hir/src/lang_items.rs2
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl4
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs255
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs8
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs94
-rw-r--r--library/core/src/marker.rs34
-rw-r--r--tests/ui/const-generics/const_patam_ty_impl_bad_field.rs12
-rw-r--r--tests/ui/const-generics/const_patam_ty_impl_bad_field.stderr12
9 files changed, 300 insertions, 122 deletions
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 8f91a96f964..e1c030d3e19 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -293,6 +293,8 @@ language_item_table! {
 
     PointerLike,             sym::pointer_like,        pointer_like,               Target::Trait,          GenericRequirement::Exact(0);
 
+    ConstParamTy,            sym::const_param_ty,      const_param_ty_trait,       Target::Trait,          GenericRequirement::Exact(0);
+
     Poll,                    sym::Poll,                poll,                       Target::Enum,           GenericRequirement::None;
     PollReady,               sym::Ready,               poll_ready_variant,         Target::Variant,        GenericRequirement::None;
     PollPending,             sym::Pending,             poll_pending_variant,       Target::Variant,        GenericRequirement::None;
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 1d7965ff5f6..bda9879b5db 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -35,6 +35,10 @@ hir_analysis_field_already_declared =
 
 hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
 
+hir_analysis_const_param_ty_impl_on_non_adt =
+    the trait `ConstParamTy` may not be implemented for this type
+    .label = type is not a structure or enumeration
+
 hir_analysis_ambiguous_lifetime_bound =
     ambiguous lifetime bound, explicit lifetime bound required
 
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 611ce13b739..0f450ae67b7 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -1,9 +1,11 @@
 //! Check properties that are required by built-in traits and set
 //! up data structures required by type-checking/codegen.
 
-use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem};
+use crate::errors::{
+    ConstParamTyImplOnNonAdt, CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem,
+};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{struct_span_err, MultiSpan};
+use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
@@ -14,9 +16,11 @@ use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
+use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::misc::{
-    type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason,
+    type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
+    ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
 };
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::{self, ObligationCause};
@@ -27,6 +31,7 @@ pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
     Checker { tcx, trait_def_id }
         .check(lang_items.drop_trait(), visit_implementation_of_drop)
         .check(lang_items.copy_trait(), visit_implementation_of_copy)
+        .check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty)
         .check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
         .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
 }
@@ -83,110 +88,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
     match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
         Ok(()) => {}
         Err(CopyImplementationError::InfringingFields(fields)) => {
-            let mut err = struct_span_err!(
-                tcx.sess,
-                span,
-                E0204,
-                "the trait `Copy` cannot be implemented for this type"
-            );
-
-            // We'll try to suggest constraining type parameters to fulfill the requirements of
-            // their `Copy` implementation.
-            let mut errors: BTreeMap<_, Vec<_>> = Default::default();
-            let mut bounds = vec![];
-
-            let mut seen_tys = FxHashSet::default();
-
-            for (field, ty, reason) in fields {
-                // Only report an error once per type.
-                if !seen_tys.insert(ty) {
-                    continue;
-                }
-
-                let field_span = tcx.def_span(field.did);
-                err.span_label(field_span, "this field does not implement `Copy`");
-
-                match reason {
-                    InfringingFieldsReason::Fulfill(fulfillment_errors) => {
-                        for error in fulfillment_errors {
-                            let error_predicate = error.obligation.predicate;
-                            // Only note if it's not the root obligation, otherwise it's trivial and
-                            // should be self-explanatory (i.e. a field literally doesn't implement Copy).
-
-                            // FIXME: This error could be more descriptive, especially if the error_predicate
-                            // contains a foreign type or if it's a deeply nested type...
-                            if error_predicate != error.root_obligation.predicate {
-                                errors
-                                    .entry((ty.to_string(), error_predicate.to_string()))
-                                    .or_default()
-                                    .push(error.obligation.cause.span);
-                            }
-                            if let ty::PredicateKind::Clause(ty::Clause::Trait(
-                                ty::TraitPredicate {
-                                    trait_ref,
-                                    polarity: ty::ImplPolarity::Positive,
-                                    ..
-                                },
-                            )) = error_predicate.kind().skip_binder()
-                            {
-                                let ty = trait_ref.self_ty();
-                                if let ty::Param(_) = ty.kind() {
-                                    bounds.push((
-                                        format!("{ty}"),
-                                        trait_ref.print_only_trait_path().to_string(),
-                                        Some(trait_ref.def_id),
-                                    ));
-                                }
-                            }
-                        }
-                    }
-                    InfringingFieldsReason::Regions(region_errors) => {
-                        for error in region_errors {
-                            let ty = ty.to_string();
-                            match error {
-                                RegionResolutionError::ConcreteFailure(origin, a, b) => {
-                                    let predicate = format!("{b}: {a}");
-                                    errors
-                                        .entry((ty.clone(), predicate.clone()))
-                                        .or_default()
-                                        .push(origin.span());
-                                    if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
-                                        bounds.push((b.to_string(), a.to_string(), None));
-                                    }
-                                }
-                                RegionResolutionError::GenericBoundFailure(origin, a, b) => {
-                                    let predicate = format!("{a}: {b}");
-                                    errors
-                                        .entry((ty.clone(), predicate.clone()))
-                                        .or_default()
-                                        .push(origin.span());
-                                    if let infer::region_constraints::GenericKind::Param(_) = a {
-                                        bounds.push((a.to_string(), b.to_string(), None));
-                                    }
-                                }
-                                _ => continue,
-                            }
-                        }
-                    }
-                }
-            }
-            for ((ty, error_predicate), spans) in errors {
-                let span: MultiSpan = spans.into();
-                err.span_note(
-                    span,
-                    &format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate),
-                );
-            }
-            suggest_constraining_type_params(
-                tcx,
-                tcx.hir().get_generics(impl_did).expect("impls always have generics"),
-                &mut err,
-                bounds.iter().map(|(param, constraint, def_id)| {
-                    (param.as_str(), constraint.as_str(), *def_id)
-                }),
-                None,
-            );
-            err.emit();
+            infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span);
         }
         Err(CopyImplementationError::NotAnAdt) => {
             tcx.sess.emit_err(CopyImplOnNonAdt { span });
@@ -197,6 +99,29 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
     }
 }
 
+fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+    let self_type = tcx.type_of(impl_did).subst_identity();
+    assert!(!self_type.has_escaping_bound_vars());
+
+    let param_env = tcx.param_env(impl_did);
+
+    let span = match tcx.hir().expect_item(impl_did).expect_impl() {
+        hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
+        impl_ => impl_.self_ty.span,
+    };
+
+    let cause = traits::ObligationCause::misc(span, impl_did);
+    match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
+        Ok(()) => {}
+        Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
+            infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span);
+        }
+        Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
+            tcx.sess.emit_err(ConstParamTyImplOnNonAdt { span });
+        }
+    }
+}
+
 fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
     debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
 
@@ -593,3 +518,119 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
 
     CoerceUnsizedInfo { custom_kind: kind }
 }
+
+fn infringing_fields_error(
+    tcx: TyCtxt<'_>,
+    fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>,
+    lang_item: LangItem,
+    impl_did: LocalDefId,
+    impl_span: Span,
+) -> ErrorGuaranteed {
+    let trait_did = tcx.require_lang_item(lang_item, Some(impl_span));
+
+    let trait_name = tcx.def_path_str(trait_did);
+
+    let mut err = struct_span_err!(
+        tcx.sess,
+        impl_span,
+        E0204,
+        "the trait `{trait_name}` cannot be implemented for this type"
+    );
+
+    // We'll try to suggest constraining type parameters to fulfill the requirements of
+    // their `Copy` implementation.
+    let mut errors: BTreeMap<_, Vec<_>> = Default::default();
+    let mut bounds = vec![];
+
+    let mut seen_tys = FxHashSet::default();
+
+    for (field, ty, reason) in fields {
+        // Only report an error once per type.
+        if !seen_tys.insert(ty) {
+            continue;
+        }
+
+        let field_span = tcx.def_span(field.did);
+        err.span_label(field_span, format!("this field does not implement `{trait_name}`"));
+
+        match reason {
+            InfringingFieldsReason::Fulfill(fulfillment_errors) => {
+                for error in fulfillment_errors {
+                    let error_predicate = error.obligation.predicate;
+                    // Only note if it's not the root obligation, otherwise it's trivial and
+                    // should be self-explanatory (i.e. a field literally doesn't implement Copy).
+
+                    // FIXME: This error could be more descriptive, especially if the error_predicate
+                    // contains a foreign type or if it's a deeply nested type...
+                    if error_predicate != error.root_obligation.predicate {
+                        errors
+                            .entry((ty.to_string(), error_predicate.to_string()))
+                            .or_default()
+                            .push(error.obligation.cause.span);
+                    }
+                    if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
+                        trait_ref,
+                        polarity: ty::ImplPolarity::Positive,
+                        ..
+                    })) = error_predicate.kind().skip_binder()
+                    {
+                        let ty = trait_ref.self_ty();
+                        if let ty::Param(_) = ty.kind() {
+                            bounds.push((
+                                format!("{ty}"),
+                                trait_ref.print_only_trait_path().to_string(),
+                                Some(trait_ref.def_id),
+                            ));
+                        }
+                    }
+                }
+            }
+            InfringingFieldsReason::Regions(region_errors) => {
+                for error in region_errors {
+                    let ty = ty.to_string();
+                    match error {
+                        RegionResolutionError::ConcreteFailure(origin, a, b) => {
+                            let predicate = format!("{b}: {a}");
+                            errors
+                                .entry((ty.clone(), predicate.clone()))
+                                .or_default()
+                                .push(origin.span());
+                            if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
+                                        bounds.push((b.to_string(), a.to_string(), None));
+                                    }
+                        }
+                        RegionResolutionError::GenericBoundFailure(origin, a, b) => {
+                            let predicate = format!("{a}: {b}");
+                            errors
+                                .entry((ty.clone(), predicate.clone()))
+                                .or_default()
+                                .push(origin.span());
+                            if let infer::region_constraints::GenericKind::Param(_) = a {
+                                bounds.push((a.to_string(), b.to_string(), None));
+                            }
+                        }
+                        _ => continue,
+                    }
+                }
+            }
+        }
+    }
+    for ((ty, error_predicate), spans) in errors {
+        let span: MultiSpan = spans.into();
+        err.span_note(
+            span,
+            format!("the `{trait_name}` impl for `{ty}` requires that `{error_predicate}`"),
+        );
+    }
+    suggest_constraining_type_params(
+        tcx,
+        tcx.hir().get_generics(impl_did).expect("impls always have generics"),
+        &mut err,
+        bounds
+            .iter()
+            .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
+        None,
+    );
+
+    err.emit()
+}
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 2a3a683489d..8dcf3b1670d 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -108,6 +108,14 @@ pub struct CopyImplOnNonAdt {
 }
 
 #[derive(Diagnostic)]
+#[diag(hir_analysis_const_param_ty_impl_on_non_adt)]
+pub struct ConstParamTyImplOnNonAdt {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(hir_analysis_trait_object_declared_with_no_traits, code = "E0224")]
 pub struct TraitObjectDeclaredWithNoTraits {
     #[primary_span]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 70b9088de50..d2e23f84514 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -531,6 +531,7 @@ symbols! {
         const_mut_refs,
         const_panic,
         const_panic_fmt,
+        const_param_ty,
         const_precise_live_drops,
         const_raw_ptr_deref,
         const_raw_ptr_to_usize_cast,
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 63949843aed..3c43758e50d 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -2,13 +2,14 @@
 
 use crate::traits::{self, ObligationCause, ObligationCtxt};
 
+use hir::LangItem;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_infer::infer::canonical::Canonical;
 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, AdtDef, GenericArg, List, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::DUMMY_SP;
 
 use super::outlives_bounds::InferCtxtExt;
@@ -19,6 +20,11 @@ pub enum CopyImplementationError<'tcx> {
     HasDestructor,
 }
 
+pub enum ConstParamTyImplementationError<'tcx> {
+    InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
+    NotAnAdtOrBuiltinAllowed,
+}
+
 pub enum InfringingFieldsReason<'tcx> {
     Fulfill(Vec<FulfillmentError<'tcx>>),
     Regions(Vec<RegionResolutionError<'tcx>>),
@@ -27,7 +33,10 @@ pub enum InfringingFieldsReason<'tcx> {
 /// Checks that the fields of the type (an ADT) all implement copy.
 ///
 /// If fields don't implement copy, return an error containing a list of
-/// those violating fields. If it's not an ADT, returns `Err(NotAnAdt)`.
+/// those violating fields.
+///
+/// If it's not an ADT, int ty, `bool`, float ty, `char`, raw pointer, `!`,
+/// a reference or an array returns `Err(NotAnAdt)`.
 pub fn type_allowed_to_implement_copy<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -47,12 +56,75 @@ pub fn type_allowed_to_implement_copy<'tcx>(
         | ty::Ref(_, _, hir::Mutability::Not)
         | ty::Array(..) => return Ok(()),
 
-        ty::Adt(adt, substs) => (adt, substs),
+        &ty::Adt(adt, substs) => (adt, substs),
 
         _ => return Err(CopyImplementationError::NotAnAdt),
     };
 
-    let copy_def_id = tcx.require_lang_item(hir::LangItem::Copy, Some(parent_cause.span));
+    all_fields_implement_trait(
+        tcx,
+        param_env,
+        self_type,
+        adt,
+        substs,
+        parent_cause,
+        hir::LangItem::Copy,
+    )
+    .map_err(CopyImplementationError::InfringingFields)?;
+
+    if adt.has_dtor(tcx) {
+        return Err(CopyImplementationError::HasDestructor);
+    }
+
+    Ok(())
+}
+
+/// Checks that the fields of the type (an ADT) all implement `ConstParamTy`.
+///
+/// If fields don't implement `ConstParamTy`, return an error containing a list of
+/// those violating fields.
+///
+/// If it's not an ADT, int ty, `bool` or `char`, returns `Err(NotAnAdtOrBuiltinAllowed)`.
+pub fn type_allowed_to_implement_const_param_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    self_type: Ty<'tcx>,
+    parent_cause: ObligationCause<'tcx>,
+) -> Result<(), ConstParamTyImplementationError<'tcx>> {
+    let (adt, substs) = match self_type.kind() {
+        // `core` provides these impls.
+        ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => return Ok(()),
+
+        &ty::Adt(adt, substs) => (adt, substs),
+
+        _ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
+    };
+
+    all_fields_implement_trait(
+        tcx,
+        param_env,
+        self_type,
+        adt,
+        substs,
+        parent_cause,
+        hir::LangItem::Copy,
+    )
+    .map_err(ConstParamTyImplementationError::InfrigingFields)?;
+
+    Ok(())
+}
+
+/// Check that all fields of a given `adt` implement `lang_item` trait.
+pub fn all_fields_implement_trait<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    self_type: Ty<'tcx>,
+    adt: AdtDef<'tcx>,
+    substs: &'tcx List<GenericArg<'tcx>>,
+    parent_cause: ObligationCause<'tcx>,
+    lang_item: LangItem,
+) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> {
+    let trait_def_id = tcx.require_lang_item(lang_item, Some(parent_cause.span));
 
     let mut infringing = Vec::new();
     for variant in adt.variants() {
@@ -93,7 +165,7 @@ pub fn type_allowed_to_implement_copy<'tcx>(
             // between expected and found const-generic types. Don't report an
             // additional copy error here, since it's not typically useful.
             if !normalization_errors.is_empty() || ty.references_error() {
-                tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking Copy implementation"));
+                tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id)));
                 continue;
             }
 
@@ -101,7 +173,7 @@ pub fn type_allowed_to_implement_copy<'tcx>(
                 ObligationCause::dummy_with_span(field_ty_span),
                 param_env,
                 ty,
-                copy_def_id,
+                trait_def_id,
             );
             let errors = ocx.select_all_or_error();
             if !errors.is_empty() {
@@ -124,15 +196,7 @@ pub fn type_allowed_to_implement_copy<'tcx>(
         }
     }
 
-    if !infringing.is_empty() {
-        return Err(CopyImplementationError::InfringingFields(infringing));
-    }
-
-    if adt.has_dtor(tcx) {
-        return Err(CopyImplementationError::HasDestructor);
-    }
-
-    Ok(())
+    if infringing.is_empty() { Ok(()) } else { Err(infringing) }
 }
 
 pub fn check_tys_might_be_eq<'tcx>(
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 1d33236c269..ff8653c0820 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -912,6 +912,40 @@ pub trait Tuple {}
 )]
 pub trait PointerLike {}
 
+/// A marker for types which can be used as types of `const` generic parameters.
+#[cfg_attr(not(bootstrap), lang = "const_param_ty")]
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+#[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")]
+pub trait ConstParamTy: StructuralEq {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for usize {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for u8 {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for u16 {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for u32 {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for u64 {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for u128 {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for isize {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for i8 {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for i16 {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for i32 {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for i64 {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for i128 {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for bool {}
+#[unstable(feature = "const_param_ty_trait", issue = "none")]
+impl ConstParamTy for char {}
+
 /// Implementations of `Copy` for primitive types.
 ///
 /// Implementations that cannot be described in Rust
diff --git a/tests/ui/const-generics/const_patam_ty_impl_bad_field.rs b/tests/ui/const-generics/const_patam_ty_impl_bad_field.rs
new file mode 100644
index 00000000000..37cfa1aa7f5
--- /dev/null
+++ b/tests/ui/const-generics/const_patam_ty_impl_bad_field.rs
@@ -0,0 +1,12 @@
+#![feature(const_param_ty_trait)]
+
+#[derive(PartialEq)]
+struct NotParam;
+
+#[derive(PartialEq)]
+struct CantParam(NotParam);
+
+impl std::marker::ConstParamTy for CantParam {}
+//~^ error: the trait `ConstParamTy` may not be implemented for this type
+
+fn main() {}
diff --git a/tests/ui/const-generics/const_patam_ty_impl_bad_field.stderr b/tests/ui/const-generics/const_patam_ty_impl_bad_field.stderr
new file mode 100644
index 00000000000..dd150deffc2
--- /dev/null
+++ b/tests/ui/const-generics/const_patam_ty_impl_bad_field.stderr
@@ -0,0 +1,12 @@
+error[E0204]: the trait `ConstParamTy` may not be implemented for this type
+  --> $DIR/const_patam_ty_impl_bad_field.rs:9:36
+   |
+LL | struct CantParam(NotParam);
+   |                  -------- this field does not implement `ConstParamTy`
+LL |
+LL | impl std::marker::ConstParamTy for CantParam {}
+   |                                    ^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0204`.