From 518d348f873ac5df4ca43b36145e5556138adad3 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 17 Feb 2023 13:43:38 +0000 Subject: [PATCH 01/17] Implement `StructuralEq` for integers, `bool` and `char` (how did this work before??) --- library/core/src/marker.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index e85c0c0a688..1d33236c269 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -214,6 +214,35 @@ pub trait StructuralEq { // Empty. } +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for usize {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for u8 {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for u16 {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for u32 {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for u64 {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for u128 {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for isize {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for i8 {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for i16 {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for i32 {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for i64 {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for i128 {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for bool {} +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralEq for char {} + /// Types whose values can be duplicated simply by copying bits. /// /// By default, variable bindings have 'move semantics.' In other From 9a716dafbe3deb97091c5e511c2d893e1f325b07 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 17 Feb 2023 13:44:35 +0000 Subject: [PATCH 02/17] Add a `ConstParamTy` trait --- compiler/rustc_hir/src/lang_items.rs | 2 + compiler/rustc_hir_analysis/messages.ftl | 4 + .../src/coherence/builtin.rs | 255 ++++++++++-------- compiler/rustc_hir_analysis/src/errors.rs | 8 + compiler/rustc_span/src/symbol.rs | 1 + .../rustc_trait_selection/src/traits/misc.rs | 94 +++++-- library/core/src/marker.rs | 34 +++ .../const_patam_ty_impl_bad_field.rs | 12 + .../const_patam_ty_impl_bad_field.stderr | 12 + 9 files changed, 300 insertions(+), 122 deletions(-) create mode 100644 tests/ui/const-generics/const_patam_ty_impl_bad_field.rs create mode 100644 tests/ui/const-generics/const_patam_ty_impl_bad_field.stderr 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 @@ -107,6 +107,14 @@ pub struct CopyImplOnNonAdt { pub span: Span, } +#[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 { 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>), Regions(Vec>), @@ -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>, + 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`. From c8844e1337f1304d06417a712110abbd3a2beb95 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 22 Feb 2023 17:57:52 +0000 Subject: [PATCH 03/17] `derive(Eq)` in a test --- tests/ui/const-generics/const_patam_ty_impl_bad_field.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 37cfa1aa7f5..2cfccb68b0e 100644 --- a/tests/ui/const-generics/const_patam_ty_impl_bad_field.rs +++ b/tests/ui/const-generics/const_patam_ty_impl_bad_field.rs @@ -1,9 +1,9 @@ #![feature(const_param_ty_trait)] -#[derive(PartialEq)] +#[derive(PartialEq, Eq)] struct NotParam; -#[derive(PartialEq)] +#[derive(PartialEq, Eq)] struct CantParam(NotParam); impl std::marker::ConstParamTy for CantParam {} From 81a2b856c8e6336f01831108924004f582ad59d0 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 22 Feb 2023 17:59:49 +0000 Subject: [PATCH 04/17] Remove `feature(const_param_ty_trait)`, use `adt_const_params` instead --- library/core/src/marker.rs | 30 +++++++++---------- .../const_patam_ty_impl_bad_field.rs | 3 +- .../const_patam_ty_impl_bad_field.stderr | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index ff8653c0820..24e95aed27e 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -914,36 +914,36 @@ 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")] +#[unstable(feature = "adt_const_params", issue = "95174")] #[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")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for usize {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for u8 {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for u16 {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for u32 {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for u64 {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for u128 {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for isize {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for i8 {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for i16 {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for i32 {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for i64 {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for i128 {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for bool {} -#[unstable(feature = "const_param_ty_trait", issue = "none")] +#[unstable(feature = "adt_const_params", issue = "95174")] impl ConstParamTy for char {} /// Implementations of `Copy` for primitive types. 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 index 2cfccb68b0e..3d2d99b9d38 100644 --- a/tests/ui/const-generics/const_patam_ty_impl_bad_field.rs +++ b/tests/ui/const-generics/const_patam_ty_impl_bad_field.rs @@ -1,4 +1,5 @@ -#![feature(const_param_ty_trait)] +#![allow(incomplete_features)] +#![feature(adt_const_params)] #[derive(PartialEq, Eq)] struct NotParam; 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 index dd150deffc2..273845b1668 100644 --- a/tests/ui/const-generics/const_patam_ty_impl_bad_field.stderr +++ b/tests/ui/const-generics/const_patam_ty_impl_bad_field.stderr @@ -1,5 +1,5 @@ error[E0204]: the trait `ConstParamTy` may not be implemented for this type - --> $DIR/const_patam_ty_impl_bad_field.rs:9:36 + --> $DIR/const_patam_ty_impl_bad_field.rs:10:36 | LL | struct CantParam(NotParam); | -------- this field does not implement `ConstParamTy` From c45c4f2cb13968722ae15f76c70fe598c73698fb Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 22 Feb 2023 18:11:47 +0000 Subject: [PATCH 05/17] Rename/move a test --- .../const_param_ty_impl_bad_field.rs} | 0 .../const_param_ty_impl_bad_field.stderr} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/ui/const-generics/{const_patam_ty_impl_bad_field.rs => adt_const_params/const_param_ty_impl_bad_field.rs} (100%) rename tests/ui/const-generics/{const_patam_ty_impl_bad_field.stderr => adt_const_params/const_param_ty_impl_bad_field.stderr} (89%) diff --git a/tests/ui/const-generics/const_patam_ty_impl_bad_field.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs similarity index 100% rename from tests/ui/const-generics/const_patam_ty_impl_bad_field.rs rename to tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs diff --git a/tests/ui/const-generics/const_patam_ty_impl_bad_field.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr similarity index 89% rename from tests/ui/const-generics/const_patam_ty_impl_bad_field.stderr rename to tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr index 273845b1668..5cd5cae6d79 100644 --- a/tests/ui/const-generics/const_patam_ty_impl_bad_field.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr @@ -1,5 +1,5 @@ error[E0204]: the trait `ConstParamTy` may not be implemented for this type - --> $DIR/const_patam_ty_impl_bad_field.rs:10:36 + --> $DIR/const_param_ty_impl_bad_field.rs:10:36 | LL | struct CantParam(NotParam); | -------- this field does not implement `ConstParamTy` From 1c544108b1e10124b3a9f45a68c1cb36c1c45e90 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 23 Feb 2023 11:54:09 +0000 Subject: [PATCH 06/17] Check the correct trait when checking `ConstParamTy` impls --- compiler/rustc_trait_selection/src/traits/misc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 3c43758e50d..cb8f64dd2e8 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -107,7 +107,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( adt, substs, parent_cause, - hir::LangItem::Copy, + hir::LangItem::ConstParamTy, ) .map_err(ConstParamTyImplementationError::InfrigingFields)?; From 7234d63ea4880c62fa2ed0078c465cc07bbbb289 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 23 Feb 2023 12:00:34 +0000 Subject: [PATCH 07/17] Add `!StructuralEq` test for `ConstParamTy` --- .../const_param_ty_impl_no_structural_eq.rs | 17 +++++++++++++++++ .../const_param_ty_impl_no_structural_eq.stderr | 12 ++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs new file mode 100644 index 00000000000..17ef396164e --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs @@ -0,0 +1,17 @@ +#![allow(incomplete_features)] +#![feature(adt_const_params)] + +#[derive(PartialEq, Eq)] +struct ImplementsConstParamTy; +impl std::marker::ConstParamTy for ImplementsConstParamTy {} + +struct CantParam(ImplementsConstParamTy); + +impl std::marker::ConstParamTy for CantParam {} +//~^ error: the type `CantParam` does not `#[derive(Eq)]` + +fn check() {} + +fn main() { + check::(); +} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr new file mode 100644 index 00000000000..ca5abf5e254 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr @@ -0,0 +1,12 @@ +error[E0277]: the type `CantParam` does not `#[derive(Eq)]` + --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:36 + | +LL | impl std::marker::ConstParamTy for CantParam {} + | ^^^^^^^^^ the trait `StructuralEq` is not implemented for `CantParam` + | +note: required by a bound in `ConstParamTy` + --> $SRC_DIR/core/src/marker.rs:LL:COL + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 2205c3fa5ffdb8794917d541e580742f527be8f1 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 3 Mar 2023 11:29:21 +0000 Subject: [PATCH 08/17] Add a macro to conveniently implement marker traits --- library/core/src/lib.rs | 1 + library/core/src/marker.rs | 221 +++++++++++++++++++------------------ 2 files changed, 114 insertions(+), 108 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 24a9d81d037..b269a3bcb00 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -162,6 +162,7 @@ #![feature(const_waker)] #![feature(core_panic)] #![feature(duration_consts_float)] +#![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] #![feature(maybe_uninit_uninit_array)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 24e95aed27e..8c240661b2b 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -12,6 +12,60 @@ use crate::fmt::Debug; use crate::hash::Hash; use crate::hash::Hasher; +/// Implements a given marker trait for multiple types at the same time. +/// +/// The basic syntax looks like this: +/// ```ignore private macro +/// marker_impls! { MarkerTrait for u8, i8 } +/// ``` +/// You can also implement `unsafe` traits +/// ```ignore private macro +/// marker_impls! { unsafe MarkerTrait for u8, i8 } +/// ``` +/// Add attributes to all impls: +/// ```ignore private macro +/// marker_impls! { +/// #[allow(lint)] +/// #[unstable(feature = "marker_trait", issue = "none")] +/// MarkerTrait for u8, i8 +/// } +/// ``` +/// And use generics: +/// ```ignore private macro +/// marker_impls! { +/// MarkerTrait for +/// u8, i8, +/// {T: ?Sized} *const T, +/// {T: ?Sized} *mut T, +/// {T: MarkerTrait} PhantomData, +/// u32, +/// } +/// ``` +#[unstable(feature = "internal_impls_macro", issue = "none")] +macro marker_impls { + ( $(#[$($meta:tt)*])* $Trait:ident for $( $({$($bounds:tt)*})? $T:ty ),+ $(,)?) => { + // This inner macro is needed because... idk macros are weird. + // It allows repeating `meta` on all impls. + #[unstable(feature = "internal_impls_macro", issue = "none")] + macro _impl { + ( $$({$$($$bounds_:tt)*})? $$T_:ty ) => { + $(#[$($meta)*])* impl<$$($$($$bounds_)*)?> $Trait for $$T_ {} + } + } + $( _impl! { $({$($bounds)*})? $T } )+ + }, + ( $(#[$($meta:tt)*])* unsafe $Trait:ident for $( $({$($bounds:tt)*})? $T:ty ),+ $(,)?) => { + #[unstable(feature = "internal_impls_macro", issue = "none")] + macro _impl { + ( $$({$$($$bounds_:tt)*})? $$T_:ty ) => { + $(#[$($meta)*])* unsafe impl<$$($$($$bounds_)*)?> $Trait for $$T_ {} + } + } + + $( _impl! { $({$($bounds)*})? $T } )+ + }, +} + /// Types that can be transferred across thread boundaries. /// /// This trait is automatically implemented when the compiler determines it's @@ -214,34 +268,14 @@ pub trait StructuralEq { // Empty. } -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for usize {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for u8 {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for u16 {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for u32 {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for u64 {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for u128 {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for isize {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for i8 {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for i16 {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for i32 {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for i64 {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for i128 {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for bool {} -#[unstable(feature = "structural_match", issue = "31434")] -impl StructuralEq for char {} +marker_impls! { + #[unstable(feature = "structural_match", issue = "31434")] + StructuralEq for + usize, u8, u16, u32, u64, u128, + isize, i8, i16, i32, i64, i128, + bool, + char, +} /// Types whose values can be duplicated simply by copying bits. /// @@ -430,6 +464,30 @@ pub macro Copy($item:item) { /* compiler built-in */ } +// Implementations of `Copy` for primitive types. +// +// Implementations that cannot be described in Rust +// are implemented in `traits::SelectionContext::copy_clone_conditions()` +// in `rustc_trait_selection`. +marker_impls! { + #[stable(feature = "rust1", since = "1.0.0")] + Copy for + usize, u8, u16, u32, u64, u128, + isize, i8, i16, i32, i64, i128, + f32, f64, + bool, char, + {T: ?Sized} *const T, + {T: ?Sized} *mut T, + +} + +#[unstable(feature = "never_type", issue = "35121")] +impl Copy for ! {} + +/// Shared references can be copied, but mutable references *cannot*! +#[stable(feature = "rust1", since = "1.0.0")] +impl Copy for &T {} + /// Types for which it is safe to share references between threads. /// /// This trait is automatically implemented when the compiler determines @@ -802,11 +860,14 @@ pub trait DiscriminantKind { pub(crate) unsafe auto trait Freeze {} impl !Freeze for UnsafeCell {} -unsafe impl Freeze for PhantomData {} -unsafe impl Freeze for *const T {} -unsafe impl Freeze for *mut T {} -unsafe impl Freeze for &T {} -unsafe impl Freeze for &mut T {} +marker_impls! { + unsafe Freeze for + {T: ?Sized} PhantomData, + {T: ?Sized} *const T, + {T: ?Sized} *mut T, + {T: ?Sized} &T, + {T: ?Sized} &mut T, +} /// Types that can be safely moved after being pinned. /// @@ -867,17 +928,19 @@ pub struct PhantomPinned; #[stable(feature = "pin", since = "1.33.0")] impl !Unpin for PhantomPinned {} -#[stable(feature = "pin", since = "1.33.0")] -impl<'a, T: ?Sized + 'a> Unpin for &'a T {} +marker_impls! { + #[stable(feature = "pin", since = "1.33.0")] + Unpin for + {T: ?Sized} &T, + {T: ?Sized} &mut T, +} -#[stable(feature = "pin", since = "1.33.0")] -impl<'a, T: ?Sized + 'a> Unpin for &'a mut T {} - -#[stable(feature = "pin_raw", since = "1.38.0")] -impl Unpin for *const T {} - -#[stable(feature = "pin_raw", since = "1.38.0")] -impl Unpin for *mut T {} +marker_impls! { + #[stable(feature = "pin_raw", since = "1.38.0")] + Unpin for + {T: ?Sized} *const T, + {T: ?Sized} *mut T, +} /// A marker for types that can be dropped. /// @@ -917,72 +980,14 @@ pub trait PointerLike {} #[unstable(feature = "adt_const_params", issue = "95174")] #[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] pub trait ConstParamTy: StructuralEq {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for usize {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for u8 {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for u16 {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for u32 {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for u64 {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for u128 {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for isize {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for i8 {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for i16 {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for i32 {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for i64 {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for i128 {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for bool {} -#[unstable(feature = "adt_const_params", issue = "95174")] -impl ConstParamTy for char {} -/// Implementations of `Copy` for primitive types. -/// -/// Implementations that cannot be described in Rust -/// are implemented in `traits::SelectionContext::copy_clone_conditions()` -/// in `rustc_trait_selection`. -mod copy_impls { - - use super::Copy; - - macro_rules! impl_copy { - ($($t:ty)*) => { - $( - #[stable(feature = "rust1", since = "1.0.0")] - impl Copy for $t {} - )* - } - } - - impl_copy! { - usize u8 u16 u32 u64 u128 - isize i8 i16 i32 i64 i128 - f32 f64 - bool char - } - - #[unstable(feature = "never_type", issue = "35121")] - impl Copy for ! {} - - #[stable(feature = "rust1", since = "1.0.0")] - impl Copy for *const T {} - - #[stable(feature = "rust1", since = "1.0.0")] - impl Copy for *mut T {} - - /// Shared references can be copied, but mutable references *cannot*! - #[stable(feature = "rust1", since = "1.0.0")] - impl Copy for &T {} +marker_impls! { + #[unstable(feature = "adt_const_params", issue = "95174")] + ConstParamTy for + usize, u8, u16, u32, u64, u128, + isize, i8, i16, i32, i64, i128, + bool, + char, } /// A common trait implemented by all function pointers. From 1bf6bbb1bd199956d1be3d8988f0d8b6036cd2e3 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 3 Mar 2023 18:02:11 +0000 Subject: [PATCH 09/17] Impl `StructuralEq` & `ConstParamTy` for `str`, `&T`, `[T; N]` and `[T]` --- compiler/rustc_trait_selection/src/traits/misc.rs | 9 ++++++++- library/core/src/marker.rs | 9 +++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index cb8f64dd2e8..2210ef975e6 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -93,7 +93,14 @@ pub fn type_allowed_to_implement_const_param_ty<'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::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Char + | ty::Str + | ty::Array(..) + | ty::Slice(_) + | ty::Ref(.., hir::Mutability::Not) => return Ok(()), &ty::Adt(adt, substs) => (adt, substs), diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 8c240661b2b..2f9138c56f2 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -268,6 +268,7 @@ pub trait StructuralEq { // Empty. } +// FIXME: Remove special cases of these types from the compiler pattern checking code and always check `T: StructuralEq` instead marker_impls! { #[unstable(feature = "structural_match", issue = "31434")] StructuralEq for @@ -275,6 +276,10 @@ marker_impls! { isize, i8, i16, i32, i64, i128, bool, char, + str /* Technically requires `[u8]: StructuralEq` */, + {T: ConstParamTy, const N: usize} [T; N], + {T: ConstParamTy} [T], + {T: ConstParamTy} &T, } /// Types whose values can be duplicated simply by copying bits. @@ -988,6 +993,10 @@ marker_impls! { isize, i8, i16, i32, i64, i128, bool, char, + str /* Technically requires `[u8]: ConstParamTy` */, + {T: ConstParamTy, const N: usize} [T; N], + {T: ConstParamTy} [T], + {T: ConstParamTy} &T, } /// A common trait implemented by all function pointers. From 2c5e7160f30a13f1f32c7d41075515ffbc6012cf Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 3 Mar 2023 18:09:49 +0000 Subject: [PATCH 10/17] Add FIXMEs --- library/core/src/marker.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 2f9138c56f2..47b431e93b0 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -986,6 +986,8 @@ pub trait PointerLike {} #[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] pub trait ConstParamTy: StructuralEq {} +// FIXME(generic_const_parameter_types): handle `ty::FnDef`/`ty::Closure` +// FIXME(generic_const_parameter_types): handle `ty::Tuple` marker_impls! { #[unstable(feature = "adt_const_params", issue = "95174")] ConstParamTy for From 51355ad92b6a98a38e72f4e1c168abd494b59160 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 3 Mar 2023 18:20:17 +0000 Subject: [PATCH 11/17] Add a test for `[NotParam; 0]: ConstParamTy` (not holding) --- .../const_param_ty_bad_empty_array.rs | 12 ++++++++++++ .../const_param_ty_bad_empty_array.stderr | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs new file mode 100644 index 00000000000..b0e3b13cc1e --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs @@ -0,0 +1,12 @@ +#![allow(incomplete_features)] +#![feature(adt_const_params)] + +#[derive(PartialEq, Eq)] +struct NotParam; + +fn check() {} + +fn main() { + check::<[NotParam; 0]>(); + //~^ error: `NotParam` can't be used as a const parameter type +} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr new file mode 100644 index 00000000000..ef55242df87 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr @@ -0,0 +1,16 @@ +error[E0277]: `NotParam` can't be used as a const parameter type + --> $DIR/const_param_ty_bad_empty_array.rs:10:13 + | +LL | check::<[NotParam; 0]>(); + | ^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam` + | + = note: required for `[NotParam; 0]` to implement `ConstParamTy` +note: required by a bound in `check` + --> $DIR/const_param_ty_bad_empty_array.rs:7:13 + | +LL | fn check() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From bdb5502aa862e22cec579eb845df4bfe42612cfd Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 3 Mar 2023 18:35:57 +0000 Subject: [PATCH 12/17] Fix some marker impls --- library/core/src/marker.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 47b431e93b0..a1cad6e9992 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -277,9 +277,9 @@ marker_impls! { bool, char, str /* Technically requires `[u8]: StructuralEq` */, - {T: ConstParamTy, const N: usize} [T; N], - {T: ConstParamTy} [T], - {T: ConstParamTy} &T, + {T: StructuralEq, const N: usize} [T; N], + {T: StructuralEq} [T], + {T: ?Sized + StructuralEq} &T, } /// Types whose values can be duplicated simply by copying bits. @@ -998,7 +998,7 @@ marker_impls! { str /* Technically requires `[u8]: ConstParamTy` */, {T: ConstParamTy, const N: usize} [T; N], {T: ConstParamTy} [T], - {T: ConstParamTy} &T, + {T: ?Sized + ConstParamTy} &T, } /// A common trait implemented by all function pointers. From 26417a85e7551115146f98c64ea4e433453b9b4b Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 3 Mar 2023 18:52:49 +0000 Subject: [PATCH 13/17] Add `ConstParamTy` tests --- .../adt_const_params/const_param_ty_bad.rs | 13 +++ .../const_param_ty_bad.stderr | 87 +++++++++++++++++++ ...nst_param_ty_generic_bounds_do_not_hold.rs | 13 +++ ...param_ty_generic_bounds_do_not_hold.stderr | 42 +++++++++ .../adt_const_params/const_param_ty_good.rs | 43 +++++++++ 5 files changed, 198 insertions(+) create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr create mode 100644 tests/ui/const-generics/adt_const_params/const_param_ty_good.rs diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs new file mode 100644 index 00000000000..a9ade9d838c --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs @@ -0,0 +1,13 @@ +#![allow(incomplete_features)] +#![feature(adt_const_params)] + +fn check(_: impl std::marker::ConstParamTy) {} + +fn main() { + check(main); //~ error: `fn() {main}` can't be used as a const parameter type + check(|| {}); //~ error: `[closure@fake-test-src-base/const-generics/adt_const_params/const_param_ty_bad.rs:8:11: 8:13]` can't be used as a const parameter type + check(main as fn()); //~ error: `fn()` can't be used as a const parameter type + check(&mut ()); //~ error: `&mut ()` can't be used as a const parameter type + check(&mut () as *mut ()); //~ error: `*mut ()` can't be used as a const parameter type + check(&() as *const ()); //~ error: `*const ()` can't be used as a const parameter type +} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr new file mode 100644 index 00000000000..de5704ee429 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr @@ -0,0 +1,87 @@ +error[E0277]: `fn() {main}` can't be used as a const parameter type + --> $DIR/const_param_ty_bad.rs:7:11 + | +LL | check(main); + | ----- ^^^^ the trait `ConstParamTy` is not implemented for fn item `fn() {main}` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check` + --> $DIR/const_param_ty_bad.rs:4:18 + | +LL | fn check(_: impl std::marker::ConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error[E0277]: `[closure@$DIR/const_param_ty_bad.rs:8:11: 8:13]` can't be used as a const parameter type + --> $DIR/const_param_ty_bad.rs:8:11 + | +LL | check(|| {}); + | ----- ^^^^^ the trait `ConstParamTy` is not implemented for closure `[closure@$DIR/const_param_ty_bad.rs:8:11: 8:13]` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check` + --> $DIR/const_param_ty_bad.rs:4:18 + | +LL | fn check(_: impl std::marker::ConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error[E0277]: `fn()` can't be used as a const parameter type + --> $DIR/const_param_ty_bad.rs:9:11 + | +LL | check(main as fn()); + | ----- ^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `fn()` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check` + --> $DIR/const_param_ty_bad.rs:4:18 + | +LL | fn check(_: impl std::marker::ConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error[E0277]: `&mut ()` can't be used as a const parameter type + --> $DIR/const_param_ty_bad.rs:10:11 + | +LL | check(&mut ()); + | ----- ^^^^^^^ the trait `ConstParamTy` is not implemented for `&mut ()` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check` + --> $DIR/const_param_ty_bad.rs:4:18 + | +LL | fn check(_: impl std::marker::ConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error[E0277]: `*mut ()` can't be used as a const parameter type + --> $DIR/const_param_ty_bad.rs:11:11 + | +LL | check(&mut () as *mut ()); + | ----- ^^^^^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `*mut ()` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check` + --> $DIR/const_param_ty_bad.rs:4:18 + | +LL | fn check(_: impl std::marker::ConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error[E0277]: `*const ()` can't be used as a const parameter type + --> $DIR/const_param_ty_bad.rs:12:11 + | +LL | check(&() as *const ()); + | ----- ^^^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `*const ()` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check` + --> $DIR/const_param_ty_bad.rs:4:18 + | +LL | fn check(_: impl std::marker::ConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs new file mode 100644 index 00000000000..e4dc76703a2 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs @@ -0,0 +1,13 @@ +#![allow(incomplete_features)] +#![feature(adt_const_params)] + +#[derive(PartialEq, Eq)] +struct NotParam; + +fn check() {} + +fn main() { + check::<&NotParam>(); //~ error: `NotParam` can't be used as a const parameter type + check::<[NotParam]>(); //~ error: `NotParam` can't be used as a const parameter type + check::<[NotParam; 17]>(); //~ error: `NotParam` can't be used as a const parameter type +} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr new file mode 100644 index 00000000000..86d1c94e87f --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr @@ -0,0 +1,42 @@ +error[E0277]: `NotParam` can't be used as a const parameter type + --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:10:13 + | +LL | check::<&NotParam>(); + | ^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam` + | + = note: required for `&NotParam` to implement `ConstParamTy` +note: required by a bound in `check` + --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 + | +LL | fn check() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error[E0277]: `NotParam` can't be used as a const parameter type + --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:11:13 + | +LL | check::<[NotParam]>(); + | ^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam` + | + = note: required for `[NotParam]` to implement `ConstParamTy` +note: required by a bound in `check` + --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 + | +LL | fn check() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error[E0277]: `NotParam` can't be used as a const parameter type + --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:12:13 + | +LL | check::<[NotParam; 17]>(); + | ^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam` + | + = note: required for `[NotParam; 17]` to implement `ConstParamTy` +note: required by a bound in `check` + --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 + | +LL | fn check() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs new file mode 100644 index 00000000000..a1b711a3024 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs @@ -0,0 +1,43 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(adt_const_params)] +use std::marker::ConstParamTy; + +#[derive(PartialEq, Eq)] +struct S { + field: u8, + gen: T, +} + +impl ConstParamTy for S {} + +fn check() {} + +fn main() { + check::(); + check::(); + check::(); + check::(); + check::(); + + check::(); + check::(); + check::(); + check::(); + check::(); + + check::(); + check::(); + check::(); + + check::<&u8>(); + check::<&str>(); + check::<[usize]>(); + check::<[u16; 0]>(); + check::<[u8; 42]>(); + + check::>(); + check::>(); + + // FIXME: test tuples +} From 2f70d02df46916a56f15ef52b13a99c3a69fbd5b Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 27 Apr 2023 17:25:51 +0000 Subject: [PATCH 14/17] Fix compile test so it normalizes (un)expected error messages --- src/tools/compiletest/src/runtest.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f6597c72938..514b96ce852 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1384,7 +1384,9 @@ impl<'test> TestCx<'test> { let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res); let mut unexpected = Vec::new(); let mut found = vec![false; expected_errors.len()]; - for actual_error in &actual_errors { + for mut actual_error in actual_errors { + actual_error.msg = self.normalize_output(&actual_error.msg, &[]); + let opt_index = expected_errors.iter().enumerate().position(|(index, expected_error)| { !found[index] @@ -1403,7 +1405,8 @@ impl<'test> TestCx<'test> { None => { // If the test is a known bug, don't require that the error is annotated - if self.is_unexpected_compiler_message(actual_error, expect_help, expect_note) { + if self.is_unexpected_compiler_message(&actual_error, expect_help, expect_note) + { self.error(&format!( "{}:{}: unexpected {}: '{}'", file_name, From 1f44a24e725bd2fdeccfb91b0daa51788ac761f1 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 27 Apr 2023 17:26:59 +0000 Subject: [PATCH 15/17] --bless `ConstParamTy` ui tests --- tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs | 2 +- .../adt_const_params/const_param_ty_impl_bad_field.rs | 2 +- .../adt_const_params/const_param_ty_impl_bad_field.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs index a9ade9d838c..0da68ae7573 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs @@ -5,7 +5,7 @@ fn check(_: impl std::marker::ConstParamTy) {} fn main() { check(main); //~ error: `fn() {main}` can't be used as a const parameter type - check(|| {}); //~ error: `[closure@fake-test-src-base/const-generics/adt_const_params/const_param_ty_bad.rs:8:11: 8:13]` can't be used as a const parameter type + check(|| {}); //~ error: `[closure@$DIR/const_param_ty_bad.rs:8:11: 8:13]` can't be used as a const parameter type check(main as fn()); //~ error: `fn()` can't be used as a const parameter type check(&mut ()); //~ error: `&mut ()` can't be used as a const parameter type check(&mut () as *mut ()); //~ error: `*mut ()` can't be used as a const parameter type diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs index 3d2d99b9d38..07fd243737e 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs @@ -8,6 +8,6 @@ struct NotParam; struct CantParam(NotParam); impl std::marker::ConstParamTy for CantParam {} -//~^ error: the trait `ConstParamTy` may not be implemented for this type +//~^ error: the trait `ConstParamTy` cannot be implemented for this type fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr index 5cd5cae6d79..c8e065848b1 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr @@ -1,4 +1,4 @@ -error[E0204]: the trait `ConstParamTy` may not be implemented for this type +error[E0204]: the trait `ConstParamTy` cannot be implemented for this type --> $DIR/const_param_ty_impl_bad_field.rs:10:36 | LL | struct CantParam(NotParam); From 182eee298c05b7259c98209a3d9a87ecac484040 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 28 Apr 2023 11:56:02 +0000 Subject: [PATCH 16/17] fixup tests wrt new normalization --- tests/ui/const-generics/nested-type.rs | 6 +++++- tests/ui/fmt/format-string-error.rs | 2 +- tests/ui/parser/issues/issue-62913.rs | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/ui/const-generics/nested-type.rs b/tests/ui/const-generics/nested-type.rs index 5240f5c3b0b..ff95018065a 100644 --- a/tests/ui/const-generics/nested-type.rs +++ b/tests/ui/const-generics/nested-type.rs @@ -3,7 +3,7 @@ #![cfg_attr(full, feature(adt_const_params))] #![cfg_attr(full, allow(incomplete_features))] -struct Foo; impl Foo { @@ -15,5 +15,9 @@ struct Foo::value() //~^ ERROR cannot call non-const fn }]>; +//[min]~^^^^^^^^^^^^ ERROR `[u8; { + +// N.B. it is important that the comment above is not inside the array length, +// otherwise it may check for itself, instead of the actual error fn main() {} diff --git a/tests/ui/fmt/format-string-error.rs b/tests/ui/fmt/format-string-error.rs index eae4f3cb547..9b436e2c479 100644 --- a/tests/ui/fmt/format-string-error.rs +++ b/tests/ui/fmt/format-string-error.rs @@ -17,7 +17,7 @@ fn main() { let _ = format!("}"); //~^ ERROR invalid format string: unmatched `}` found let _ = format!("{\\}"); - //~^ ERROR invalid format string: expected `'}'`, found `'\\'` + //~^ ERROR invalid format string: expected `'}'`, found `'\'` let _ = format!("\n\n\n{\n\n\n"); //~^ ERROR invalid format string let _ = format!(r###" diff --git a/tests/ui/parser/issues/issue-62913.rs b/tests/ui/parser/issues/issue-62913.rs index 0db06f636c3..a55ef5ac710 100644 --- a/tests/ui/parser/issues/issue-62913.rs +++ b/tests/ui/parser/issues/issue-62913.rs @@ -1,4 +1,4 @@ "\u\\" //~^ ERROR incorrect unicode escape sequence //~| ERROR invalid trailing slash in literal -//~| ERROR expected item, found `"\u\\"` +//~| ERROR expected item, found `"\u\"` From c31754651da17b207fa7fb94c2f3ba2c188aa0b1 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 1 May 2023 11:45:51 +0000 Subject: [PATCH 17/17] Fix `StructuralEq` impls for `&T`, `[T]` and `[T; N]` (`StructuralEq` is shallow for some reason...) --- library/core/src/marker.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index a1cad6e9992..2ebe42aef21 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -277,9 +277,9 @@ marker_impls! { bool, char, str /* Technically requires `[u8]: StructuralEq` */, - {T: StructuralEq, const N: usize} [T; N], - {T: StructuralEq} [T], - {T: ?Sized + StructuralEq} &T, + {T, const N: usize} [T; N], + {T} [T], + {T: ?Sized} &T, } /// Types whose values can be duplicated simply by copying bits.