Skip to content

Commit 92c7a29

Browse files
committed
library/trait_sel: make {Meta,}Sized const
Makes `{Meta,}Sized` into const traits and implements them in the trait solvers so everything is `Sized` except ADTs with the `rustc_non_const_sized` attribute.
1 parent 42e770a commit 92c7a29

File tree

12 files changed

+240
-10
lines changed

12 files changed

+240
-10
lines changed

compiler/rustc_middle/src/ty/adt.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ bitflags::bitflags! {
5555
const IS_UNSAFE_CELL = 1 << 9;
5656
/// Indicates whether the type is anonymous.
5757
const IS_ANONYMOUS = 1 << 10;
58+
/// Indicates whether the type is annotated with `#[rustc_non_const_sized]`.
59+
///
60+
/// Necessary to know when to add a type flag since `TyCtxt` isn't available and the
61+
/// presence of the attribute cannot be checked.
62+
/// FIXME(sized-hierarchy): Consider removing this when scalable vectors are implemented
63+
/// and `def.repr.scalable` can be checked.
64+
const HAS_NON_CONST_SIZEDNESS = 1 << 11;
5865
}
5966
}
6067
rustc_data_structures::external_bitflags_debug! { AdtFlags }
@@ -287,6 +294,10 @@ impl AdtDefData {
287294
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
288295
}
289296

297+
if tcx.has_attr(did, sym::rustc_non_const_sized) {
298+
flags = flags | AdtFlags::HAS_NON_CONST_SIZEDNESS;
299+
}
300+
290301
flags |= match kind {
291302
AdtKind::Enum => AdtFlags::IS_ENUM,
292303
AdtKind::Union => AdtFlags::IS_UNION,
@@ -342,6 +353,12 @@ impl<'tcx> AdtDef<'tcx> {
342353
self.flags().contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
343354
}
344355

356+
/// Returns `true` if this type only has non-const implementations of sizedness traits.
357+
#[inline]
358+
pub fn has_non_const_sizedness(self) -> bool {
359+
self.flags().contains(AdtFlags::HAS_NON_CONST_SIZEDNESS)
360+
}
361+
345362
/// Returns the kind of the ADT.
346363
#[inline]
347364
pub fn adt_kind(self) -> AdtKind {

compiler/rustc_middle/src/ty/flags.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,11 @@ impl FlagComputation {
183183
}
184184
}
185185

186-
&ty::Adt(_, args) => {
186+
&ty::Adt(def, args) => {
187+
if def.has_non_const_sizedness() {
188+
self.add_flags(TypeFlags::HAS_NON_CONST_SIZEDNESS);
189+
}
190+
187191
self.add_args(args);
188192
}
189193

compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ impl<'tcx> TyCtxt<'tcx> {
7878
ty::ExistentialProjection::erase_self_ty(self, projection_pred),
7979
))
8080
}
81-
ty::ClauseKind::TypeOutlives(_) => {
82-
// Type outlives bounds don't really turn into anything,
81+
ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::HostEffect(_) => {
82+
// Type outlives and host effect bounds don't really turn into anything,
8383
// since we must use an intersection region for the `dyn*`'s
8484
// region anyways.
8585
None

compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
77
use rustc_type_ir::inherent::*;
88
use rustc_type_ir::lang_items::TraitSolverLangItem;
99
use rustc_type_ir::solve::Sizedness;
10+
use rustc_type_ir::visit::TypeVisitableExt;
1011
use rustc_type_ir::{self as ty, Interner, Movability, Mutability, Upcast as _, elaborate};
1112
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
1213
use tracing::instrument;
@@ -216,6 +217,35 @@ where
216217
}
217218
}
218219

220+
/// Returns the trait refs which need to hold for `self_ty`, with a given `sizedness` trait, to be
221+
/// `const` - can return `Err(NoSolution)` if the given `self_ty` cannot be const.
222+
///
223+
/// This only checks the conditions for constness, not the conditions for the given `sizedness`
224+
/// trait to be implemented (see the trait goal for that), as these are orthogonal. This means that
225+
/// the effect predicate can succeed while the trait predicate can fail - this is unintuitive but
226+
/// allows this function to be much simpler.
227+
// NOTE: Keep this in sync with `evaluate_host_effect_for_sizedness_goal` in the old solver.
228+
#[instrument(level = "trace", skip(cx), ret)]
229+
pub(in crate::solve) fn const_conditions_for_sizedness<I: Interner>(
230+
cx: I,
231+
self_ty: I::Ty,
232+
sizedness: Sizedness,
233+
) -> Result<Vec<ty::TraitRef<I>>, NoSolution> {
234+
// The specific degree of sizedness is orthogonal to whether a type implements any given
235+
// sizedness trait const-ly or not.
236+
237+
if !self_ty.has_non_const_sizedness() && matches!(sizedness, Sizedness::Sized) {
238+
let metasized_def_id = cx.require_lang_item(TraitSolverLangItem::MetaSized);
239+
let metasized_trait_ref = ty::TraitRef::new(cx, metasized_def_id, [self_ty]);
240+
Ok(vec![metasized_trait_ref])
241+
} else if !self_ty.has_non_const_sizedness() {
242+
// `MetaSized` has no conditionally const supertrait
243+
Ok(vec![])
244+
} else {
245+
Err(NoSolution)
246+
}
247+
}
248+
219249
#[instrument(level = "trace", skip(ecx), ret)]
220250
pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<D, I>(
221251
ecx: &EvalCtxt<'_, D>,

compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,29 @@ where
200200
}
201201

202202
fn consider_builtin_sizedness_candidates(
203-
_ecx: &mut EvalCtxt<'_, D>,
204-
_goal: Goal<I, Self>,
205-
_sizedness: Sizedness,
203+
ecx: &mut EvalCtxt<'_, D>,
204+
goal: Goal<I, Self>,
205+
sizedness: Sizedness,
206206
) -> Result<Candidate<I>, NoSolution> {
207-
unreachable!("Sized/MetaSized/PointeeSized is never const")
207+
let cx = ecx.cx();
208+
209+
let self_ty = goal.predicate.self_ty();
210+
let const_conditions =
211+
structural_traits::const_conditions_for_sizedness(cx, self_ty, sizedness)?;
212+
213+
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Trivial).enter(|ecx| {
214+
ecx.add_goals(
215+
GoalSource::AliasBoundConstCondition,
216+
const_conditions.into_iter().map(|trait_ref| {
217+
goal.with(
218+
cx,
219+
ty::Binder::dummy(trait_ref)
220+
.to_host_effect_clause(cx, goal.predicate.constness),
221+
)
222+
}),
223+
);
224+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
225+
})
208226
}
209227

210228
fn consider_builtin_copy_clone_candidate(

compiler/rustc_trait_selection/src/traits/effects.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use rustc_infer::traits::{
55
};
66
use rustc_middle::span_bug;
77
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
8-
use rustc_middle::ty::{self, TypingMode};
8+
use rustc_middle::ty::{self, TypeVisitableExt, TypingMode};
99
use rustc_type_ir::elaborate::elaborate;
10-
use rustc_type_ir::solve::NoSolution;
10+
use rustc_type_ir::solve::{NoSolution, Sizedness};
1111
use thin_vec::{ThinVec, thin_vec};
1212

1313
use super::SelectionContext;
@@ -242,10 +242,45 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>(
242242
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
243243
match selcx.tcx().as_lang_item(obligation.predicate.def_id()) {
244244
Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation),
245+
Some(LangItem::Sized) => {
246+
evaluate_host_effect_for_sizedness_goal(selcx, obligation, Sizedness::Sized)
247+
}
248+
Some(LangItem::MetaSized) => {
249+
evaluate_host_effect_for_sizedness_goal(selcx, obligation, Sizedness::MetaSized)
250+
}
251+
Some(LangItem::PointeeSized) => {
252+
evaluate_host_effect_for_sizedness_goal(selcx, obligation, Sizedness::PointeeSized)
253+
}
245254
_ => Err(EvaluationFailure::NoSolution),
246255
}
247256
}
248257

258+
// NOTE: Keep this in sync with `const_conditions_for_sizedness` in the new solver.
259+
fn evaluate_host_effect_for_sizedness_goal<'tcx>(
260+
selcx: &mut SelectionContext<'_, 'tcx>,
261+
obligation: &HostEffectObligation<'tcx>,
262+
sizedness: Sizedness,
263+
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
264+
let tcx = selcx.tcx();
265+
let self_ty = obligation.predicate.self_ty();
266+
267+
if !self_ty.has_non_const_sizedness() && matches!(sizedness, Sizedness::Sized) {
268+
let metasized_def_id = tcx.require_lang_item(LangItem::MetaSized, None);
269+
let metasized_trait_ref = ty::TraitRef::new(tcx, metasized_def_id, [self_ty]);
270+
let metasized_obligation = obligation.with(
271+
tcx,
272+
ty::Binder::dummy(metasized_trait_ref)
273+
.to_host_effect_clause(tcx, obligation.predicate.constness),
274+
);
275+
Ok(thin_vec![metasized_obligation])
276+
} else if !self_ty.has_non_const_sizedness() {
277+
// `MetaSized` has no conditionally const supertrait
278+
Ok(thin_vec![])
279+
} else {
280+
Err(EvaluationFailure::NoSolution)
281+
}
282+
}
283+
249284
// NOTE: Keep this in sync with `const_conditions_for_destruct` in the new solver.
250285
fn evaluate_host_effect_for_destruct_goal<'tcx>(
251286
selcx: &mut SelectionContext<'_, 'tcx>,

compiler/rustc_type_ir/src/flags.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,8 @@ bitflags::bitflags! {
124124

125125
/// Does this have any binders with bound vars (e.g. that need to be anonymized)?
126126
const HAS_BINDER_VARS = 1 << 25;
127+
128+
/// Does this type only have non-const implementations of sizedness traits?
129+
const HAS_NON_CONST_SIZEDNESS = 1 << 26;
127130
}
128131
}

compiler/rustc_type_ir/src/visit.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,11 @@ pub trait TypeVisitableExt<I: Interner>: TypeVisitable<I> {
346346
self.has_type_flags(TypeFlags::HAS_BOUND_VARS)
347347
}
348348

349+
/// Returns `true` if this type only has non-const implementations of sizedness traits.
350+
fn has_non_const_sizedness(&self) -> bool {
351+
self.has_type_flags(TypeFlags::HAS_NON_CONST_SIZEDNESS)
352+
}
353+
349354
/// Indicates whether this value still has parameters/placeholders/inference variables
350355
/// which could be replaced later, in a way that would change the results of `impl`
351356
/// specialization.

library/core/src/marker.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ unsafe impl<T: Sync + ?Sized + PointeeSized> Send for &T {}
151151
#[rustc_deny_explicit_impl]
152152
#[rustc_do_not_implement_via_object]
153153
#[rustc_coinductive]
154+
#[cfg_attr(not(bootstrap), const_trait)]
155+
#[cfg_attr(not(bootstrap), rustc_const_unstable(feature = "sized_hierarchy", issue = "none"))]
154156
pub trait Sized: MetaSized {
155157
// Empty.
156158
}
@@ -167,6 +169,8 @@ pub trait Sized: MetaSized {
167169
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
168170
#[rustc_do_not_implement_via_object]
169171
#[rustc_coinductive]
172+
#[cfg_attr(not(bootstrap), const_trait)]
173+
#[cfg_attr(not(bootstrap), rustc_const_unstable(feature = "sized_hierarchy", issue = "none"))]
170174
pub trait MetaSized: PointeeSized {
171175
// Empty
172176
}

tests/ui/sized-hierarchy/constness.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//@ compile-flags: -Zunstable-options
2+
//@ edition: future
3+
#![allow(internal_features)]
4+
#![feature(rustc_attrs, const_trait_impl, sized_hierarchy)]
5+
6+
#[rustc_non_const_sized]
7+
struct NotConstSized;
8+
9+
#[rustc_non_const_sized]
10+
struct NotConstMetaSized([u8]);
11+
12+
impl NotConstMetaSized {
13+
fn new() -> &'static Self { unimplemented!() }
14+
}
15+
16+
const fn size_of<T: ~const Sized>() { unimplemented!() }
17+
const fn size_of_val<T: ~const MetaSized>(_t: &T) { unimplemented!() }
18+
19+
fn main() {
20+
let _ = const { size_of::<NotConstSized>() };
21+
//~^ ERROR the trait bound `NotConstSized: const Sized` is not satisfied
22+
let _ = size_of::<NotConstSized>();
23+
24+
let _ = const { size_of::<NotConstMetaSized>() };
25+
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
26+
let _ = size_of::<NotConstMetaSized>();
27+
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
28+
29+
let v = NotConstSized;
30+
let _ = const { size_of_val(&v) };
31+
//~^ ERROR attempt to use a non-constant value in a constant
32+
let _ = size_of_val(&v);
33+
34+
let v = NotConstMetaSized::new();
35+
let _ = const { size_of_val(v) };
36+
//~^ ERROR attempt to use a non-constant value in a constant
37+
let _ = size_of_val(v);
38+
}

0 commit comments

Comments
 (0)