Skip to content

Commit bd1e7c7

Browse files
committed
Auto merge of #153815 - GokhanKabar:fix-ice-enum-discr-generic-self, r=BoxyUwU
Fix ICE when Self is used in enum discriminant of a generic enum Fixes #153756 Let discriminant AnonConst inherit parent generics via Node::Variant in generics_of, and emit a proper error instead of span_bug! for the TooGeneric case in wfcheck.
2 parents a5c825c + aacac7e commit bd1e7c7

File tree

5 files changed

+139
-23
lines changed

5 files changed

+139
-23
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 88 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -380,24 +380,44 @@ pub trait GenericArgsLowerer<'a, 'tcx> {
380380
) -> ty::GenericArg<'tcx>;
381381
}
382382

383-
struct ForbidMCGParamUsesFolder<'tcx> {
383+
/// Context in which `ForbidParamUsesFolder` is being used, to emit appropriate diagnostics.
384+
enum ForbidParamContext {
385+
/// Anon const in a const argument position.
386+
ConstArgument,
387+
/// Enum discriminant expression.
388+
EnumDiscriminant,
389+
}
390+
391+
struct ForbidParamUsesFolder<'tcx> {
384392
tcx: TyCtxt<'tcx>,
385393
anon_const_def_id: LocalDefId,
386394
span: Span,
387395
is_self_alias: bool,
396+
context: ForbidParamContext,
388397
}
389398

390-
impl<'tcx> ForbidMCGParamUsesFolder<'tcx> {
399+
impl<'tcx> ForbidParamUsesFolder<'tcx> {
391400
fn error(&self) -> ErrorGuaranteed {
392-
let msg = if self.is_self_alias {
393-
"generic `Self` types are currently not permitted in anonymous constants"
394-
} else if self.tcx.features().generic_const_args() {
395-
"generic parameters in const blocks are only allowed as the direct value of a `type const`"
396-
} else {
397-
"generic parameters may not be used in const operations"
401+
let msg = match self.context {
402+
ForbidParamContext::EnumDiscriminant if self.is_self_alias => {
403+
"generic `Self` types are not permitted in enum discriminant values"
404+
}
405+
ForbidParamContext::EnumDiscriminant => {
406+
"generic parameters may not be used in enum discriminant values"
407+
}
408+
ForbidParamContext::ConstArgument if self.is_self_alias => {
409+
"generic `Self` types are currently not permitted in anonymous constants"
410+
}
411+
ForbidParamContext::ConstArgument => {
412+
if self.tcx.features().generic_const_args() {
413+
"generic parameters in const blocks are only allowed as the direct value of a `type const`"
414+
} else {
415+
"generic parameters may not be used in const operations"
416+
}
417+
}
398418
};
399419
let mut diag = self.tcx.dcx().struct_span_err(self.span, msg);
400-
if self.is_self_alias {
420+
if self.is_self_alias && matches!(self.context, ForbidParamContext::ConstArgument) {
401421
let anon_const_hir_id: HirId = HirId::make_owner(self.anon_const_def_id);
402422
let parent_impl = self.tcx.hir_parent_owner_iter(anon_const_hir_id).find_map(
403423
|(_, node)| match node {
@@ -411,18 +431,20 @@ impl<'tcx> ForbidMCGParamUsesFolder<'tcx> {
411431
diag.span_note(impl_.self_ty.span, "not a concrete type");
412432
}
413433
}
414-
if self.tcx.features().min_generic_const_args() {
434+
if matches!(self.context, ForbidParamContext::ConstArgument)
435+
&& self.tcx.features().min_generic_const_args()
436+
{
415437
if !self.tcx.features().generic_const_args() {
416438
diag.help("add `#![feature(generic_const_args)]` to allow generic expressions as the RHS of const items");
417439
} else {
418440
diag.help("consider factoring the expression into a `type const` item and use it as the const argument instead");
419441
}
420-
};
442+
}
421443
diag.emit()
422444
}
423445
}
424446

425-
impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for ForbidMCGParamUsesFolder<'tcx> {
447+
impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for ForbidParamUsesFolder<'tcx> {
426448
fn cx(&self) -> TyCtxt<'tcx> {
427449
self.tcx
428450
}
@@ -464,37 +486,80 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
464486
&& tcx.def_kind(parent_def_id) == DefKind::AnonConst
465487
&& let ty::AnonConstKind::MCG = tcx.anon_const_kind(parent_def_id)
466488
{
467-
let folder = ForbidMCGParamUsesFolder {
489+
let folder = ForbidParamUsesFolder {
468490
tcx,
469491
anon_const_def_id: parent_def_id,
470492
span,
471493
is_self_alias: false,
494+
context: ForbidParamContext::ConstArgument,
472495
};
473496
return Err(folder.error());
474497
}
475498
Ok(())
476499
}
477500

501+
/// Returns the `ForbidParamContext` for the current anon const if it is a context that
502+
/// forbids uses of generic parameters. `None` if the current item is not such a context.
503+
///
504+
/// Name resolution handles most invalid generic parameter uses in these contexts, but it
505+
/// cannot reject `Self` that aliases a generic type, nor generic parameters introduced by
506+
/// type-dependent name resolution (e.g. `<Self as Trait>::Assoc` resolving to a type that
507+
/// contains params). Those cases are handled by `check_param_uses_if_mcg`.
508+
fn anon_const_forbids_generic_params(&self) -> Option<ForbidParamContext> {
509+
let tcx = self.tcx();
510+
let parent_def_id = self.item_def_id();
511+
512+
// Inline consts and closures can be nested inside anon consts that forbid generic
513+
// params (e.g. an enum discriminant). Walk up the def parent chain to find the
514+
// nearest enclosing AnonConst and use that to determine the context.
515+
let anon_const_def_id = match tcx.def_kind(parent_def_id) {
516+
DefKind::AnonConst => parent_def_id,
517+
DefKind::InlineConst | DefKind::Closure => {
518+
let root = tcx.typeck_root_def_id(parent_def_id.into());
519+
match tcx.def_kind(root) {
520+
DefKind::AnonConst => root.expect_local(),
521+
_ => return None,
522+
}
523+
}
524+
_ => return None,
525+
};
526+
527+
match tcx.anon_const_kind(anon_const_def_id) {
528+
ty::AnonConstKind::MCG => Some(ForbidParamContext::ConstArgument),
529+
ty::AnonConstKind::NonTypeSystem => {
530+
// NonTypeSystem anon consts only have accessible generic parameters in specific
531+
// positions (ty patterns and field defaults — see `generics_of`). In all other
532+
// positions (e.g. enum discriminants) generic parameters are not in scope.
533+
if tcx.generics_of(anon_const_def_id).count() == 0 {
534+
Some(ForbidParamContext::EnumDiscriminant)
535+
} else {
536+
None
537+
}
538+
}
539+
ty::AnonConstKind::GCE
540+
| ty::AnonConstKind::GCA
541+
| ty::AnonConstKind::RepeatExprCount => None,
542+
}
543+
}
544+
478545
/// Check for uses of generic parameters that are not in scope due to this being
479-
/// in a non-generic anon const context.
546+
/// in a non-generic anon const context (e.g. MCG or an enum discriminant).
547+
///
548+
/// Name resolution rejects most invalid uses, but cannot handle `Self` aliasing a
549+
/// generic type or generic parameters introduced by type-dependent name resolution.
480550
#[must_use = "need to use transformed output"]
481551
fn check_param_uses_if_mcg<T>(&self, term: T, span: Span, is_self_alias: bool) -> T
482552
where
483553
T: ty::TypeFoldable<TyCtxt<'tcx>>,
484554
{
485555
let tcx = self.tcx();
486-
let parent_def_id = self.item_def_id();
487-
if tcx.def_kind(parent_def_id) == DefKind::AnonConst
488-
&& let ty::AnonConstKind::MCG = tcx.anon_const_kind(parent_def_id)
556+
if let Some(context) = self.anon_const_forbids_generic_params()
489557
// Fast path if contains no params/escaping bound vars.
490558
&& (term.has_param() || term.has_escaping_bound_vars())
491559
{
492-
let mut folder = ForbidMCGParamUsesFolder {
493-
tcx,
494-
anon_const_def_id: parent_def_id,
495-
span,
496-
is_self_alias,
497-
};
560+
let anon_const_def_id = self.item_def_id();
561+
let mut folder =
562+
ForbidParamUsesFolder { tcx, anon_const_def_id, span, is_self_alias, context };
498563
term.fold_with(&mut folder)
499564
} else {
500565
term
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![feature(sized_hierarchy)]
2+
3+
use std::marker::PointeeSized;
4+
5+
#[repr(usize)]
6+
enum What<T: PointeeSized> {
7+
X = size_of::<*mut Self>(),
8+
//~^ ERROR generic `Self` types are not permitted in enum discriminant values
9+
Y(*mut T),
10+
}
11+
12+
fn main() {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: generic `Self` types are not permitted in enum discriminant values
2+
--> $DIR/generic-self-in-discr-ice.rs:7:24
3+
|
4+
LL | X = size_of::<*mut Self>(),
5+
| ^^^^
6+
7+
error: aborting due to 1 previous error
8+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ check-fail
2+
// Test that `Self` is rejected even when nested inside an inline const
3+
// or closure within an enum discriminant. Regression test for issue #154281.
4+
#![feature(sized_hierarchy)]
5+
6+
use std::marker::PointeeSized;
7+
8+
#[repr(usize)]
9+
enum What<T: PointeeSized> {
10+
X = const { { let _: *mut Self; 1_usize } },
11+
//~^ ERROR generic `Self` types are not permitted in enum discriminant values
12+
Y = { let _f = || { let _: *mut Self; }; 1_usize },
13+
//~^ ERROR generic `Self` types are not permitted in enum discriminant values
14+
Z(*mut T),
15+
}
16+
17+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: generic `Self` types are not permitted in enum discriminant values
2+
--> $DIR/generic-self-in-discr-inline-const.rs:10:31
3+
|
4+
LL | X = const { { let _: *mut Self; 1_usize } },
5+
| ^^^^
6+
7+
error: generic `Self` types are not permitted in enum discriminant values
8+
--> $DIR/generic-self-in-discr-inline-const.rs:12:37
9+
|
10+
LL | Y = { let _f = || { let _: *mut Self; }; 1_usize },
11+
| ^^^^
12+
13+
error: aborting due to 2 previous errors
14+

0 commit comments

Comments
 (0)