Forbid !Sized
types and references
This commit is contained in:
parent
cb12b52f16
commit
42cc42b942
7 changed files with 167 additions and 39 deletions
|
@ -339,8 +339,8 @@ declare_features! (
|
||||||
(unstable, abi_riscv_interrupt, "1.73.0", Some(111889)),
|
(unstable, abi_riscv_interrupt, "1.73.0", Some(111889)),
|
||||||
/// Allows `extern "x86-interrupt" fn()`.
|
/// Allows `extern "x86-interrupt" fn()`.
|
||||||
(unstable, abi_x86_interrupt, "1.17.0", Some(40180)),
|
(unstable, abi_x86_interrupt, "1.17.0", Some(40180)),
|
||||||
/// Allows additional const parameter types, such as `&'static str` or user defined types
|
/// Allows additional const parameter types, such as `[u8; 10]` or user defined types
|
||||||
(incomplete, adt_const_params, "1.56.0", Some(95174)),
|
(unstable, adt_const_params, "1.56.0", Some(95174)),
|
||||||
/// Allows defining an `#[alloc_error_handler]`.
|
/// Allows defining an `#[alloc_error_handler]`.
|
||||||
(unstable, alloc_error_handler, "1.29.0", Some(51540)),
|
(unstable, alloc_error_handler, "1.29.0", Some(51540)),
|
||||||
/// Allows trait methods with arbitrary self types.
|
/// Allows trait methods with arbitrary self types.
|
||||||
|
|
|
@ -78,6 +78,10 @@ hir_analysis_const_impl_for_non_const_trait =
|
||||||
.note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
|
.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
|
.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 =
|
hir_analysis_const_param_ty_impl_on_non_adt =
|
||||||
the trait `ConstParamTy` may not be implemented for this type
|
the trait `ConstParamTy` may not be implemented for this type
|
||||||
.label = type is not a structure or enumeration
|
.label = type is not a structure or enumeration
|
||||||
|
|
|
@ -924,8 +924,6 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
|
||||||
|
|
||||||
if tcx.features().adt_const_params {
|
if tcx.features().adt_const_params {
|
||||||
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
|
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
|
||||||
let trait_def_id =
|
|
||||||
tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span));
|
|
||||||
wfcx.register_bound(
|
wfcx.register_bound(
|
||||||
ObligationCause::new(
|
ObligationCause::new(
|
||||||
hir_ty.span,
|
hir_ty.span,
|
||||||
|
@ -934,7 +932,13 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
|
||||||
),
|
),
|
||||||
wfcx.param_env,
|
wfcx.param_env,
|
||||||
ty,
|
ty,
|
||||||
trait_def_id,
|
tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)),
|
||||||
|
);
|
||||||
|
wfcx.register_bound(
|
||||||
|
ObligationCause::new(hir_ty.span, param.def_id, ObligationCauseCode::Misc),
|
||||||
|
wfcx.param_env,
|
||||||
|
ty,
|
||||||
|
tcx.require_lang_item(LangItem::Sized, Some(hir_ty.span)),
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -965,7 +969,11 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
|
||||||
cause,
|
cause,
|
||||||
) {
|
) {
|
||||||
// Can never implement `ConstParamTy`, don't suggest anything.
|
// Can never implement `ConstParamTy`, don't suggest anything.
|
||||||
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false,
|
Err(
|
||||||
|
ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed
|
||||||
|
| ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(..)
|
||||||
|
| ConstParamTyImplementationError::TypeNotSized,
|
||||||
|
) => false,
|
||||||
// May be able to implement `ConstParamTy`. Only emit the feature help
|
// 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.
|
// if the type is local, since the user may be able to fix the local type.
|
||||||
Err(ConstParamTyImplementationError::InfrigingFields(..)) => {
|
Err(ConstParamTyImplementationError::InfrigingFields(..)) => {
|
||||||
|
|
|
@ -103,7 +103,13 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(CopyImplementationError::InfringingFields(fields)) => {
|
Err(CopyImplementationError::InfringingFields(fields)) => {
|
||||||
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
|
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
|
||||||
Err(infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span))
|
Err(infringing_fields_error(
|
||||||
|
tcx,
|
||||||
|
fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
|
||||||
|
LangItem::Copy,
|
||||||
|
impl_did,
|
||||||
|
span,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
Err(CopyImplementationError::NotAnAdt) => {
|
Err(CopyImplementationError::NotAnAdt) => {
|
||||||
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
|
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
|
||||||
|
@ -125,7 +131,7 @@ fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), E
|
||||||
|
|
||||||
let param_env = tcx.param_env(impl_did);
|
let param_env = tcx.param_env(impl_did);
|
||||||
|
|
||||||
if let ty::ImplPolarity::Negative = header.polarity {
|
if let ty::ImplPolarity::Negative | ty::ImplPolarity::Reservation = header.polarity {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,12 +140,32 @@ fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), E
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
|
Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
|
||||||
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
|
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
|
||||||
Err(infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span))
|
Err(infringing_fields_error(
|
||||||
|
tcx,
|
||||||
|
fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
|
||||||
|
LangItem::ConstParamTy,
|
||||||
|
impl_did,
|
||||||
|
span,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
|
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
|
||||||
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
|
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
|
||||||
Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
|
Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
|
||||||
}
|
}
|
||||||
|
Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => {
|
||||||
|
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
|
||||||
|
Err(infringing_fields_error(
|
||||||
|
tcx,
|
||||||
|
infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)),
|
||||||
|
LangItem::ConstParamTy,
|
||||||
|
impl_did,
|
||||||
|
span,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
Err(ConstParamTyImplementationError::TypeNotSized) => {
|
||||||
|
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
|
||||||
|
Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,9 +527,9 @@ pub fn coerce_unsized_info<'tcx>(
|
||||||
Ok(CoerceUnsizedInfo { custom_kind: kind })
|
Ok(CoerceUnsizedInfo { custom_kind: kind })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infringing_fields_error(
|
fn infringing_fields_error<'tcx>(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'tcx>,
|
||||||
fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>,
|
infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
|
||||||
lang_item: LangItem,
|
lang_item: LangItem,
|
||||||
impl_did: LocalDefId,
|
impl_did: LocalDefId,
|
||||||
impl_span: Span,
|
impl_span: Span,
|
||||||
|
@ -521,13 +547,13 @@ fn infringing_fields_error(
|
||||||
|
|
||||||
let mut label_spans = Vec::new();
|
let mut label_spans = Vec::new();
|
||||||
|
|
||||||
for (field, ty, reason) in fields {
|
for (span, ty, reason) in infringing_tys {
|
||||||
// Only report an error once per type.
|
// Only report an error once per type.
|
||||||
if !seen_tys.insert(ty) {
|
if !seen_tys.insert(ty) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
label_spans.push(tcx.def_span(field.did));
|
label_spans.push(span);
|
||||||
|
|
||||||
match reason {
|
match reason {
|
||||||
InfringingFieldsReason::Fulfill(fulfillment_errors) => {
|
InfringingFieldsReason::Fulfill(fulfillment_errors) => {
|
||||||
|
|
|
@ -278,6 +278,14 @@ pub struct CopyImplOnNonAdt {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis_const_param_ty_impl_on_unsized)]
|
||||||
|
pub struct ConstParamTyImplOnUnsized {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis_const_param_ty_impl_on_non_adt)]
|
#[diag(hir_analysis_const_param_ty_impl_on_non_adt)]
|
||||||
pub struct ConstParamTyImplOnNonAdt {
|
pub struct ConstParamTyImplOnNonAdt {
|
||||||
|
|
|
@ -19,6 +19,8 @@ pub enum CopyImplementationError<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ConstParamTyImplementationError<'tcx> {
|
pub enum ConstParamTyImplementationError<'tcx> {
|
||||||
|
TypeNotSized,
|
||||||
|
InvalidInnerTyOfBuiltinTy(Vec<(Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
|
||||||
InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
|
InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
|
||||||
NotAnAdtOrBuiltinAllowed,
|
NotAnAdtOrBuiltinAllowed,
|
||||||
}
|
}
|
||||||
|
@ -89,34 +91,105 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
|
||||||
self_type: Ty<'tcx>,
|
self_type: Ty<'tcx>,
|
||||||
parent_cause: ObligationCause<'tcx>,
|
parent_cause: ObligationCause<'tcx>,
|
||||||
) -> Result<(), ConstParamTyImplementationError<'tcx>> {
|
) -> Result<(), ConstParamTyImplementationError<'tcx>> {
|
||||||
let (adt, args) = match self_type.kind() {
|
{
|
||||||
// `core` provides these impls.
|
// Check for sizedness before recursing into ADT fields so that if someone tries to write:
|
||||||
ty::Uint(_)
|
// ```rust
|
||||||
| ty::Int(_)
|
// #[derive(ConstParamTy)]
|
||||||
| ty::Bool
|
// struct Foo([u8])
|
||||||
| ty::Char
|
// ```
|
||||||
| ty::Str
|
// They are told that const parameter types must be sized, instead of it saying that
|
||||||
| ty::Array(..)
|
// the trait implementation `[u8]: ConstParamTy` is not satisfied.
|
||||||
| ty::Slice(_)
|
let infcx = tcx.infer_ctxt().build();
|
||||||
| ty::Ref(.., hir::Mutability::Not)
|
let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
|
||||||
| ty::Tuple(_) => return Ok(()),
|
|
||||||
|
|
||||||
&ty::Adt(adt, args) => (adt, args),
|
ocx.register_bound(
|
||||||
|
parent_cause.clone(),
|
||||||
|
param_env,
|
||||||
|
self_type,
|
||||||
|
tcx.require_lang_item(LangItem::Sized, Some(parent_cause.span)),
|
||||||
|
);
|
||||||
|
|
||||||
_ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
|
if !ocx.select_all_or_error().is_empty() {
|
||||||
|
return Err(ConstParamTyImplementationError::TypeNotSized);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let inner_tys: Vec<_> = match *self_type.kind() {
|
||||||
|
// Trivially okay as these types are all:
|
||||||
|
// - Sized
|
||||||
|
// - Contain no nested types
|
||||||
|
// - Have structural equality
|
||||||
|
ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => return Ok(()),
|
||||||
|
|
||||||
|
ty::Ref(..) => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
|
||||||
|
|
||||||
|
// 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() => {
|
||||||
all_fields_implement_trait(
|
all_fields_implement_trait(
|
||||||
tcx,
|
tcx,
|
||||||
param_env,
|
param_env,
|
||||||
self_type,
|
self_type,
|
||||||
adt,
|
adt,
|
||||||
args,
|
args,
|
||||||
parent_cause,
|
parent_cause.clone(),
|
||||||
hir::LangItem::ConstParamTy,
|
hir::LangItem::ConstParamTy,
|
||||||
)
|
)
|
||||||
.map_err(ConstParamTyImplementationError::InfrigingFields)?;
|
.map_err(ConstParamTyImplementationError::InfrigingFields)?;
|
||||||
|
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut infringing_inner_tys = vec![];
|
||||||
|
for inner_ty in inner_tys {
|
||||||
|
// We use an ocx per inner ty for better diagnostics
|
||||||
|
let infcx = tcx.infer_ctxt().build();
|
||||||
|
let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
|
||||||
|
|
||||||
|
ocx.register_bound(
|
||||||
|
parent_cause.clone(),
|
||||||
|
param_env,
|
||||||
|
inner_ty,
|
||||||
|
tcx.require_lang_item(LangItem::ConstParamTy, Some(parent_cause.span)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let errors = ocx.select_all_or_error();
|
||||||
|
if !errors.is_empty() {
|
||||||
|
infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Fulfill(errors)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check regions assuming the self type of the impl is WF
|
||||||
|
let outlives_env = OutlivesEnvironment::with_bounds(
|
||||||
|
param_env,
|
||||||
|
infcx.implied_bounds_tys(
|
||||||
|
param_env,
|
||||||
|
parent_cause.body_id,
|
||||||
|
&FxIndexSet::from_iter([self_type]),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let errors = infcx.resolve_regions(&outlives_env);
|
||||||
|
if !errors.is_empty() {
|
||||||
|
infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Regions(errors)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !infringing_inner_tys.is_empty() {
|
||||||
|
return Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(
|
||||||
|
infringing_inner_tys,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -995,13 +995,22 @@ marker_impls! {
|
||||||
isize, i8, i16, i32, i64, i128,
|
isize, i8, i16, i32, i64, i128,
|
||||||
bool,
|
bool,
|
||||||
char,
|
char,
|
||||||
str /* Technically requires `[u8]: ConstParamTy` */,
|
|
||||||
(),
|
(),
|
||||||
{T: ConstParamTy, const N: usize} [T; N],
|
{T: ConstParamTy, const N: usize} [T; N],
|
||||||
{T: ConstParamTy} [T],
|
|
||||||
{T: ?Sized + ConstParamTy} &T,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "adt_const_params", issue = "95174")]
|
||||||
|
#[rustc_reservation_impl = "types that are not `Sized` are not supported as the type of a const generic parameter"]
|
||||||
|
impl<T> ConstParamTy for [T] {}
|
||||||
|
|
||||||
|
#[unstable(feature = "adt_const_params", issue = "95174")]
|
||||||
|
#[rustc_reservation_impl = "types that are not `Sized` are not supported as the type of a const generic parameter"]
|
||||||
|
impl ConstParamTy for str {}
|
||||||
|
|
||||||
|
#[unstable(feature = "adt_const_params", issue = "95174")]
|
||||||
|
#[rustc_reservation_impl = "references are not supported as the type of a const generic parameter"]
|
||||||
|
impl<T: ?Sized> ConstParamTy for &T {}
|
||||||
|
|
||||||
/// A common trait implemented by all function pointers.
|
/// A common trait implemented by all function pointers.
|
||||||
#[unstable(
|
#[unstable(
|
||||||
feature = "fn_ptr_trait",
|
feature = "fn_ptr_trait",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue