Skip to content

Commit a47f4df

Browse files
committed
Auto merge of #150519 - camelid:mgca-forbid-params-properly, r=BoxyUwU
Use more principled check for generics in const ops Fixes #144547. Fixes #140891. In the future, we likely want to make the check less likely to be missed by reducing the number of external entry points to HIR type lowering. Note: If this causes pass->error regressions (not truly regressions because those cases were mistakenly accepted), they can easily be avoided for the time being by only running the check if `is_self_alias` is true or mgca is enabled. - **Fix parsing of mgca const blocks in array repeat exprs** - **Use more principled check for generics in const ops**
2 parents 056908d + f71e938 commit a47f4df

45 files changed

Lines changed: 404 additions & 282 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 137 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable;
3838
use rustc_middle::mir::interpret::LitToConstInput;
3939
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
4040
use rustc_middle::ty::{
41-
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
42-
TypingMode, Upcast, fold_regions,
41+
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt,
42+
TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, fold_regions,
4343
};
4444
use rustc_middle::{bug, span_bug};
4545
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@@ -394,7 +394,118 @@ pub trait GenericArgsLowerer<'a, 'tcx> {
394394
) -> ty::GenericArg<'tcx>;
395395
}
396396

397+
struct ForbidMCGParamUsesFolder<'tcx> {
398+
tcx: TyCtxt<'tcx>,
399+
anon_const_def_id: LocalDefId,
400+
span: Span,
401+
is_self_alias: bool,
402+
}
403+
404+
impl<'tcx> ForbidMCGParamUsesFolder<'tcx> {
405+
fn error(&self) -> ErrorGuaranteed {
406+
let msg = if self.is_self_alias {
407+
"generic `Self` types are currently not permitted in anonymous constants"
408+
} else {
409+
"generic parameters may not be used in const operations"
410+
};
411+
let mut diag = self.tcx.dcx().struct_span_err(self.span, msg);
412+
if self.is_self_alias {
413+
let anon_const_hir_id: HirId = HirId::make_owner(self.anon_const_def_id);
414+
let parent_impl = self.tcx.hir_parent_owner_iter(anon_const_hir_id).find_map(
415+
|(_, node)| match node {
416+
hir::OwnerNode::Item(hir::Item {
417+
kind: hir::ItemKind::Impl(impl_), ..
418+
}) => Some(impl_),
419+
_ => None,
420+
},
421+
);
422+
if let Some(impl_) = parent_impl {
423+
diag.span_note(impl_.self_ty.span, "not a concrete type");
424+
}
425+
}
426+
diag.emit()
427+
}
428+
}
429+
430+
impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for ForbidMCGParamUsesFolder<'tcx> {
431+
fn cx(&self) -> TyCtxt<'tcx> {
432+
self.tcx
433+
}
434+
435+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
436+
if matches!(t.kind(), ty::Param(..)) {
437+
return Ty::new_error(self.tcx, self.error());
438+
}
439+
t.super_fold_with(self)
440+
}
441+
442+
fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> {
443+
if matches!(c.kind(), ty::ConstKind::Param(..)) {
444+
return Const::new_error(self.tcx, self.error());
445+
}
446+
c.super_fold_with(self)
447+
}
448+
449+
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
450+
if matches!(r.kind(), ty::RegionKind::ReEarlyParam(..) | ty::RegionKind::ReLateParam(..)) {
451+
return ty::Region::new_error(self.tcx, self.error());
452+
}
453+
r
454+
}
455+
}
456+
397457
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
458+
/// See `check_param_uses_if_mcg`.
459+
///
460+
/// FIXME(mgca): this is pub only for instantiate_value_path and would be nice to avoid altogether
461+
pub fn check_param_res_if_mcg_for_instantiate_value_path(
462+
&self,
463+
res: Res,
464+
span: Span,
465+
) -> Result<(), ErrorGuaranteed> {
466+
let tcx = self.tcx();
467+
let parent_def_id = self.item_def_id();
468+
if let Res::Def(DefKind::ConstParam, _) = res
469+
&& tcx.def_kind(parent_def_id) == DefKind::AnonConst
470+
&& let ty::AnonConstKind::MCG = tcx.anon_const_kind(parent_def_id)
471+
{
472+
let folder = ForbidMCGParamUsesFolder {
473+
tcx,
474+
anon_const_def_id: parent_def_id,
475+
span,
476+
is_self_alias: false,
477+
};
478+
return Err(folder.error());
479+
}
480+
Ok(())
481+
}
482+
483+
/// Check for uses of generic parameters that are not in scope due to this being
484+
/// in a non-generic anon const context.
485+
#[must_use = "need to use transformed output"]
486+
fn check_param_uses_if_mcg<T>(&self, term: T, span: Span, is_self_alias: bool) -> T
487+
where
488+
T: ty::TypeFoldable<TyCtxt<'tcx>>,
489+
{
490+
let tcx = self.tcx();
491+
let parent_def_id = self.item_def_id();
492+
if tcx.def_kind(parent_def_id) == DefKind::AnonConst
493+
&& let ty::AnonConstKind::MCG = tcx.anon_const_kind(parent_def_id)
494+
// Fast path if contains no params/escaping bound vars.
495+
&& (term.has_param() || term.has_escaping_bound_vars())
496+
{
497+
let mut folder = ForbidMCGParamUsesFolder {
498+
tcx,
499+
anon_const_def_id: parent_def_id,
500+
span,
501+
is_self_alias,
502+
};
503+
term.fold_with(&mut folder)
504+
} else {
505+
term
506+
}
507+
}
508+
398509
/// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*.
399510
#[instrument(level = "debug", skip(self), ret)]
400511
pub fn lower_lifetime(
@@ -403,15 +514,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
403514
reason: RegionInferReason<'_>,
404515
) -> ty::Region<'tcx> {
405516
if let Some(resolved) = self.tcx().named_bound_var(lifetime.hir_id) {
406-
self.lower_resolved_lifetime(resolved)
517+
let region = self.lower_resolved_lifetime(resolved);
518+
self.check_param_uses_if_mcg(region, lifetime.ident.span, false)
407519
} else {
408520
self.re_infer(lifetime.ident.span, reason)
409521
}
410522
}
411523

412524
/// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*.
413525
#[instrument(level = "debug", skip(self), ret)]
414-
pub fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> {
526+
fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> {
415527
let tcx = self.tcx();
416528

417529
match resolved {
@@ -1256,9 +1368,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12561368
TypeRelativePath::AssocItem(def_id, args) => {
12571369
let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args);
12581370
let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty);
1371+
let ty = self.check_param_uses_if_mcg(ty, span, false);
12591372
Ok((ty, tcx.def_kind(def_id), def_id))
12601373
}
12611374
TypeRelativePath::Variant { adt, variant_did } => {
1375+
let adt = self.check_param_uses_if_mcg(adt, span, false);
12621376
Ok((adt, DefKind::Variant, variant_did))
12631377
}
12641378
}
@@ -1275,7 +1389,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12751389
span: Span,
12761390
) -> Result<Const<'tcx>, ErrorGuaranteed> {
12771391
let tcx = self.tcx();
1278-
let (def_id, args) = match self.lower_type_relative_path(
1392+
match self.lower_type_relative_path(
12791393
self_ty,
12801394
hir_self_ty,
12811395
segment,
@@ -1292,15 +1406,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12921406
err.note("the declaration in the trait must be marked with `#[type_const]`");
12931407
return Err(err.emit());
12941408
}
1295-
(def_id, args)
1409+
let ct = Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args));
1410+
let ct = self.check_param_uses_if_mcg(ct, span, false);
1411+
Ok(ct)
12961412
}
12971413
// FIXME(mgca): implement support for this once ready to support all adt ctor expressions,
12981414
// not just const ctors
12991415
TypeRelativePath::Variant { .. } => {
13001416
span_bug!(span, "unexpected variant res for type associated const path")
13011417
}
1302-
};
1303-
Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args)))
1418+
}
13041419
}
13051420

13061421
/// Lower a [type-relative][hir::QPath::TypeRelative] (and type-level) path.
@@ -2032,9 +2147,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
20322147
GenericsArgsErrExtend::None
20332148
},
20342149
);
2035-
tcx.types.self_param
2150+
self.check_param_uses_if_mcg(tcx.types.self_param, span, false)
20362151
}
2037-
Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
2152+
Res::SelfTyAlias { alias_to: def_id, forbid_generic: _, .. } => {
20382153
// `Self` in impl (we know the concrete type).
20392154
assert_eq!(opt_self_ty, None);
20402155
// Try to evaluate any array length constants.
@@ -2043,42 +2158,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
20432158
path.segments.iter(),
20442159
GenericsArgsErrExtend::SelfTyAlias { def_id, span },
20452160
);
2046-
// HACK(min_const_generics): Forbid generic `Self` types
2047-
// here as we can't easily do that during nameres.
2048-
//
2049-
// We do this before normalization as we otherwise allow
2050-
// ```rust
2051-
// trait AlwaysApplicable { type Assoc; }
2052-
// impl<T: ?Sized> AlwaysApplicable for T { type Assoc = usize; }
2053-
//
2054-
// trait BindsParam<T> {
2055-
// type ArrayTy;
2056-
// }
2057-
// impl<T> BindsParam<T> for <T as AlwaysApplicable>::Assoc {
2058-
// type ArrayTy = [u8; Self::MAX];
2059-
// }
2060-
// ```
2061-
// Note that the normalization happens in the param env of
2062-
// the anon const, which is empty. This is why the
2063-
// `AlwaysApplicable` impl needs a `T: ?Sized` bound for
2064-
// this to compile if we were to normalize here.
2065-
if forbid_generic && ty.has_param() {
2066-
let mut err = self.dcx().struct_span_err(
2067-
path.span,
2068-
"generic `Self` types are currently not permitted in anonymous constants",
2069-
);
2070-
if let Some(hir::Node::Item(&hir::Item {
2071-
kind: hir::ItemKind::Impl(impl_),
2072-
..
2073-
})) = tcx.hir_get_if_local(def_id)
2074-
{
2075-
err.span_note(impl_.self_ty.span, "not a concrete type");
2076-
}
2077-
let reported = err.emit();
2078-
Ty::new_error(tcx, reported)
2079-
} else {
2080-
ty
2081-
}
2161+
self.check_param_uses_if_mcg(ty, span, true)
20822162
}
20832163
Res::Def(DefKind::AssocTy, def_id) => {
20842164
let trait_segment = if let [modules @ .., trait_, _item] = path.segments {
@@ -2138,7 +2218,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
21382218
/// and late-bound ones to [`ty::Bound`].
21392219
pub(crate) fn lower_ty_param(&self, hir_id: HirId) -> Ty<'tcx> {
21402220
let tcx = self.tcx();
2141-
match tcx.named_bound_var(hir_id) {
2221+
2222+
let ty = match tcx.named_bound_var(hir_id) {
21422223
Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => {
21432224
let br = ty::BoundTy {
21442225
var: ty::BoundVar::from_u32(index),
@@ -2154,7 +2235,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
21542235
}
21552236
Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar),
21562237
arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
2157-
}
2238+
};
2239+
self.check_param_uses_if_mcg(ty, tcx.hir_span(hir_id), false)
21582240
}
21592241

21602242
/// Lower a const parameter from the HIR to our internal notion of a constant.
@@ -2164,7 +2246,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
21642246
pub(crate) fn lower_const_param(&self, param_def_id: DefId, path_hir_id: HirId) -> Const<'tcx> {
21652247
let tcx = self.tcx();
21662248

2167-
match tcx.named_bound_var(path_hir_id) {
2249+
let ct = match tcx.named_bound_var(path_hir_id) {
21682250
Some(rbv::ResolvedArg::EarlyBound(_)) => {
21692251
// Find the name and index of the const parameter by indexing the generics of
21702252
// the parent item and construct a `ParamConst`.
@@ -2181,7 +2263,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
21812263
),
21822264
Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar),
21832265
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id),
2184-
}
2266+
};
2267+
self.check_param_uses_if_mcg(ct, tcx.hir_span(path_hir_id), false)
21852268
}
21862269

21872270
/// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`](Const).
@@ -2386,7 +2469,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23862469
) -> Const<'tcx> {
23872470
let tcx = self.tcx();
23882471
let span = path.span;
2389-
match path.res {
2472+
let ct = match path.res {
23902473
Res::Def(DefKind::ConstParam, def_id) => {
23912474
assert_eq!(opt_self_ty, None);
23922475
let _ = self.prohibit_generic_args(
@@ -2475,7 +2558,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24752558
span,
24762559
format!("invalid Res {res:?} for const path"),
24772560
),
2478-
}
2561+
};
2562+
self.check_param_uses_if_mcg(ct, span, false)
24792563
}
24802564

24812565
/// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`.
@@ -2520,20 +2604,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
25202604
_ => expr,
25212605
};
25222606

2523-
// FIXME(mgca): remove this delayed bug once we start checking this
2524-
// when lowering `Ty/ConstKind::Param`s more generally.
2525-
if let hir::ExprKind::Path(hir::QPath::Resolved(
2526-
_,
2527-
&hir::Path { res: Res::Def(DefKind::ConstParam, _), .. },
2528-
)) = expr.kind
2529-
{
2530-
let e = tcx.dcx().span_delayed_bug(
2531-
expr.span,
2532-
"try_lower_anon_const_lit: received const param which shouldn't be possible",
2533-
);
2534-
return Some(ty::Const::new_error(tcx, e));
2535-
};
2536-
25372607
let lit_input = match expr.kind {
25382608
hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: false }),
25392609
hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind {
@@ -2787,6 +2857,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
27872857
let args = ty::GenericArgs::for_item(tcx, def_id, |param, _| {
27882858
if let Some(i) = (param.index as usize).checked_sub(offset) {
27892859
let (lifetime, _) = lifetimes[i];
2860+
// FIXME(mgca): should we be calling self.check_params_use_if_mcg here too?
27902861
self.lower_resolved_lifetime(lifetime).into()
27912862
} else {
27922863
tcx.mk_param_from_def(param)

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10041004
err_extend,
10051005
);
10061006

1007+
if let Err(e) = self.lowerer().check_param_res_if_mcg_for_instantiate_value_path(res, span)
1008+
{
1009+
return (Ty::new_error(self.tcx, e), res);
1010+
}
1011+
10071012
if let Res::Local(hid) = res {
10081013
let ty = self.local_ty(span, hid);
10091014
let ty = self.normalize(span, ty);

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,6 @@ fn typeck_with_inspect<'tcx>(
115115
return tcx.typeck(typeck_root_def_id);
116116
}
117117

118-
// We can't handle bodies containing generic parameters even though
119-
// these generic parameters aren't part of its `generics_of` right now.
120-
//
121-
// See the FIXME on `check_anon_const_invalid_param_uses`.
122-
if tcx.features().min_generic_const_args()
123-
&& let DefKind::AnonConst = tcx.def_kind(def_id)
124-
&& let ty::AnonConstKind::MCG = tcx.anon_const_kind(def_id)
125-
&& let Err(e) = tcx.check_anon_const_invalid_param_uses(def_id)
126-
{
127-
e.raise_fatal();
128-
}
129-
130118
let id = tcx.local_def_id_to_hir_id(def_id);
131119
let node = tcx.hir_node(id);
132120
let span = tcx.def_span(def_id);

0 commit comments

Comments
 (0)