Skip to content

Commit c0939d4

Browse files
committed
Perform WF-checking on type_const RHS's
1 parent e56de95 commit c0939d4

File tree

6 files changed

+204
-83
lines changed

6 files changed

+204
-83
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 44 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,36 @@ 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+
wfcheck::check_const_item_rhs(wfcx, def_id)
922+
}));
923+
924+
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
925+
// checks. Returning early here does not miss any checks and
926+
// avoids this query from having a direct dependency edge on the HIR
927+
return res;
928+
}
903929
DefKind::TyAlias => {
904930
tcx.ensure_ok().generics_of(def_id);
905931
tcx.ensure_ok().type_of(def_id);
@@ -920,6 +946,11 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
920946
}));
921947
check_variances_for_type_defn(tcx, def_id);
922948
}
949+
950+
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
951+
// checks. Returning early here does not miss any checks and
952+
// avoids this query from having a direct dependency edge on the HIR
953+
return res;
923954
}
924955
DefKind::ForeignMod => {
925956
let it = tcx.hir_expect_item(def_id);

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 46 additions & 65 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,42 @@ 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+
if item.defaultness(tcx).has_value() {
955+
let code = ObligationCauseCode::SizedConstOrStatic;
956+
wfcx.register_bound(
957+
ObligationCause::new(span, def_id, code),
958+
wfcx.param_env,
959+
ty,
960+
tcx.require_lang_item(LangItem::Sized, span),
961+
);
962+
963+
check_const_item_rhs(wfcx, def_id)?;
964+
}
965+
959966
Ok(())
960967
}
961968
ty::AssocKind::Fn { .. } => {
962-
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
969+
let sig = tcx.fn_sig(def_id).instantiate_identity();
963970
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);
971+
tcx.hir_node_by_def_id(def_id).fn_sig().expect("bad signature for method");
972+
check_fn_or_method(wfcx, sig, hir_sig.decl, def_id);
966973
check_method_receiver(wfcx, hir_sig, item, self_ty)
967974
}
968975
ty::AssocKind::Type { .. } => {
969976
if let ty::AssocContainer::Trait = item.container {
970977
check_associated_type_bounds(wfcx, item, span)
971978
}
972979
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);
980+
let ty = tcx.type_of(def_id).instantiate_identity();
981+
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty);
975982
wfcx.register_wf_obligation(span, loc, ty.into());
976983
}
977984
Ok(())
@@ -1222,28 +1229,19 @@ pub(crate) fn check_static_item<'tcx>(
12221229
})
12231230
}
12241231

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);
1230-
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-
);
1242-
1243-
check_where_clauses(wfcx, def_id);
1244-
1245-
Ok(())
1246-
})
1232+
#[instrument(level = "debug", skip(wfcx))]
1233+
pub(super) fn check_const_item_rhs<'tcx>(
1234+
wfcx: &WfCheckingCtxt<'_, 'tcx>,
1235+
def_id: LocalDefId,
1236+
) -> Result<(), ErrorGuaranteed> {
1237+
let tcx = wfcx.tcx();
1238+
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) {
1239+
let raw_ct = tcx.const_of_item(def_id).instantiate_identity();
1240+
let span = tcx.def_span(def_id);
1241+
let norm_ct = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), raw_ct);
1242+
wfcx.register_wf_obligation(span, Some(WellFormedLoc::Ty(def_id)), norm_ct.into());
1243+
}
1244+
Ok(())
12471245
}
12481246

12491247
#[instrument(level = "debug", skip(tcx, impl_))]
@@ -1583,33 +1581,16 @@ fn check_fn_or_method<'tcx>(
15831581
}
15841582

15851583
// 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();
16061584
if let Some(body) = tcx.hir_maybe_body_owned_by(def_id) {
1607-
let span = maybe_span.unwrap_or(body.value.span);
1585+
let span = match hir_decl.output {
1586+
hir::FnRetTy::Return(ty) => ty.span,
1587+
hir::FnRetTy::DefaultReturn(_) => body.value.span,
1588+
};
16081589

16091590
wfcx.register_bound(
1610-
ObligationCause::new(span, def_id, code),
1591+
ObligationCause::new(span, def_id, ObligationCauseCode::SizedReturnType),
16111592
wfcx.param_env,
1612-
ty,
1593+
sig.output(),
16131594
tcx.require_lang_item(LangItem::Sized, span),
16141595
);
16151596
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//@ check-pass
2+
3+
#![expect(incomplete_features)]
4+
#![feature(min_generic_const_args, generic_const_items)]
5+
6+
pub trait Tr<const X: usize> {
7+
#[type_const]
8+
const N1<T>: usize;
9+
#[type_const]
10+
const N2<const I: usize>: usize;
11+
#[type_const]
12+
const N3: usize;
13+
}
14+
15+
pub struct S;
16+
17+
impl<const X: usize> Tr<X> for S {
18+
#[type_const]
19+
const N1<T>: usize = 0;
20+
#[type_const]
21+
const N2<const I: usize>: usize = 1;
22+
#[type_const]
23+
const N3: usize = 2;
24+
}
25+
26+
fn main() {}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![expect(incomplete_features)]
2+
#![feature(min_generic_const_args, generic_const_items)]
3+
4+
#[type_const]
5+
const FREE1<T>: usize = std::mem::size_of::<T>();
6+
//~^ ERROR generic parameters may not be used in const operations
7+
#[type_const]
8+
const FREE2<const I: usize>: usize = I + 1;
9+
//~^ ERROR generic parameters may not be used in const operations
10+
11+
pub trait Tr<const X: usize> {
12+
#[type_const]
13+
const N1<T>: usize;
14+
#[type_const]
15+
const N2<const I: usize>: usize;
16+
#[type_const]
17+
const N3: usize;
18+
}
19+
20+
pub struct S;
21+
22+
impl<const X: usize> Tr<X> for S {
23+
#[type_const]
24+
const N1<T>: usize = std::mem::size_of::<T>();
25+
//~^ ERROR generic parameters may not be used in const operations
26+
#[type_const]
27+
const N2<const I: usize>: usize = I + 1;
28+
//~^ ERROR generic parameters may not be used in const operations
29+
#[type_const]
30+
const N3: usize = 2 & X;
31+
//~^ ERROR generic parameters may not be used in const operations
32+
}
33+
34+
fn main() {}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error: generic parameters may not be used in const operations
2+
--> $DIR/type_const-on-generic-expr.rs:5:45
3+
|
4+
LL | const FREE1<T>: usize = std::mem::size_of::<T>();
5+
| ^ cannot perform const operation using `T`
6+
|
7+
= note: type parameters may not be used in const expressions
8+
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
9+
10+
error: generic parameters may not be used in const operations
11+
--> $DIR/type_const-on-generic-expr.rs:8:38
12+
|
13+
LL | const FREE2<const I: usize>: usize = I + 1;
14+
| ^ cannot perform const operation using `I`
15+
|
16+
= help: const parameters may only be used as standalone arguments here, i.e. `I`
17+
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
18+
19+
error: generic parameters may not be used in const operations
20+
--> $DIR/type_const-on-generic-expr.rs:24:46
21+
|
22+
LL | const N1<T>: usize = std::mem::size_of::<T>();
23+
| ^ cannot perform const operation using `T`
24+
|
25+
= note: type parameters may not be used in const expressions
26+
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
27+
28+
error: generic parameters may not be used in const operations
29+
--> $DIR/type_const-on-generic-expr.rs:27:39
30+
|
31+
LL | const N2<const I: usize>: usize = I + 1;
32+
| ^ cannot perform const operation using `I`
33+
|
34+
= help: const parameters may only be used as standalone arguments here, i.e. `I`
35+
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
36+
37+
error: generic parameters may not be used in const operations
38+
--> $DIR/type_const-on-generic-expr.rs:30:27
39+
|
40+
LL | const N3: usize = 2 & X;
41+
| ^ cannot perform const operation using `X`
42+
|
43+
= help: const parameters may only be used as standalone arguments here, i.e. `X`
44+
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
45+
46+
error: aborting due to 5 previous errors
47+

tests/ui/generic-const-items/associated-const-equality.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,24 @@ trait Owner {
99
const C<const N: u32>: u32;
1010
#[type_const]
1111
const K<const N: u32>: u32;
12-
#[type_const]
13-
const Q<T>: Maybe<T>;
12+
// #[type_const]
13+
// const Q<T>: Maybe<T>;
1414
}
1515

1616
impl Owner for () {
1717
#[type_const]
1818
const C<const N: u32>: u32 = N;
1919
#[type_const]
2020
const K<const N: u32>: u32 = 99 + 1;
21-
#[type_const]
22-
const Q<T>: Maybe<T> = Maybe::Nothing;
21+
// FIXME(mgca): re-enable once we properly support ctors and generics on paths
22+
// #[type_const]
23+
// const Q<T>: Maybe<T> = Maybe::Nothing;
2324
}
2425

2526
fn take0<const N: u32>(_: impl Owner<C<N> = { N }>) {}
2627
fn take1(_: impl Owner<K<99> = 100>) {}
27-
fn take2(_: impl Owner<Q<()> = { Maybe::Just(()) }>) {}
28+
// FIXME(mgca): re-enable once we properly support ctors and generics on paths
29+
// fn take2(_: impl Owner<Q<()> = { Maybe::Just(()) }>) {}
2830

2931
fn main() {
3032
take0::<128>(());

0 commit comments

Comments
 (0)