Skip to content

Commit 36be4d6

Browse files
authored
Rollup merge of rust-lang#148716 - camelid:finish-type_const, r=BoxyUwU
mgca: Finish implementation of `#[type_const]` tracking issue: rust-lang#132980 fixes rust-lang#140729 fixes rust-lang#140860 - **Fix `#[type_const]` attribute placement validation** - **Perform WF-checking on type_const RHS's** - **Check type_const type is ConstParamTy_ and that RHS matches it** - **Check that impls of `#[type_const]` consts also have the attr** r? `@BoxyUwU`
2 parents bbcb105 + db2fbdb commit 36be4d6

34 files changed

+536
-170
lines changed

compiler/rustc_attr_parsing/src/attributes/traits.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ pub(crate) struct TypeConstParser;
6666
impl<S: Stage> NoArgsAttributeParser<S> for TypeConstParser {
6767
const PATH: &[Symbol] = &[sym::type_const];
6868
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
69-
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocConst)]);
69+
const ALLOWED_TARGETS: AllowedTargets =
70+
AllowedTargets::AllowList(&[Allow(Target::Const), Allow(Target::AssocConst)]);
7071
const CREATE: fn(Span) -> AttributeKind = AttributeKind::TypeConst;
7172
}
7273

compiler/rustc_hir/src/hir.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3065,7 +3065,7 @@ macro_rules! expect_methods_self_kind {
30653065
$(
30663066
#[track_caller]
30673067
pub fn $name(&self) -> $ret_ty {
3068-
let $pat = &self.kind else { expect_failed(stringify!($ident), self) };
3068+
let $pat = &self.kind else { expect_failed(stringify!($name), self) };
30693069
$ret_val
30703070
}
30713071
)*
@@ -3077,7 +3077,7 @@ macro_rules! expect_methods_self {
30773077
$(
30783078
#[track_caller]
30793079
pub fn $name(&self) -> $ret_ty {
3080-
let $pat = self else { expect_failed(stringify!($ident), self) };
3080+
let $pat = self else { expect_failed(stringify!($name), self) };
30813081
$ret_val
30823082
}
30833083
)*
@@ -4790,6 +4790,11 @@ impl<'hir> Node<'hir> {
47904790
ForeignItemKind::Static(ty, ..) => Some(ty),
47914791
_ => None,
47924792
},
4793+
Node::GenericParam(param) => match param.kind {
4794+
GenericParamKind::Lifetime { .. } => None,
4795+
GenericParamKind::Type { default, .. } => default,
4796+
GenericParamKind::Const { ty, .. } => Some(ty),
4797+
},
47934798
_ => None,
47944799
}
47954800
}

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -757,22 +757,18 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
757757
}
758758

759759
match tcx.def_kind(def_id) {
760-
def_kind @ (DefKind::Static { .. } | DefKind::Const) => {
760+
DefKind::Static { .. } => {
761761
tcx.ensure_ok().generics_of(def_id);
762762
tcx.ensure_ok().type_of(def_id);
763763
tcx.ensure_ok().predicates_of(def_id);
764-
match def_kind {
765-
DefKind::Static { .. } => {
766-
check_static_inhabited(tcx, def_id);
767-
check_static_linkage(tcx, def_id);
768-
let ty = tcx.type_of(def_id).instantiate_identity();
769-
res = res.and(wfcheck::check_static_item(
770-
tcx, def_id, ty, /* should_check_for_sync */ true,
771-
));
772-
}
773-
DefKind::Const => res = res.and(wfcheck::check_const_item(tcx, def_id)),
774-
_ => unreachable!(),
775-
}
764+
765+
check_static_inhabited(tcx, def_id);
766+
check_static_linkage(tcx, def_id);
767+
let ty = tcx.type_of(def_id).instantiate_identity();
768+
res = res.and(wfcheck::check_static_item(
769+
tcx, def_id, ty, /* should_check_for_sync */ true,
770+
));
771+
776772
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
777773
// checks. Returning early here does not miss any checks and
778774
// avoids this query from having a direct dependency edge on the HIR
@@ -900,6 +896,39 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
900896
// avoids this query from having a direct dependency edge on the HIR
901897
return res;
902898
}
899+
DefKind::Const => {
900+
tcx.ensure_ok().generics_of(def_id);
901+
tcx.ensure_ok().type_of(def_id);
902+
tcx.ensure_ok().predicates_of(def_id);
903+
904+
res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
905+
let ty = tcx.type_of(def_id).instantiate_identity();
906+
let ty_span = tcx.ty_span(def_id);
907+
let ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(def_id)), ty);
908+
wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(def_id)), ty.into());
909+
wfcx.register_bound(
910+
traits::ObligationCause::new(
911+
ty_span,
912+
def_id,
913+
ObligationCauseCode::SizedConstOrStatic,
914+
),
915+
tcx.param_env(def_id),
916+
ty,
917+
tcx.require_lang_item(LangItem::Sized, ty_span),
918+
);
919+
check_where_clauses(wfcx, def_id);
920+
921+
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) {
922+
wfcheck::check_type_const(wfcx, def_id, ty, true)?;
923+
}
924+
Ok(())
925+
}));
926+
927+
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
928+
// checks. Returning early here does not miss any checks and
929+
// avoids this query from having a direct dependency edge on the HIR
930+
return res;
931+
}
903932
DefKind::TyAlias => {
904933
tcx.ensure_ok().generics_of(def_id);
905934
tcx.ensure_ok().type_of(def_id);
@@ -920,6 +949,11 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
920949
}));
921950
check_variances_for_type_defn(tcx, def_id);
922951
}
952+
953+
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
954+
// checks. Returning early here does not miss any checks and
955+
// avoids this query from having a direct dependency edge on the HIR
956+
return res;
923957
}
924958
DefKind::ForeignMod => {
925959
let it = tcx.hir_expect_item(def_id);

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ use hir::def_id::{DefId, DefIdMap, LocalDefId};
66
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
77
use rustc_errors::codes::*;
88
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err};
9+
use rustc_hir::attrs::AttributeKind;
910
use rustc_hir::def::{DefKind, Res};
1011
use rustc_hir::intravisit::VisitorExt;
11-
use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit};
12+
use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, find_attr, intravisit};
1213
use rustc_infer::infer::{self, BoundRegionConversionTime, InferCtxt, TyCtxtInferExt};
1314
use rustc_infer::traits::util;
1415
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -1984,12 +1985,46 @@ fn compare_impl_const<'tcx>(
19841985
trait_const_item: ty::AssocItem,
19851986
impl_trait_ref: ty::TraitRef<'tcx>,
19861987
) -> Result<(), ErrorGuaranteed> {
1988+
compare_type_const(tcx, impl_const_item, trait_const_item)?;
19871989
compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?;
19881990
compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?;
19891991
check_region_bounds_on_impl_item(tcx, impl_const_item, trait_const_item, false)?;
19901992
compare_const_predicate_entailment(tcx, impl_const_item, trait_const_item, impl_trait_ref)
19911993
}
19921994

1995+
fn compare_type_const<'tcx>(
1996+
tcx: TyCtxt<'tcx>,
1997+
impl_const_item: ty::AssocItem,
1998+
trait_const_item: ty::AssocItem,
1999+
) -> Result<(), ErrorGuaranteed> {
2000+
let impl_is_type_const =
2001+
find_attr!(tcx.get_all_attrs(impl_const_item.def_id), AttributeKind::TypeConst(_));
2002+
let trait_type_const_span = find_attr!(
2003+
tcx.get_all_attrs(trait_const_item.def_id),
2004+
AttributeKind::TypeConst(sp) => *sp
2005+
);
2006+
2007+
if let Some(trait_type_const_span) = trait_type_const_span
2008+
&& !impl_is_type_const
2009+
{
2010+
return Err(tcx
2011+
.dcx()
2012+
.struct_span_err(
2013+
tcx.def_span(impl_const_item.def_id),
2014+
"implementation of `#[type_const]` const must be marked with `#[type_const]`",
2015+
)
2016+
.with_span_note(
2017+
MultiSpan::from_spans(vec![
2018+
tcx.def_span(trait_const_item.def_id),
2019+
trait_type_const_span,
2020+
]),
2021+
"trait declaration of const is marked with `#[type_const]`",
2022+
)
2023+
.emit());
2024+
}
2025+
Ok(())
2026+
}
2027+
19932028
/// The equivalent of [compare_method_predicate_entailment], but for associated constants
19942029
/// instead of associated functions.
19952030
// FIXME(generic_const_items): If possible extract the common parts of `compare_{type,const}_predicate_entailment`.

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 63 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ use rustc_abi::ExternAbi;
66
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
77
use rustc_errors::codes::*;
88
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
9+
use rustc_hir::attrs::AttributeKind;
910
use rustc_hir::def::{DefKind, Res};
1011
use rustc_hir::def_id::{DefId, LocalDefId};
1112
use rustc_hir::lang_items::LangItem;
12-
use rustc_hir::{AmbigArg, ItemKind};
13+
use rustc_hir::{AmbigArg, ItemKind, find_attr};
1314
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
1415
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin, TyCtxtInferExt};
1516
use rustc_lint_defs::builtin::SUPERTRAIT_ITEM_SHADOWING_DEFINITION;
@@ -925,11 +926,11 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &ty::GenericParamDef) -> Result<(), Er
925926
#[instrument(level = "debug", skip(tcx))]
926927
pub(crate) fn check_associated_item(
927928
tcx: TyCtxt<'_>,
928-
item_id: LocalDefId,
929+
def_id: LocalDefId,
929930
) -> Result<(), ErrorGuaranteed> {
930-
let loc = Some(WellFormedLoc::Ty(item_id));
931-
enter_wf_checking_ctxt(tcx, item_id, |wfcx| {
932-
let item = tcx.associated_item(item_id);
931+
let loc = Some(WellFormedLoc::Ty(def_id));
932+
enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
933+
let item = tcx.associated_item(def_id);
933934

934935
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
935936
// other `Foo` impls are incoherent.
@@ -942,36 +943,45 @@ pub(crate) fn check_associated_item(
942943
}
943944
};
944945

945-
let span = tcx.def_span(item_id);
946+
let span = tcx.def_span(def_id);
946947

947948
match item.kind {
948949
ty::AssocKind::Const { .. } => {
949-
let ty = tcx.type_of(item.def_id).instantiate_identity();
950-
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
950+
let ty = tcx.type_of(def_id).instantiate_identity();
951+
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty);
951952
wfcx.register_wf_obligation(span, loc, ty.into());
952-
check_sized_if_body(
953-
wfcx,
954-
item.def_id.expect_local(),
955-
ty,
956-
Some(span),
957-
ObligationCauseCode::SizedConstOrStatic,
958-
);
953+
954+
let has_value = item.defaultness(tcx).has_value();
955+
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) {
956+
check_type_const(wfcx, def_id, ty, has_value)?;
957+
}
958+
959+
if has_value {
960+
let code = ObligationCauseCode::SizedConstOrStatic;
961+
wfcx.register_bound(
962+
ObligationCause::new(span, def_id, code),
963+
wfcx.param_env,
964+
ty,
965+
tcx.require_lang_item(LangItem::Sized, span),
966+
);
967+
}
968+
959969
Ok(())
960970
}
961971
ty::AssocKind::Fn { .. } => {
962-
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
972+
let sig = tcx.fn_sig(def_id).instantiate_identity();
963973
let hir_sig =
964-
tcx.hir_node_by_def_id(item_id).fn_sig().expect("bad signature for method");
965-
check_fn_or_method(wfcx, sig, hir_sig.decl, item_id);
974+
tcx.hir_node_by_def_id(def_id).fn_sig().expect("bad signature for method");
975+
check_fn_or_method(wfcx, sig, hir_sig.decl, def_id);
966976
check_method_receiver(wfcx, hir_sig, item, self_ty)
967977
}
968978
ty::AssocKind::Type { .. } => {
969979
if let ty::AssocContainer::Trait = item.container {
970980
check_associated_type_bounds(wfcx, item, span)
971981
}
972982
if item.defaultness(tcx).has_value() {
973-
let ty = tcx.type_of(item.def_id).instantiate_identity();
974-
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
983+
let ty = tcx.type_of(def_id).instantiate_identity();
984+
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty);
975985
wfcx.register_wf_obligation(span, loc, ty.into());
976986
}
977987
Ok(())
@@ -1222,28 +1232,36 @@ pub(crate) fn check_static_item<'tcx>(
12221232
})
12231233
}
12241234

1225-
pub(crate) fn check_const_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
1226-
enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
1227-
let ty = tcx.type_of(def_id).instantiate_identity();
1228-
let ty_span = tcx.ty_span(def_id);
1229-
let ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(def_id)), ty);
1235+
#[instrument(level = "debug", skip(wfcx))]
1236+
pub(super) fn check_type_const<'tcx>(
1237+
wfcx: &WfCheckingCtxt<'_, 'tcx>,
1238+
def_id: LocalDefId,
1239+
item_ty: Ty<'tcx>,
1240+
has_value: bool,
1241+
) -> Result<(), ErrorGuaranteed> {
1242+
let tcx = wfcx.tcx();
1243+
let span = tcx.def_span(def_id);
12301244

1231-
wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(def_id)), ty.into());
1232-
wfcx.register_bound(
1233-
traits::ObligationCause::new(
1234-
ty_span,
1235-
wfcx.body_def_id,
1236-
ObligationCauseCode::SizedConstOrStatic,
1237-
),
1238-
wfcx.param_env,
1239-
ty,
1240-
tcx.require_lang_item(LangItem::Sized, ty_span),
1241-
);
1245+
wfcx.register_bound(
1246+
ObligationCause::new(span, def_id, ObligationCauseCode::ConstParam(item_ty)),
1247+
wfcx.param_env,
1248+
item_ty,
1249+
tcx.require_lang_item(LangItem::ConstParamTy, span),
1250+
);
12421251

1243-
check_where_clauses(wfcx, def_id);
1252+
if has_value {
1253+
let raw_ct = tcx.const_of_item(def_id).instantiate_identity();
1254+
let norm_ct = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), raw_ct);
1255+
wfcx.register_wf_obligation(span, Some(WellFormedLoc::Ty(def_id)), norm_ct.into());
12441256

1245-
Ok(())
1246-
})
1257+
wfcx.register_obligation(Obligation::new(
1258+
tcx,
1259+
ObligationCause::new(span, def_id, ObligationCauseCode::WellFormed(None)),
1260+
wfcx.param_env,
1261+
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(norm_ct, item_ty)),
1262+
));
1263+
}
1264+
Ok(())
12471265
}
12481266

12491267
#[instrument(level = "debug", skip(tcx, impl_))]
@@ -1583,33 +1601,16 @@ fn check_fn_or_method<'tcx>(
15831601
}
15841602

15851603
// If the function has a body, additionally require that the return type is sized.
1586-
check_sized_if_body(
1587-
wfcx,
1588-
def_id,
1589-
sig.output(),
1590-
match hir_decl.output {
1591-
hir::FnRetTy::Return(ty) => Some(ty.span),
1592-
hir::FnRetTy::DefaultReturn(_) => None,
1593-
},
1594-
ObligationCauseCode::SizedReturnType,
1595-
);
1596-
}
1597-
1598-
fn check_sized_if_body<'tcx>(
1599-
wfcx: &WfCheckingCtxt<'_, 'tcx>,
1600-
def_id: LocalDefId,
1601-
ty: Ty<'tcx>,
1602-
maybe_span: Option<Span>,
1603-
code: ObligationCauseCode<'tcx>,
1604-
) {
1605-
let tcx = wfcx.tcx();
16061604
if let Some(body) = tcx.hir_maybe_body_owned_by(def_id) {
1607-
let span = maybe_span.unwrap_or(body.value.span);
1605+
let span = match hir_decl.output {
1606+
hir::FnRetTy::Return(ty) => ty.span,
1607+
hir::FnRetTy::DefaultReturn(_) => body.value.span,
1608+
};
16081609

16091610
wfcx.register_bound(
1610-
ObligationCause::new(span, def_id, code),
1611+
ObligationCause::new(span, def_id, ObligationCauseCode::SizedReturnType),
16111612
wfcx.param_env,
1612-
ty,
1613+
sig.output(),
16131614
tcx.require_lang_item(LangItem::Sized, span),
16141615
);
16151616
}

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,8 +1611,12 @@ fn const_of_item<'tcx>(
16111611
};
16121612
let ct_arg = match ct_rhs {
16131613
hir::ConstItemRhs::TypeConst(ct_arg) => ct_arg,
1614-
hir::ConstItemRhs::Body(body_id) => {
1615-
bug!("cannot call const_of_item on a non-type_const {body_id:?}")
1614+
hir::ConstItemRhs::Body(_) => {
1615+
let e = tcx.dcx().span_delayed_bug(
1616+
tcx.def_span(def_id),
1617+
"cannot call const_of_item on a non-type_const",
1618+
);
1619+
return ty::EarlyBinder::bind(Const::new_error(tcx, e));
16161620
}
16171621
};
16181622
let icx = ItemCtxt::new(tcx, def_id);

0 commit comments

Comments
 (0)