Skip to content

Commit 42cc42b

Browse files
committed
Forbid !Sized types and references
1 parent cb12b52 commit 42cc42b

File tree

7 files changed

+167
-39
lines changed

7 files changed

+167
-39
lines changed

compiler/rustc_feature/src/unstable.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,8 @@ declare_features! (
339339
(unstable, abi_riscv_interrupt, "1.73.0", Some(111889)),
340340
/// Allows `extern "x86-interrupt" fn()`.
341341
(unstable, abi_x86_interrupt, "1.17.0", Some(40180)),
342-
/// Allows additional const parameter types, such as `&'static str` or user defined types
343-
(incomplete, adt_const_params, "1.56.0", Some(95174)),
342+
/// Allows additional const parameter types, such as `[u8; 10]` or user defined types
343+
(unstable, adt_const_params, "1.56.0", Some(95174)),
344344
/// Allows defining an `#[alloc_error_handler]`.
345345
(unstable, alloc_error_handler, "1.29.0", Some(51540)),
346346
/// Allows trait methods with arbitrary self types.

compiler/rustc_hir_analysis/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ hir_analysis_const_impl_for_non_const_trait =
7878
.note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
7979
.adding = adding a non-const method body in the future would be a breaking change
8080
81+
hir_analysis_const_param_ty_impl_on_unsized =
82+
the trait `ConstParamTy` may not be implemented for this type
83+
.label = type is not `Sized`
84+
8185
hir_analysis_const_param_ty_impl_on_non_adt =
8286
the trait `ConstParamTy` may not be implemented for this type
8387
.label = type is not a structure or enumeration

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -924,8 +924,6 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
924924

925925
if tcx.features().adt_const_params {
926926
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
927-
let trait_def_id =
928-
tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span));
929927
wfcx.register_bound(
930928
ObligationCause::new(
931929
hir_ty.span,
@@ -934,7 +932,13 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
934932
),
935933
wfcx.param_env,
936934
ty,
937-
trait_def_id,
935+
tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)),
936+
);
937+
wfcx.register_bound(
938+
ObligationCause::new(hir_ty.span, param.def_id, ObligationCauseCode::Misc),
939+
wfcx.param_env,
940+
ty,
941+
tcx.require_lang_item(LangItem::Sized, Some(hir_ty.span)),
938942
);
939943
Ok(())
940944
})
@@ -965,7 +969,11 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
965969
cause,
966970
) {
967971
// Can never implement `ConstParamTy`, don't suggest anything.
968-
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false,
972+
Err(
973+
ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed
974+
| ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(..)
975+
| ConstParamTyImplementationError::TypeNotSized,
976+
) => false,
969977
// May be able to implement `ConstParamTy`. Only emit the feature help
970978
// if the type is local, since the user may be able to fix the local type.
971979
Err(ConstParamTyImplementationError::InfrigingFields(..)) => {

compiler/rustc_hir_analysis/src/coherence/builtin.rs

+34-8
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,13 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
103103
Ok(()) => Ok(()),
104104
Err(CopyImplementationError::InfringingFields(fields)) => {
105105
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
106-
Err(infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span))
106+
Err(infringing_fields_error(
107+
tcx,
108+
fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
109+
LangItem::Copy,
110+
impl_did,
111+
span,
112+
))
107113
}
108114
Err(CopyImplementationError::NotAnAdt) => {
109115
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
125131

126132
let param_env = tcx.param_env(impl_did);
127133

128-
if let ty::ImplPolarity::Negative = header.polarity {
134+
if let ty::ImplPolarity::Negative | ty::ImplPolarity::Reservation = header.polarity {
129135
return Ok(());
130136
}
131137

@@ -134,12 +140,32 @@ fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), E
134140
Ok(()) => Ok(()),
135141
Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
136142
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
137-
Err(infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span))
143+
Err(infringing_fields_error(
144+
tcx,
145+
fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
146+
LangItem::ConstParamTy,
147+
impl_did,
148+
span,
149+
))
138150
}
139151
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
140152
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
141153
Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
142154
}
155+
Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => {
156+
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
157+
Err(infringing_fields_error(
158+
tcx,
159+
infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)),
160+
LangItem::ConstParamTy,
161+
impl_did,
162+
span,
163+
))
164+
}
165+
Err(ConstParamTyImplementationError::TypeNotSized) => {
166+
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
167+
Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span }))
168+
}
143169
}
144170
}
145171

@@ -501,9 +527,9 @@ pub fn coerce_unsized_info<'tcx>(
501527
Ok(CoerceUnsizedInfo { custom_kind: kind })
502528
}
503529

504-
fn infringing_fields_error(
505-
tcx: TyCtxt<'_>,
506-
fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>,
530+
fn infringing_fields_error<'tcx>(
531+
tcx: TyCtxt<'tcx>,
532+
infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
507533
lang_item: LangItem,
508534
impl_did: LocalDefId,
509535
impl_span: Span,
@@ -521,13 +547,13 @@ fn infringing_fields_error(
521547

522548
let mut label_spans = Vec::new();
523549

524-
for (field, ty, reason) in fields {
550+
for (span, ty, reason) in infringing_tys {
525551
// Only report an error once per type.
526552
if !seen_tys.insert(ty) {
527553
continue;
528554
}
529555

530-
label_spans.push(tcx.def_span(field.did));
556+
label_spans.push(span);
531557

532558
match reason {
533559
InfringingFieldsReason::Fulfill(fulfillment_errors) => {

compiler/rustc_hir_analysis/src/errors.rs

+8
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,14 @@ pub struct CopyImplOnNonAdt {
278278
pub span: Span,
279279
}
280280

281+
#[derive(Diagnostic)]
282+
#[diag(hir_analysis_const_param_ty_impl_on_unsized)]
283+
pub struct ConstParamTyImplOnUnsized {
284+
#[primary_span]
285+
#[label]
286+
pub span: Span,
287+
}
288+
281289
#[derive(Diagnostic)]
282290
#[diag(hir_analysis_const_param_ty_impl_on_non_adt)]
283291
pub struct ConstParamTyImplOnNonAdt {

compiler/rustc_trait_selection/src/traits/misc.rs

+95-22
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ pub enum CopyImplementationError<'tcx> {
1919
}
2020

2121
pub enum ConstParamTyImplementationError<'tcx> {
22+
TypeNotSized,
23+
InvalidInnerTyOfBuiltinTy(Vec<(Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
2224
InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
2325
NotAnAdtOrBuiltinAllowed,
2426
}
@@ -89,33 +91,104 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
8991
self_type: Ty<'tcx>,
9092
parent_cause: ObligationCause<'tcx>,
9193
) -> Result<(), ConstParamTyImplementationError<'tcx>> {
92-
let (adt, args) = match self_type.kind() {
93-
// `core` provides these impls.
94-
ty::Uint(_)
95-
| ty::Int(_)
96-
| ty::Bool
97-
| ty::Char
98-
| ty::Str
99-
| ty::Array(..)
100-
| ty::Slice(_)
101-
| ty::Ref(.., hir::Mutability::Not)
102-
| ty::Tuple(_) => return Ok(()),
94+
{
95+
// Check for sizedness before recursing into ADT fields so that if someone tries to write:
96+
// ```rust
97+
// #[derive(ConstParamTy)]
98+
// struct Foo([u8])
99+
// ```
100+
// They are told that const parameter types must be sized, instead of it saying that
101+
// the trait implementation `[u8]: ConstParamTy` is not satisfied.
102+
let infcx = tcx.infer_ctxt().build();
103+
let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
103104

104-
&ty::Adt(adt, args) => (adt, args),
105+
ocx.register_bound(
106+
parent_cause.clone(),
107+
param_env,
108+
self_type,
109+
tcx.require_lang_item(LangItem::Sized, Some(parent_cause.span)),
110+
);
111+
112+
if !ocx.select_all_or_error().is_empty() {
113+
return Err(ConstParamTyImplementationError::TypeNotSized);
114+
}
115+
};
116+
117+
let inner_tys: Vec<_> = match *self_type.kind() {
118+
// Trivially okay as these types are all:
119+
// - Sized
120+
// - Contain no nested types
121+
// - Have structural equality
122+
ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => return Ok(()),
123+
124+
ty::Ref(..) => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
125+
126+
// Even if we currently require const params to be `Sized` we may aswell handle them correctly
127+
// here anyway.
128+
ty::Slice(inner_ty) | ty::Array(inner_ty, _) => vec![inner_ty],
129+
// `str` morally acts like a newtype around `[u8]`
130+
ty::Str => vec![Ty::new_slice(tcx, tcx.types.u8)],
131+
132+
ty::Tuple(inner_tys) => inner_tys.into_iter().collect(),
133+
134+
ty::Adt(adt, args) if adt.is_enum() || adt.is_struct() => {
135+
all_fields_implement_trait(
136+
tcx,
137+
param_env,
138+
self_type,
139+
adt,
140+
args,
141+
parent_cause.clone(),
142+
hir::LangItem::ConstParamTy,
143+
)
144+
.map_err(ConstParamTyImplementationError::InfrigingFields)?;
145+
146+
vec![]
147+
}
105148

106149
_ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
107150
};
108151

109-
all_fields_implement_trait(
110-
tcx,
111-
param_env,
112-
self_type,
113-
adt,
114-
args,
115-
parent_cause,
116-
hir::LangItem::ConstParamTy,
117-
)
118-
.map_err(ConstParamTyImplementationError::InfrigingFields)?;
152+
let mut infringing_inner_tys = vec![];
153+
for inner_ty in inner_tys {
154+
// We use an ocx per inner ty for better diagnostics
155+
let infcx = tcx.infer_ctxt().build();
156+
let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
157+
158+
ocx.register_bound(
159+
parent_cause.clone(),
160+
param_env,
161+
inner_ty,
162+
tcx.require_lang_item(LangItem::ConstParamTy, Some(parent_cause.span)),
163+
);
164+
165+
let errors = ocx.select_all_or_error();
166+
if !errors.is_empty() {
167+
infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Fulfill(errors)));
168+
continue;
169+
}
170+
171+
// Check regions assuming the self type of the impl is WF
172+
let outlives_env = OutlivesEnvironment::with_bounds(
173+
param_env,
174+
infcx.implied_bounds_tys(
175+
param_env,
176+
parent_cause.body_id,
177+
&FxIndexSet::from_iter([self_type]),
178+
),
179+
);
180+
let errors = infcx.resolve_regions(&outlives_env);
181+
if !errors.is_empty() {
182+
infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Regions(errors)));
183+
continue;
184+
}
185+
}
186+
187+
if !infringing_inner_tys.is_empty() {
188+
return Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(
189+
infringing_inner_tys,
190+
));
191+
}
119192

120193
Ok(())
121194
}

library/core/src/marker.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -995,13 +995,22 @@ marker_impls! {
995995
isize, i8, i16, i32, i64, i128,
996996
bool,
997997
char,
998-
str /* Technically requires `[u8]: ConstParamTy` */,
999998
(),
1000999
{T: ConstParamTy, const N: usize} [T; N],
1001-
{T: ConstParamTy} [T],
1002-
{T: ?Sized + ConstParamTy} &T,
10031000
}
10041001

1002+
#[unstable(feature = "adt_const_params", issue = "95174")]
1003+
#[rustc_reservation_impl = "types that are not `Sized` are not supported as the type of a const generic parameter"]
1004+
impl<T> ConstParamTy for [T] {}
1005+
1006+
#[unstable(feature = "adt_const_params", issue = "95174")]
1007+
#[rustc_reservation_impl = "types that are not `Sized` are not supported as the type of a const generic parameter"]
1008+
impl ConstParamTy for str {}
1009+
1010+
#[unstable(feature = "adt_const_params", issue = "95174")]
1011+
#[rustc_reservation_impl = "references are not supported as the type of a const generic parameter"]
1012+
impl<T: ?Sized> ConstParamTy for &T {}
1013+
10051014
/// A common trait implemented by all function pointers.
10061015
#[unstable(
10071016
feature = "fn_ptr_trait",

0 commit comments

Comments
 (0)