Skip to content

Commit

Permalink
mark ty::Const::Error when meet unsupport ty for const generic params
Browse files Browse the repository at this point in the history
  • Loading branch information
bvanjoi committed Oct 25, 2023
1 parent b66fe58 commit ce80d0e
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 39 deletions.
56 changes: 18 additions & 38 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
return Err(ValTreeCreationError::NodesOverflow);
}

if ty::maybe_not_supported_generic_const_param(ty).is_some_and(|v| v) {
return Err(ValTreeCreationError::NonSupportedType);
}

match ty.kind() {
ty::FnDef(..) => {
*num_nodes += 1;
Expand All @@ -97,62 +101,38 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
Ok(ty::ValTree::Leaf(val.assert_int()))
}

// Raw pointers are not allowed in type level constants, as we cannot properly test them for
// equality at compile-time (see `ptr_guaranteed_cmp`).
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
// agree with runtime equality tests.
ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),

ty::Ref(_, _, _) => {
let Ok(derefd_place)= ecx.deref_pointer(place) else {
ty::Ref(_, _, _) => {
let Ok(derefd_place) = ecx.deref_pointer(place) else {
return Err(ValTreeCreationError::Other);
};
debug!(?derefd_place);

const_to_valtree_inner(ecx, &derefd_place, num_nodes)
}

ty::Str | ty::Slice(_) | ty::Array(_, _) => {
slice_branches(ecx, place, num_nodes)
}
// Trait objects are not allowed in type level constants, as we have no concept for
// resolving their backing type, even if we can do that at const eval time. We may
// hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
// but it is unclear if this is useful.
ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType),

ty::Tuple(elem_tys) => {
branches(ecx, place, elem_tys.len(), None, num_nodes)
}
ty::Str | ty::Slice(_) | ty::Array(_, _) => slice_branches(ecx, place, num_nodes),

ty::Tuple(elem_tys) => branches(ecx, place, elem_tys.len(), None, num_nodes),

ty::Adt(def, _) => {
if def.is_union() {
return Err(ValTreeCreationError::NonSupportedType);
unreachable!();
} else if def.variants().is_empty() {
bug!("uninhabited types should have errored and never gotten converted to valtree")
}

let Ok(variant) = ecx.read_discriminant(place) else {
return Err(ValTreeCreationError::Other);
};
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
branches(
ecx,
place,
def.variant(variant).fields.len(),
def.is_enum().then_some(variant),
num_nodes,
)
}

ty::Never
| ty::Error(_)
| ty::Foreign(..)
| ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_))
// FIXME(oli-obk): we could look behind opaque types
| ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(_)
// FIXME(oli-obk): we can probably encode closures just like structs
| ty::Closure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType),
_ => unreachable!(),
}
}

Expand Down
12 changes: 11 additions & 1 deletion compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,20 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
kind: GenericParamKind::Const { default: Some(ct), .. },
..
}) if ct.hir_id == hir_id => {
return tcx
let ty = tcx
.type_of(param_def_id)
.no_bound_vars()
.expect("const parameter types cannot be generic");

if ty::maybe_not_supported_generic_const_param(ty).is_some_and(|v| v) {
return Ty::new_error_with_message(
tcx,
tcx.def_span(def_id),
"meet unsupported const generics type",
)
} else {
return ty;
}
}

Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
Expand Down
36 changes: 36 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,42 @@ pub struct CReaderCacheKey {
#[rustc_pass_by_value]
pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>);

pub fn maybe_not_supported_generic_const_param(ty: Ty<'_>) -> Option<bool> {
match ty.kind() {
// Raw pointers are not allowed in type level constants, as we cannot properly test them for
// equality at compile-time (see `ptr_guaranteed_cmp`).
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
// agree with runtime equality tests.
ty::FnPtr(_) | ty::RawPtr(_) => {
Some(true)
},
// Trait objects are not allowed in type level constants, as we have no concept for
// resolving their backing type, even if we can do that at const eval time. We may
// hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
// but it is unclear if this is useful.
ty::Dynamic(..) => Some(true),
ty::Adt(def, _) => {
def.is_union().then_some(true)
},
ty::Never
| ty::Error(_)
| ty::Foreign(..)
| ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_))
// FIXME(oli-obk): we could look behind opaque types
| ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(_)
// FIXME(oli-obk): we can probably encode closures just like structs
| ty::Closure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..) => Some(true),
_ => None,
}
}

impl ty::EarlyBoundRegion {
/// Does this early bound region have a name? Early bound regions normally
/// always have names except when using anonymous lifetimes (`'_`).
Expand Down
3 changes: 3 additions & 0 deletions tests/ui/consts/issue-116796.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
struct X<const FN: fn() = { || {} }>;
//~^ ERROR using function pointers as const generic parameters is forbidden
fn main() {}
10 changes: 10 additions & 0 deletions tests/ui/consts/issue-116796.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: using function pointers as const generic parameters is forbidden
--> $DIR/issue-116796.rs:1:20
|
LL | struct X<const FN: fn() = { || {} }>;
| ^^^^
|
= note: the only supported types are integers, `bool` and `char`

error: aborting due to previous error

0 comments on commit ce80d0e

Please sign in to comment.