Skip to content

Commit 0f5a47d

Browse files
Be better at enforcing that const_conditions is only called on const items
1 parent 25c9253 commit 0f5a47d

File tree

12 files changed

+126
-120
lines changed

12 files changed

+126
-120
lines changed

compiler/rustc_hir_analysis/src/bounds.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,11 @@ impl<'tcx> Bounds<'tcx> {
8989
host: ty::HostPolarity,
9090
span: Span,
9191
) {
92-
self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span));
92+
if tcx.is_const_trait(bound_trait_ref.def_id()) {
93+
self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span));
94+
} else {
95+
tcx.dcx().span_delayed_bug(span, "tried to lower {host:?} bound for non-const trait");
96+
}
9397
}
9498

9599
pub(crate) fn clauses(

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ fn compare_method_predicate_entailment<'tcx>(
206206
);
207207

208208
// FIXME(effects): This should be replaced with a more dedicated method.
209-
let check_const_if_const = tcx.constness(impl_def_id) == hir::Constness::Const;
210-
if check_const_if_const {
209+
let is_conditionally_const = tcx.is_conditionally_const(impl_def_id);
210+
if is_conditionally_const {
211211
// Augment the hybrid param-env with the const conditions
212212
// of the impl header and the trait method.
213213
hybrid_preds.extend(
@@ -255,7 +255,7 @@ fn compare_method_predicate_entailment<'tcx>(
255255
// This registers the `~const` bounds of the impl method, which we will prove
256256
// using the hybrid param-env that we earlier augmented with the const conditions
257257
// from the impl header and trait method declaration.
258-
if check_const_if_const {
258+
if is_conditionally_const {
259259
for (const_condition, span) in
260260
tcx.const_conditions(impl_m.def_id).instantiate_own_identity()
261261
{
@@ -1904,9 +1904,8 @@ fn compare_type_predicate_entailment<'tcx>(
19041904
let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
19051905

19061906
let impl_ty_own_bounds = impl_ty_predicates.instantiate_own_identity();
1907-
let impl_ty_own_const_conditions =
1908-
tcx.const_conditions(impl_ty.def_id).instantiate_own_identity();
1909-
if impl_ty_own_bounds.len() == 0 && impl_ty_own_const_conditions.len() == 0 {
1907+
// If there are no bounds, then there are no const conditions, so no need to check that here.
1908+
if impl_ty_own_bounds.len() == 0 {
19101909
// Nothing to check.
19111910
return Ok(());
19121911
}
@@ -1931,8 +1930,8 @@ fn compare_type_predicate_entailment<'tcx>(
19311930
let impl_ty_span = tcx.def_span(impl_ty_def_id);
19321931
let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id);
19331932

1934-
let check_const_if_const = tcx.constness(impl_def_id) == hir::Constness::Const;
1935-
if check_const_if_const {
1933+
let is_conditionally_const = tcx.is_conditionally_const(impl_ty.def_id);
1934+
if is_conditionally_const {
19361935
// Augment the hybrid param-env with the const conditions
19371936
// of the impl header and the trait assoc type.
19381937
hybrid_preds.extend(
@@ -1968,8 +1967,10 @@ fn compare_type_predicate_entailment<'tcx>(
19681967
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
19691968
}
19701969

1971-
if check_const_if_const {
1970+
if is_conditionally_const {
19721971
// Validate the const conditions of the impl associated type.
1972+
let impl_ty_own_const_conditions =
1973+
tcx.const_conditions(impl_ty.def_id).instantiate_own_identity();
19731974
for (const_condition, span) in impl_ty_own_const_conditions {
19741975
let normalize_cause = traits::ObligationCause::misc(span, impl_ty_def_id);
19751976
let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
@@ -2081,7 +2082,7 @@ pub(super) fn check_type_bounds<'tcx>(
20812082
.collect();
20822083

20832084
// Only in a const implementation do we need to check that the `~const` item bounds hold.
2084-
if tcx.constness(container_id) == hir::Constness::Const {
2085+
if tcx.is_conditionally_const(impl_ty_def_id) {
20852086
obligations.extend(
20862087
tcx.implied_const_bounds(trait_ty.def_id)
20872088
.iter_instantiated_copied(tcx, rebased_args)

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1372,7 +1372,7 @@ fn check_impl<'tcx>(
13721372
}
13731373

13741374
// Ensure that the `~const` where clauses of the trait hold for the impl.
1375-
if tcx.constness(item.owner_id.def_id) == hir::Constness::Const {
1375+
if tcx.is_conditionally_const(item.owner_id.def_id) {
13761376
for (bound, _) in
13771377
tcx.const_conditions(trait_ref.def_id).instantiate(tcx, trait_ref.args)
13781378
{

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

+20-60
Original file line numberDiff line numberDiff line change
@@ -888,48 +888,8 @@ pub(super) fn const_conditions<'tcx>(
888888
tcx: TyCtxt<'tcx>,
889889
def_id: LocalDefId,
890890
) -> ty::ConstConditions<'tcx> {
891-
// This logic is spaghetti, and should be cleaned up. The current methods that are
892-
// defined to deal with constness are very unintuitive.
893-
if tcx.is_const_fn_raw(def_id.to_def_id()) {
894-
// Ok, const fn or method in const trait.
895-
} else {
896-
match tcx.def_kind(def_id) {
897-
DefKind::Trait => {
898-
if !tcx.is_const_trait(def_id.to_def_id()) {
899-
return Default::default();
900-
}
901-
}
902-
DefKind::Impl { .. } => {
903-
// FIXME(effects): Should be using a dedicated function to
904-
// test if this is a const trait impl.
905-
if tcx.constness(def_id) != hir::Constness::Const {
906-
return Default::default();
907-
}
908-
}
909-
DefKind::AssocTy | DefKind::AssocFn => {
910-
let parent_def_id = tcx.local_parent(def_id).to_def_id();
911-
match tcx.associated_item(def_id).container {
912-
ty::AssocItemContainer::TraitContainer => {
913-
if !tcx.is_const_trait(parent_def_id) {
914-
return Default::default();
915-
}
916-
}
917-
ty::AssocItemContainer::ImplContainer => {
918-
// FIXME(effects): Should be using a dedicated function to
919-
// test if this is a const trait impl.
920-
if tcx.constness(parent_def_id) != hir::Constness::Const {
921-
return Default::default();
922-
}
923-
}
924-
}
925-
}
926-
DefKind::Closure | DefKind::OpaqueTy => {
927-
// Closures and RPITs will eventually have const conditions
928-
// for `~const` bounds.
929-
return Default::default();
930-
}
931-
_ => return Default::default(),
932-
}
891+
if !tcx.is_conditionally_const(def_id) {
892+
bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
933893
}
934894

935895
let (generics, trait_def_id_and_supertraits, has_parent) = match tcx.hir_node_by_def_id(def_id)
@@ -940,7 +900,7 @@ pub(super) fn const_conditions<'tcx>(
940900
hir::ItemKind::Trait(_, _, generics, supertraits, _) => {
941901
(generics, Some((item.owner_id.def_id, supertraits)), false)
942902
}
943-
_ => return Default::default(),
903+
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
944904
},
945905
// While associated types are not really const, we do allow them to have `~const`
946906
// bounds and where clauses. `const_conditions` is responsible for gathering
@@ -950,13 +910,21 @@ pub(super) fn const_conditions<'tcx>(
950910
hir::TraitItemKind::Fn(_, _) | hir::TraitItemKind::Type(_, _) => {
951911
(item.generics, None, true)
952912
}
953-
_ => return Default::default(),
913+
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
954914
},
955915
Node::ImplItem(item) => match item.kind {
956-
hir::ImplItemKind::Fn(_, _) | hir::ImplItemKind::Type(_) => (item.generics, None, true),
957-
_ => return Default::default(),
916+
hir::ImplItemKind::Fn(_, _) | hir::ImplItemKind::Type(_) => {
917+
(item.generics, None, tcx.is_conditionally_const(tcx.local_parent(def_id)))
918+
}
919+
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
958920
},
959-
_ => return Default::default(),
921+
Node::ForeignItem(item) => match item.kind {
922+
hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false),
923+
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
924+
},
925+
// N.B. Tuple ctors are unconditionally constant.
926+
Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(),
927+
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
960928
};
961929

962930
let icx = ItemCtxt::new(tcx, def_id);
@@ -1017,30 +985,22 @@ pub(super) fn implied_const_bounds<'tcx>(
1017985
tcx: TyCtxt<'tcx>,
1018986
def_id: LocalDefId,
1019987
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
988+
if !tcx.is_conditionally_const(def_id) {
989+
bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
990+
}
991+
1020992
let bounds = match tcx.hir_node_by_def_id(def_id) {
1021993
Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => {
1022-
if !tcx.is_const_trait(def_id.to_def_id()) {
1023-
return ty::EarlyBinder::bind(&[]);
1024-
}
1025-
1026994
implied_predicates_with_filter(
1027995
tcx,
1028996
def_id.to_def_id(),
1029997
PredicateFilter::SelfConstIfConst,
1030998
)
1031999
}
10321000
Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) => {
1033-
if !tcx.is_const_trait(tcx.local_parent(def_id).to_def_id()) {
1034-
return ty::EarlyBinder::bind(&[]);
1035-
}
1036-
10371001
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)
10381002
}
1039-
Node::OpaqueTy(..) => {
1040-
// We should eventually collect the `~const` bounds on opaques.
1041-
return ty::EarlyBinder::bind(&[]);
1042-
}
1043-
_ => return ty::EarlyBinder::bind(&[]),
1003+
_ => bug!("implied_const_bounds called on wrong item: {def_id:?}"),
10441004
};
10451005

10461006
bounds.map_bound(|bounds| {

compiler/rustc_hir_typeck/src/callee.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -861,12 +861,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
861861

862862
// FIXME(effects): Should this be `is_const_fn_raw`? It depends on if we move
863863
// const stability checking here too, I guess.
864-
if self.tcx.is_const_fn(callee_did)
865-
|| self
866-
.tcx
867-
.trait_of_item(callee_did)
868-
.is_some_and(|def_id| self.tcx.is_const_trait(def_id))
869-
{
864+
if self.tcx.is_conditionally_const(callee_did) {
870865
let q = self.tcx.const_conditions(callee_did);
871866
// FIXME(effects): Use this span with a better cause code.
872867
for (cond, _) in q.instantiate(self.tcx, callee_args) {

compiler/rustc_metadata/src/rmeta/encoder.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14231423
let g = tcx.generics_of(def_id);
14241424
record!(self.tables.generics_of[def_id] <- g);
14251425
record!(self.tables.explicit_predicates_of[def_id] <- self.tcx.explicit_predicates_of(def_id));
1426-
record!(self.tables.const_conditions[def_id] <- self.tcx.const_conditions(def_id));
14271426
let inferred_outlives = self.tcx.inferred_outlives_of(def_id);
14281427
record_defaulted_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
14291428

@@ -1434,6 +1433,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14341433
}
14351434
}
14361435
}
1436+
if tcx.is_conditionally_const(def_id) {
1437+
record!(self.tables.const_conditions[def_id] <- self.tcx.const_conditions(def_id));
1438+
}
14371439
if should_encode_type(tcx, local_id, def_kind) {
14381440
record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id));
14391441
}
@@ -1457,20 +1459,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14571459
self.tcx.explicit_super_predicates_of(def_id).skip_binder());
14581460
record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <-
14591461
self.tcx.explicit_implied_predicates_of(def_id).skip_binder());
1460-
record_defaulted_array!(self.tables.implied_const_bounds[def_id]
1461-
<- self.tcx.implied_const_bounds(def_id).skip_binder());
14621462
let module_children = self.tcx.module_children_local(local_id);
14631463
record_array!(self.tables.module_children_non_reexports[def_id] <-
14641464
module_children.iter().map(|child| child.res.def_id().index));
1465+
if self.tcx.is_const_trait(def_id) {
1466+
record_defaulted_array!(self.tables.implied_const_bounds[def_id]
1467+
<- self.tcx.implied_const_bounds(def_id).skip_binder());
1468+
}
14651469
}
14661470
if let DefKind::TraitAlias = def_kind {
14671471
record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
14681472
record_defaulted_array!(self.tables.explicit_super_predicates_of[def_id] <-
14691473
self.tcx.explicit_super_predicates_of(def_id).skip_binder());
14701474
record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <-
14711475
self.tcx.explicit_implied_predicates_of(def_id).skip_binder());
1472-
record_defaulted_array!(self.tables.implied_const_bounds[def_id]
1473-
<- self.tcx.implied_const_bounds(def_id).skip_binder());
14741476
}
14751477
if let DefKind::Trait | DefKind::Impl { .. } = def_kind {
14761478
let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
@@ -1653,8 +1655,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
16531655
if let ty::AssocKind::Type = item.kind {
16541656
self.encode_explicit_item_bounds(def_id);
16551657
self.encode_explicit_item_super_predicates(def_id);
1656-
record_defaulted_array!(self.tables.implied_const_bounds[def_id]
1657-
<- self.tcx.implied_const_bounds(def_id).skip_binder());
1658+
if tcx.is_conditionally_const(def_id) {
1659+
record_defaulted_array!(self.tables.implied_const_bounds[def_id]
1660+
<- self.tcx.implied_const_bounds(def_id).skip_binder());
1661+
}
16581662
}
16591663
}
16601664
AssocItemContainer::ImplContainer => {

compiler/rustc_middle/src/ty/context.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
384384
}
385385

386386
fn is_const_impl(self, def_id: DefId) -> bool {
387-
self.constness(def_id) == hir::Constness::Const
387+
self.is_conditionally_const(def_id)
388388
}
389389

390390
fn const_conditions(
@@ -3140,6 +3140,7 @@ impl<'tcx> TyCtxt<'tcx> {
31403140
}
31413141
}
31423142

3143+
// FIXME(effects): Please remove this. It's a footgun.
31433144
/// Whether the trait impl is marked const. This does not consider stability or feature gates.
31443145
pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool {
31453146
let Some(local_def_id) = def_id.as_local() else { return false };

compiler/rustc_middle/src/ty/mod.rs

+66-1
Original file line numberDiff line numberDiff line change
@@ -1999,10 +1999,75 @@ impl<'tcx> TyCtxt<'tcx> {
19991999
pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
20002000
matches!(
20012001
self.def_kind(def_id),
2002-
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure
2002+
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Closure
20032003
) && self.constness(def_id) == hir::Constness::Const
20042004
}
20052005

2006+
/// Whether this item is conditionally constant for the purposes of the
2007+
/// effects implementation.
2008+
///
2009+
/// This roughly corresponds to all const functions and other callable
2010+
/// items, along with const impls and traits, and associated types within
2011+
/// those impls and traits.
2012+
pub fn is_conditionally_const(self, def_id: impl Into<DefId>) -> bool {
2013+
let def_id: DefId = def_id.into();
2014+
match self.def_kind(def_id) {
2015+
DefKind::Impl { of_trait: true } => {
2016+
self.constness(def_id) == hir::Constness::Const
2017+
&& self.is_const_trait(
2018+
self.trait_id_of_impl(def_id)
2019+
.expect("expected trait for trait implementation"),
2020+
)
2021+
}
2022+
DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => {
2023+
self.constness(def_id) == hir::Constness::Const
2024+
}
2025+
DefKind::Trait => self.is_const_trait(def_id),
2026+
DefKind::AssocTy | DefKind::AssocFn => {
2027+
let parent_def_id = self.parent(def_id);
2028+
match self.def_kind(parent_def_id) {
2029+
DefKind::Impl { of_trait: false } => {
2030+
self.constness(def_id) == hir::Constness::Const
2031+
}
2032+
DefKind::Impl { of_trait: true } | DefKind::Trait => {
2033+
self.is_conditionally_const(parent_def_id)
2034+
}
2035+
_ => bug!("unexpected parent item of associated item: {parent_def_id:?}"),
2036+
}
2037+
}
2038+
DefKind::Closure | DefKind::OpaqueTy => {
2039+
// Closures and RPITs will eventually have const conditions
2040+
// for `~const` bounds.
2041+
false
2042+
}
2043+
DefKind::Ctor(_, CtorKind::Const)
2044+
| DefKind::Impl { of_trait: false }
2045+
| DefKind::Mod
2046+
| DefKind::Struct
2047+
| DefKind::Union
2048+
| DefKind::Enum
2049+
| DefKind::Variant
2050+
| DefKind::TyAlias
2051+
| DefKind::ForeignTy
2052+
| DefKind::TraitAlias
2053+
| DefKind::TyParam
2054+
| DefKind::Const
2055+
| DefKind::ConstParam
2056+
| DefKind::Static { .. }
2057+
| DefKind::AssocConst
2058+
| DefKind::Macro(_)
2059+
| DefKind::ExternCrate
2060+
| DefKind::Use
2061+
| DefKind::ForeignMod
2062+
| DefKind::AnonConst
2063+
| DefKind::InlineConst
2064+
| DefKind::Field
2065+
| DefKind::LifetimeParam
2066+
| DefKind::GlobalAsm
2067+
| DefKind::SyntheticCoroutineBody => false,
2068+
}
2069+
}
2070+
20062071
#[inline]
20072072
pub fn is_const_trait(self, def_id: DefId) -> bool {
20082073
self.trait_def(def_id).constness == hir::Constness::Const

compiler/rustc_ty_utils/src/ty.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,13 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
152152

153153
// We extend the param-env of our item with the const conditions of the item,
154154
// since we're allowed to assume `~const` bounds hold within the item itself.
155-
predicates.extend(
156-
tcx.const_conditions(def_id)
157-
.instantiate_identity(tcx)
158-
.into_iter()
159-
.map(|(trait_ref, _)| trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)),
160-
);
155+
if tcx.is_conditionally_const(def_id) {
156+
predicates.extend(
157+
tcx.const_conditions(def_id).instantiate_identity(tcx).into_iter().map(
158+
|(trait_ref, _)| trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
159+
),
160+
);
161+
}
161162

162163
let local_did = def_id.as_local();
163164

0 commit comments

Comments
 (0)