Skip to content

Commit ce80d0e

Browse files
committed
mark ty::Const::Error when meet unsupport ty for const generic params
1 parent b66fe58 commit ce80d0e

File tree

5 files changed

+78
-39
lines changed

5 files changed

+78
-39
lines changed

compiler/rustc_const_eval/src/const_eval/valtrees.rs

+18-38
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
8282
return Err(ValTreeCreationError::NodesOverflow);
8383
}
8484

85+
if ty::maybe_not_supported_generic_const_param(ty).is_some_and(|v| v) {
86+
return Err(ValTreeCreationError::NonSupportedType);
87+
}
88+
8589
match ty.kind() {
8690
ty::FnDef(..) => {
8791
*num_nodes += 1;
@@ -97,62 +101,38 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
97101
Ok(ty::ValTree::Leaf(val.assert_int()))
98102
}
99103

100-
// Raw pointers are not allowed in type level constants, as we cannot properly test them for
101-
// equality at compile-time (see `ptr_guaranteed_cmp`).
102-
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
103-
// agree with runtime equality tests.
104-
ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
105-
106-
ty::Ref(_, _, _) => {
107-
let Ok(derefd_place)= ecx.deref_pointer(place) else {
104+
ty::Ref(_, _, _) => {
105+
let Ok(derefd_place) = ecx.deref_pointer(place) else {
108106
return Err(ValTreeCreationError::Other);
109107
};
110108
debug!(?derefd_place);
111109

112110
const_to_valtree_inner(ecx, &derefd_place, num_nodes)
113111
}
114112

115-
ty::Str | ty::Slice(_) | ty::Array(_, _) => {
116-
slice_branches(ecx, place, num_nodes)
117-
}
118-
// Trait objects are not allowed in type level constants, as we have no concept for
119-
// resolving their backing type, even if we can do that at const eval time. We may
120-
// hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
121-
// but it is unclear if this is useful.
122-
ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType),
123-
124-
ty::Tuple(elem_tys) => {
125-
branches(ecx, place, elem_tys.len(), None, num_nodes)
126-
}
113+
ty::Str | ty::Slice(_) | ty::Array(_, _) => slice_branches(ecx, place, num_nodes),
114+
115+
ty::Tuple(elem_tys) => branches(ecx, place, elem_tys.len(), None, num_nodes),
127116

128117
ty::Adt(def, _) => {
129118
if def.is_union() {
130-
return Err(ValTreeCreationError::NonSupportedType);
119+
unreachable!();
131120
} else if def.variants().is_empty() {
132121
bug!("uninhabited types should have errored and never gotten converted to valtree")
133122
}
134123

135124
let Ok(variant) = ecx.read_discriminant(place) else {
136125
return Err(ValTreeCreationError::Other);
137126
};
138-
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
127+
branches(
128+
ecx,
129+
place,
130+
def.variant(variant).fields.len(),
131+
def.is_enum().then_some(variant),
132+
num_nodes,
133+
)
139134
}
140-
141-
ty::Never
142-
| ty::Error(_)
143-
| ty::Foreign(..)
144-
| ty::Infer(ty::FreshIntTy(_))
145-
| ty::Infer(ty::FreshFloatTy(_))
146-
// FIXME(oli-obk): we could look behind opaque types
147-
| ty::Alias(..)
148-
| ty::Param(_)
149-
| ty::Bound(..)
150-
| ty::Placeholder(..)
151-
| ty::Infer(_)
152-
// FIXME(oli-obk): we can probably encode closures just like structs
153-
| ty::Closure(..)
154-
| ty::Coroutine(..)
155-
| ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType),
135+
_ => unreachable!(),
156136
}
157137
}
158138

compiler/rustc_hir_analysis/src/collect/type_of.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,20 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
5454
kind: GenericParamKind::Const { default: Some(ct), .. },
5555
..
5656
}) if ct.hir_id == hir_id => {
57-
return tcx
57+
let ty = tcx
5858
.type_of(param_def_id)
5959
.no_bound_vars()
6060
.expect("const parameter types cannot be generic");
61+
62+
if ty::maybe_not_supported_generic_const_param(ty).is_some_and(|v| v) {
63+
return Ty::new_error_with_message(
64+
tcx,
65+
tcx.def_span(def_id),
66+
"meet unsupported const generics type",
67+
)
68+
} else {
69+
return ty;
70+
}
6171
}
6272

6373
Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })

compiler/rustc_middle/src/ty/mod.rs

+36
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,42 @@ pub struct CReaderCacheKey {
462462
#[rustc_pass_by_value]
463463
pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>);
464464

465+
pub fn maybe_not_supported_generic_const_param(ty: Ty<'_>) -> Option<bool> {
466+
match ty.kind() {
467+
// Raw pointers are not allowed in type level constants, as we cannot properly test them for
468+
// equality at compile-time (see `ptr_guaranteed_cmp`).
469+
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
470+
// agree with runtime equality tests.
471+
ty::FnPtr(_) | ty::RawPtr(_) => {
472+
Some(true)
473+
},
474+
// Trait objects are not allowed in type level constants, as we have no concept for
475+
// resolving their backing type, even if we can do that at const eval time. We may
476+
// hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
477+
// but it is unclear if this is useful.
478+
ty::Dynamic(..) => Some(true),
479+
ty::Adt(def, _) => {
480+
def.is_union().then_some(true)
481+
},
482+
ty::Never
483+
| ty::Error(_)
484+
| ty::Foreign(..)
485+
| ty::Infer(ty::FreshIntTy(_))
486+
| ty::Infer(ty::FreshFloatTy(_))
487+
// FIXME(oli-obk): we could look behind opaque types
488+
| ty::Alias(..)
489+
| ty::Param(_)
490+
| ty::Bound(..)
491+
| ty::Placeholder(..)
492+
| ty::Infer(_)
493+
// FIXME(oli-obk): we can probably encode closures just like structs
494+
| ty::Closure(..)
495+
| ty::Coroutine(..)
496+
| ty::CoroutineWitness(..) => Some(true),
497+
_ => None,
498+
}
499+
}
500+
465501
impl ty::EarlyBoundRegion {
466502
/// Does this early bound region have a name? Early bound regions normally
467503
/// always have names except when using anonymous lifetimes (`'_`).

tests/ui/consts/issue-116796.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct X<const FN: fn() = { || {} }>;
2+
//~^ ERROR using function pointers as const generic parameters is forbidden
3+
fn main() {}

tests/ui/consts/issue-116796.stderr

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: using function pointers as const generic parameters is forbidden
2+
--> $DIR/issue-116796.rs:1:20
3+
|
4+
LL | struct X<const FN: fn() = { || {} }>;
5+
| ^^^^
6+
|
7+
= note: the only supported types are integers, `bool` and `char`
8+
9+
error: aborting due to previous error
10+

0 commit comments

Comments
 (0)