Skip to content

Commit

Permalink
Split part of adt_const_params into unsized_const_params
Browse files Browse the repository at this point in the history
  • Loading branch information
BoxyUwU committed Jul 15, 2024
1 parent fd94759 commit 5a3ad51
Show file tree
Hide file tree
Showing 139 changed files with 1,115 additions and 553 deletions.
39 changes: 38 additions & 1 deletion compiler/rustc_builtin_macros/src/deriving/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,44 @@ pub(crate) fn expand_deriving_const_param_ty(
) {
let trait_def = TraitDef {
span,
path: path_std!(marker::ConstParamTy),
path: path_std!(marker::ConstParamTy_),
skip_path_as_bound: false,
needs_copy_as_bound_if_packed: false,
additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))],
supports_unions: false,
methods: Vec::new(),
associated_types: Vec::new(),
is_const,
};

trait_def.expand(cx, mitem, item, push);

let trait_def = TraitDef {
span,
path: path_std!(marker::UnsizedConstParamTy),
skip_path_as_bound: false,
needs_copy_as_bound_if_packed: false,
additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))],
supports_unions: false,
methods: Vec::new(),
associated_types: Vec::new(),
is_const,
};

trait_def.expand(cx, mitem, item, push);
}

pub(crate) fn expand_deriving_unsized_const_param_ty(
cx: &ExtCtxt<'_>,
span: Span,
mitem: &MetaItem,
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
is_const: bool,
) {
let trait_def = TraitDef {
span,
path: path_std!(marker::UnsizedConstParamTy),
skip_path_as_bound: false,
needs_copy_as_bound_if_packed: false,
additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))],
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
Clone: clone::expand_deriving_clone,
Copy: bounds::expand_deriving_copy,
ConstParamTy: bounds::expand_deriving_const_param_ty,
UnsizedConstParamTy: bounds::expand_deriving_unsized_const_param_ty,
Debug: debug::expand_deriving_debug,
Default: default::expand_deriving_default,
Eq: eq::expand_deriving_eq,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,9 @@ declare_features! (
(unstable, unsafe_attributes, "1.80.0", Some(123757)),
/// Allows unsafe on extern declarations and safety qualifiers over internal items.
(unstable, unsafe_extern_blocks, "1.80.0", Some(123743)),
/// Allows const generic parameters to be defined with types that
/// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`.
(incomplete, unsized_const_parameters, "CURRENT_RUSTC_VERSION", Some(95174)),
/// Allows unsized fn parameters.
(internal, unsized_fn_params, "1.49.0", Some(48055)),
/// Allows unsized rvalues at arguments and parameters.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ 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);
UnsizedConstParamTy, sym::unsized_const_param_ty, unsized_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;
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ 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_unsized =
the trait `ConstParamTy` may not be implemented for this type
.label = type is not `Sized`
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_const_param_ty_impl_on_unsized =
the trait `ConstParamTy` may not be implemented for this type
.label = type is not `Sized`
hir_analysis_const_specialize = cannot specialize on const impl with non-const impl
hir_analysis_copy_impl_on_non_adt =
Expand Down
51 changes: 33 additions & 18 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
} => {
let ty = tcx.type_of(param.def_id).instantiate_identity();

if tcx.features().adt_const_params {
if tcx.features().unsized_const_parameters {
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
wfcx.register_bound(
ObligationCause::new(
Expand All @@ -932,13 +932,21 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
),
wfcx.param_env,
ty,
tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)),
tcx.require_lang_item(LangItem::UnsizedConstParamTy, Some(hir_ty.span)),
);
Ok(())
})
} else if tcx.features().adt_const_params {
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
wfcx.register_bound(
ObligationCause::new(hir_ty.span, param.def_id, ObligationCauseCode::Misc),
ObligationCause::new(
hir_ty.span,
param.def_id,
ObligationCauseCode::ConstParam(ty),
),
wfcx.param_env,
ty,
tcx.require_lang_item(LangItem::Sized, Some(hir_ty.span)),
tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)),
);
Ok(())
})
Expand All @@ -962,18 +970,29 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
diag.note("the only supported types are integers, `bool` and `char`");

let cause = ObligationCause::misc(hir_ty.span, param.def_id);
let adt_const_params_feature_string =
" more complex and user defined types".to_string();
let may_suggest_feature = match type_allowed_to_implement_const_param_ty(
tcx,
tcx.param_env(param.def_id),
ty,
LangItem::ConstParamTy,
cause,
) {
// Can never implement `ConstParamTy`, don't suggest anything.
Err(
ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed
| ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(..)
| ConstParamTyImplementationError::TypeNotSized,
) => false,
| ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(..),
) => None,
Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {
Some(vec![
(adt_const_params_feature_string, sym::adt_const_params),
(
" references to implement the `ConstParamTy` trait".into(),
sym::unsized_const_parameters,
),
])
}
// May be able to implement `ConstParamTy`. Only emit the feature help
// if the type is local, since the user may be able to fix the local type.
Err(ConstParamTyImplementationError::InfrigingFields(..)) => {
Expand All @@ -993,20 +1012,16 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
}
}

ty_is_local(ty)
ty_is_local(ty).then_some(vec![(
adt_const_params_feature_string,
sym::adt_const_params,
)])
}
// Implments `ConstParamTy`, suggest adding the feature to enable.
Ok(..) => true,
Ok(..) => Some(vec![(adt_const_params_feature_string, sym::adt_const_params)]),
};
if may_suggest_feature {
tcx.disabled_nightly_features(
&mut diag,
Some(param.hir_id),
[(
" more complex and user defined types".to_string(),
sym::adt_const_params,
)],
);
if let Some(features) = may_suggest_feature {
tcx.disabled_nightly_features(&mut diag, Some(param.hir_id), features);
}

Err(diag.emit())
Expand Down
21 changes: 15 additions & 6 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,13 @@ pub(super) fn check_trait<'tcx>(
let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
res = res.and(
checker.check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty),
);
res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| {
visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
}));
res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
}));

res = res.and(
checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized),
);
Expand Down Expand Up @@ -122,7 +126,12 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
}
}

fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
fn visit_implementation_of_const_param_ty(
checker: &Checker<'_>,
kind: LangItem,
) -> Result<(), ErrorGuaranteed> {
assert!(matches!(kind, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy));

let tcx = checker.tcx;
let header = checker.impl_header;
let impl_did = checker.impl_def_id;
Expand All @@ -136,7 +145,7 @@ fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), E
}

let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, kind, cause) {
Ok(()) => Ok(()),
Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
Expand All @@ -162,7 +171,7 @@ fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), E
span,
))
}
Err(ConstParamTyImplementationError::TypeNotSized) => {
Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span }))
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ symbols! {
CoerceUnsized,
Command,
ConstParamTy,
ConstParamTy_,
Context,
Continue,
Copy,
Expand Down Expand Up @@ -336,6 +337,7 @@ symbols! {
TyKind,
Unknown,
Unsize,
UnsizedConstParamTy,
Upvars,
Vec,
VecDeque,
Expand Down Expand Up @@ -2000,6 +2002,8 @@ symbols! {
unsafe_no_drop_flag,
unsafe_pin_internals,
unsize,
unsized_const_param_ty,
unsized_const_parameters,
unsized_fn_params,
unsized_locals,
unsized_tuple_coercion,
Expand Down
56 changes: 23 additions & 33 deletions compiler/rustc_trait_selection/src/traits/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::regions::InferCtxtRegionExt;
use crate::traits::{self, FulfillmentError, ObligationCause};

use hir::LangItem;
use rustc_ast::Mutability;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
Expand All @@ -19,7 +20,7 @@ pub enum CopyImplementationError<'tcx> {
}

pub enum ConstParamTyImplementationError<'tcx> {
TypeNotSized,
UnsizedConstParamsFeatureRequired,
InvalidInnerTyOfBuiltinTy(Vec<(Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
NotAnAdtOrBuiltinAllowed,
Expand Down Expand Up @@ -79,40 +80,20 @@ pub fn type_allowed_to_implement_copy<'tcx>(
Ok(())
}

/// Checks that the fields of the type (an ADT) all implement `ConstParamTy`.
/// Checks that the fields of the type (an ADT) all implement `(Unsized?)ConstParamTy`.
///
/// If fields don't implement `ConstParamTy`, return an error containing a list of
/// If fields don't implement `(Unsized?)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>,
lang_item: LangItem,
parent_cause: ObligationCause<'tcx>,
) -> Result<(), ConstParamTyImplementationError<'tcx>> {
{
// Check for sizedness before recursing into ADT fields so that if someone tries to write:
// ```rust
// #[derive(ConstParamTy)]
// struct Foo([u8])
// ```
// They are told that const parameter types must be sized, instead of it saying that
// the trait implementation `[u8]: ConstParamTy` is not satisfied.
let infcx = tcx.infer_ctxt().build();
let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);

ocx.register_bound(
parent_cause.clone(),
param_env,
self_type,
tcx.require_lang_item(LangItem::Sized, Some(parent_cause.span)),
);

if !ocx.select_all_or_error().is_empty() {
return Err(ConstParamTyImplementationError::TypeNotSized);
}
};
assert!(matches!(lang_item, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy));

let inner_tys: Vec<_> = match *self_type.kind() {
// Trivially okay as these types are all:
Expand All @@ -121,14 +102,23 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
// - Have structural equality
ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => return Ok(()),

ty::Ref(..) => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
// Handle types gated under `feature(unsized_const_parameters)`
// FIXME(unsized_const_parameters): Make `const N: [u8]` work then forbid references
ty::Slice(inner_ty) | ty::Ref(_, inner_ty, Mutability::Not)
if lang_item == LangItem::UnsizedConstParamTy =>
{
vec![inner_ty]
}
ty::Str if lang_item == LangItem::UnsizedConstParamTy => {
vec![Ty::new_slice(tcx, tcx.types.u8)]
}
ty::Str | ty::Slice(..) | ty::Ref(_, _, Mutability::Not) => {
return Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired);
}

ty::Array(inner_ty, _) => vec![inner_ty],

// Even if we currently require const params to be `Sized` we may aswell handle them correctly
// here anyway.
ty::Slice(inner_ty) | ty::Array(inner_ty, _) => vec![inner_ty],
// `str` morally acts like a newtype around `[u8]`
ty::Str => vec![Ty::new_slice(tcx, tcx.types.u8)],

ty::Tuple(inner_tys) => inner_tys.into_iter().collect(),

ty::Adt(adt, args) if adt.is_enum() || adt.is_struct() => {
Expand All @@ -139,7 +129,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
adt,
args,
parent_cause.clone(),
hir::LangItem::ConstParamTy,
lang_item,
)
.map_err(ConstParamTyImplementationError::InfrigingFields)?;

Expand All @@ -159,7 +149,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
parent_cause.clone(),
param_env,
inner_ty,
tcx.require_lang_item(LangItem::ConstParamTy, Some(parent_cause.span)),
tcx.require_lang_item(lang_item, Some(parent_cause.span)),
);

let errors = ocx.select_all_or_error();
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@
#![feature(transparent_unions)]
#![feature(try_blocks)]
#![feature(unboxed_closures)]
#![feature(unsized_const_parameters)]
#![feature(unsized_fn_params)]
#![feature(with_negative_coherence)]
// tidy-alphabetical-end
Expand Down
Loading

0 comments on commit 5a3ad51

Please sign in to comment.