Deeply deny fn and raw ptrs in const generics

This commit is contained in:
Michael Goulet 2022-07-23 20:09:52 +00:00
parent babff2211e
commit 1152e70363
17 changed files with 147 additions and 61 deletions

View File

@ -226,7 +226,7 @@ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
// because that component may be part of an enum variant (e.g.,
// `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
// structural-match (`Option::None`).
traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty, true).is_some()
traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty, false).is_some()
}
fn in_adt_inherently<'tcx>(

View File

@ -203,7 +203,7 @@ pub fn from_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Se
pub fn to_valtree(self) -> ty::ValTree<'tcx> {
match self.kind() {
ty::ConstKind::Value(valtree) => valtree,
_ => bug!("expected ConstKind::Value"),
_ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
}
}

View File

@ -120,7 +120,7 @@ fn adt_derive_msg(&self, adt_def: AdtDef<'tcx>) -> String {
}
fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
traits::search_for_structural_match_violation(self.span, self.tcx(), ty, true).map(
traits::search_for_structural_match_violation(self.span, self.tcx(), ty, false).map(
|non_sm_ty| {
with_no_trimmed_paths!(match non_sm_ty.kind {
traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt),
@ -139,6 +139,12 @@ fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String>
traits::NonStructuralMatchTyKind::Float => {
"floating-point numbers cannot be used in patterns".to_string()
}
traits::NonStructuralMatchTyKind::FnPtr => {
"function pointers cannot be used in patterns".to_string()
}
traits::NonStructuralMatchTyKind::RawPtr => {
"raw pointers cannot be used in patterns".to_string()
}
traits::NonStructuralMatchTyKind::Param => {
bug!("use of a constant whose type is a parameter inside a pattern")
}

View File

@ -27,6 +27,8 @@ pub enum NonStructuralMatchTyKind<'tcx> {
Generator,
Projection,
Float,
FnPtr,
RawPtr,
}
/// This method traverses the structure of `ty`, trying to find an
@ -55,14 +57,15 @@ pub enum NonStructuralMatchTyKind<'tcx> {
/// that arose when the requirement was not enforced completely, see
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
///
/// The floats_allowed flag is used to deny constants in floating point
/// When the `valtree_semantics` flag is set, then we also deny additional
/// types that are not evaluatable to valtrees, such as floats and fn ptrs.
pub fn search_for_structural_match_violation<'tcx>(
span: Span,
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
floats_allowed: bool,
valtree_semantics: bool,
) -> Option<NonStructuralMatchTy<'tcx>> {
ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), floats_allowed })
ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), valtree_semantics })
.break_value()
}
@ -125,7 +128,9 @@ struct Search<'tcx> {
/// we will not recur on them again.
seen: FxHashSet<hir::def_id::DefId>,
floats_allowed: bool,
// Additionally deny things that have been allowed in patterns,
// but are not evaluatable to a valtree, such as floats and fn ptrs.
valtree_semantics: bool,
}
impl<'tcx> Search<'tcx> {
@ -170,24 +175,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
let kind = NonStructuralMatchTyKind::Generator;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
}
ty::RawPtr(..) => {
// structural-match ignores substructure of
// `*const _`/`*mut _`, so skip `super_visit_with`.
//
// For example, if you have:
// ```
// struct NonStructural;
// #[derive(PartialEq, Eq)]
// struct T(*const NonStructural);
// const C: T = T(std::ptr::null());
// ```
//
// Even though `NonStructural` does not implement `PartialEq`,
// structural equality on `T` does not recur into the raw
// pointer. Therefore, one can still use `C` in a pattern.
return ControlFlow::CONTINUE;
}
ty::FnDef(..) | ty::FnPtr(..) => {
ty::FnDef(..) => {
// Types of formals and return in `fn(_) -> _` are also irrelevant;
// so we do not recur into them via `super_visit_with`
return ControlFlow::CONTINUE;
@ -206,8 +194,44 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
return ControlFlow::CONTINUE;
}
ty::FnPtr(..) => {
if !self.valtree_semantics {
return ControlFlow::CONTINUE;
} else {
return ControlFlow::Break(NonStructuralMatchTy {
ty,
kind: NonStructuralMatchTyKind::FnPtr,
});
}
}
ty::RawPtr(..) => {
if !self.valtree_semantics {
// structural-match ignores substructure of
// `*const _`/`*mut _`, so skip `super_visit_with`.
//
// For example, if you have:
// ```
// struct NonStructural;
// #[derive(PartialEq, Eq)]
// struct T(*const NonStructural);
// const C: T = T(std::ptr::null());
// ```
//
// Even though `NonStructural` does not implement `PartialEq`,
// structural equality on `T` does not recur into the raw
// pointer. Therefore, one can still use `C` in a pattern.
return ControlFlow::CONTINUE;
} else {
return ControlFlow::Break(NonStructuralMatchTy {
ty,
kind: NonStructuralMatchTyKind::FnPtr,
});
}
}
ty::Float(_) => {
if self.floats_allowed {
if !self.valtree_semantics {
return ControlFlow::CONTINUE;
} else {
return ControlFlow::Break(NonStructuralMatchTy {

View File

@ -848,29 +848,13 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
if tcx.features().adt_const_params {
let err = match ty.peel_refs().kind() {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => None,
};
if let Some(unsupported_type) = err {
tcx.sess.span_err(
hir_ty.span,
&format!(
"using {} as const generic parameters is forbidden",
unsupported_type
),
);
}
if let Some(non_structural_match_ty) =
traits::search_for_structural_match_violation(param.span, tcx, ty, false)
traits::search_for_structural_match_violation(param.span, tcx, ty, true)
{
// We use the same error code in both branches, because this is really the same
// issue: we just special-case the message for type parameters to make it
// clearer.
match ty.peel_refs().kind() {
match non_structural_match_ty.ty.kind() {
ty::Param(_) => {
// Const parameters may not have type parameters as their types,
// because we cannot be sure that the type parameter derives `PartialEq`
@ -902,6 +886,24 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
.note("floats do not derive `Eq` or `Ord`, which are required for const parameters")
.emit();
}
ty::FnPtr(_) => {
struct_span_err!(
tcx.sess,
hir_ty.span,
E0741,
"using function pointers as const generic parameters is forbidden",
)
.emit();
}
ty::RawPtr(_) => {
struct_span_err!(
tcx.sess,
hir_ty.span,
E0741,
"using raw pointers as const generic parameters is forbidden",
)
.emit();
}
_ => {
let mut diag = struct_span_err!(
tcx.sess,

View File

@ -1,10 +1,10 @@
error: using function pointers as const generic parameters is forbidden
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-call.rs:11:25
|
LL | struct Wrapper<const F: fn() -> u32>;
| ^^^^^^^^^^^
error: using function pointers as const generic parameters is forbidden
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-call.rs:13:15
|
LL | impl<const F: fn() -> u32> Wrapper<F> {
@ -12,3 +12,4 @@ LL | impl<const F: fn() -> u32> Wrapper<F> {
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0741`.

View File

@ -1,4 +1,4 @@
error: using function pointers as const generic parameters is forbidden
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-infer.rs:6:25
|
LL | struct Checked<const F: fn(usize) -> bool>;
@ -6,3 +6,4 @@ LL | struct Checked<const F: fn(usize) -> bool>;
error: aborting due to previous error
For more information about this error, try `rustc --explain E0741`.

View File

@ -10,13 +10,13 @@ error[E0770]: the type of const parameters must not depend on other generic para
LL | const FN: unsafe extern "C" fn(Args),
| ^^^^ the type must not depend on the parameter `Args`
error: using function pointers as const generic parameters is forbidden
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-71381.rs:14:61
|
LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: using function pointers as const generic parameters is forbidden
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-71381.rs:23:19
|
LL | const FN: unsafe extern "C" fn(Args),
@ -24,4 +24,5 @@ LL | const FN: unsafe extern "C" fn(Args),
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0770`.
Some errors have detailed explanations: E0741, E0770.
For more information about an error, try `rustc --explain E0741`.

View File

@ -1,4 +1,4 @@
error: using function pointers as const generic parameters is forbidden
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-71382.rs:16:23
|
LL | fn test<const FN: fn()>(&self) {
@ -6,3 +6,4 @@ LL | fn test<const FN: fn()>(&self) {
error: aborting due to previous error
For more information about this error, try `rustc --explain E0741`.

View File

@ -4,7 +4,7 @@ error[E0770]: the type of const parameters must not depend on other generic para
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
| ^ the type must not depend on the parameter `A`
error: using function pointers as const generic parameters is forbidden
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-71611.rs:5:21
|
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
@ -12,4 +12,5 @@ LL | fn func<A, const F: fn(inner: A)>(outer: A) {
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0770`.
Some errors have detailed explanations: E0741, E0770.
For more information about an error, try `rustc --explain E0741`.

View File

@ -1,4 +1,4 @@
error: using function pointers as const generic parameters is forbidden
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-72352.rs:7:42
|
LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8) -> usize {
@ -6,3 +6,4 @@ LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8
error: aborting due to previous error
For more information about this error, try `rustc --explain E0741`.

View File

@ -0,0 +1,18 @@
#![feature(adt_const_params)]
#![allow(incomplete_features)]
fn main() {
pub struct Color<const WHITE: (fn(),)>;
//~^ ERROR using function pointers
impl<const WHITE: (fn(),)> Color<WHITE> {
//~^ ERROR using function pointers
pub fn new() -> Self {
Color::<WHITE>
}
}
pub const D65: (fn(),) = (|| {},);
Color::<D65>::new();
}

View File

@ -0,0 +1,15 @@
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-99641.rs:5:35
|
LL | pub struct Color<const WHITE: (fn(),)>;
| ^^^^^^^
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-99641.rs:8:23
|
LL | impl<const WHITE: (fn(),)> Color<WHITE> {
| ^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0741`.

View File

@ -1,10 +1,10 @@
error: using raw pointers as const generic parameters is forbidden
error[E0741]: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param-deref.rs:9:23
|
LL | struct Const<const P: *const u32>;
| ^^^^^^^^^^
error: using raw pointers as const generic parameters is forbidden
error[E0741]: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param-deref.rs:11:15
|
LL | impl<const P: *const u32> Const<P> {
@ -12,3 +12,4 @@ LL | impl<const P: *const u32> Const<P> {
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0741`.

View File

@ -1,4 +1,4 @@
error: using raw pointers as const generic parameters is forbidden
error[E0741]: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param.rs:6:23
|
LL | struct Const<const P: *const u32>;
@ -6,3 +6,4 @@ LL | struct Const<const P: *const u32>;
error: aborting due to previous error
For more information about this error, try `rustc --explain E0741`.

View File

@ -1,5 +1,3 @@
// check-pass
#![feature(fn_traits)]
#![feature(adt_const_params)]
//~^ WARNING the feature `adt_const_params` is incomplete
@ -10,8 +8,10 @@ struct CompileTimeSettings{
}
struct Foo<const T: CompileTimeSettings>;
//~^ ERROR using function pointers as const generic parameters is forbidden
impl<const T: CompileTimeSettings> Foo<T> {
//~^ ERROR using function pointers as const generic parameters is forbidden
fn call_hooks(){
}
}

View File

@ -1,5 +1,5 @@
warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/refs_check_const_eq-issue-88384.rs:4:12
--> $DIR/refs_check_const_eq-issue-88384.rs:2:12
|
LL | #![feature(adt_const_params)]
| ^^^^^^^^^^^^^^^^
@ -7,5 +7,18 @@ LL | #![feature(adt_const_params)]
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
warning: 1 warning emitted
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/refs_check_const_eq-issue-88384.rs:10:21
|
LL | struct Foo<const T: CompileTimeSettings>;
| ^^^^^^^^^^^^^^^^^^^
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/refs_check_const_eq-issue-88384.rs:13:15
|
LL | impl<const T: CompileTimeSettings> Foo<T> {
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0741`.