Skip to content

Commit 1152e70

Browse files
Deeply deny fn and raw ptrs in const generics
1 parent babff22 commit 1152e70

17 files changed

+147
-61
lines changed

compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ impl Qualif for CustomEq {
226226
// because that component may be part of an enum variant (e.g.,
227227
// `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
228228
// structural-match (`Option::None`).
229-
traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty, true).is_some()
229+
traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty, false).is_some()
230230
}
231231

232232
fn in_adt_inherently<'tcx>(

compiler/rustc_middle/src/ty/consts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ impl<'tcx> Const<'tcx> {
203203
pub fn to_valtree(self) -> ty::ValTree<'tcx> {
204204
match self.kind() {
205205
ty::ConstKind::Value(valtree) => valtree,
206-
_ => bug!("expected ConstKind::Value"),
206+
_ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
207207
}
208208
}
209209

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
120120
}
121121

122122
fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
123-
traits::search_for_structural_match_violation(self.span, self.tcx(), ty, true).map(
123+
traits::search_for_structural_match_violation(self.span, self.tcx(), ty, false).map(
124124
|non_sm_ty| {
125125
with_no_trimmed_paths!(match non_sm_ty.kind {
126126
traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt),
@@ -139,6 +139,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
139139
traits::NonStructuralMatchTyKind::Float => {
140140
"floating-point numbers cannot be used in patterns".to_string()
141141
}
142+
traits::NonStructuralMatchTyKind::FnPtr => {
143+
"function pointers cannot be used in patterns".to_string()
144+
}
145+
traits::NonStructuralMatchTyKind::RawPtr => {
146+
"raw pointers cannot be used in patterns".to_string()
147+
}
142148
traits::NonStructuralMatchTyKind::Param => {
143149
bug!("use of a constant whose type is a parameter inside a pattern")
144150
}

compiler/rustc_trait_selection/src/traits/structural_match.rs

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ pub enum NonStructuralMatchTyKind<'tcx> {
2727
Generator,
2828
Projection,
2929
Float,
30+
FnPtr,
31+
RawPtr,
3032
}
3133

3234
/// This method traverses the structure of `ty`, trying to find an
@@ -55,14 +57,15 @@ pub enum NonStructuralMatchTyKind<'tcx> {
5557
/// that arose when the requirement was not enforced completely, see
5658
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
5759
///
58-
/// The floats_allowed flag is used to deny constants in floating point
60+
/// When the `valtree_semantics` flag is set, then we also deny additional
61+
/// types that are not evaluatable to valtrees, such as floats and fn ptrs.
5962
pub fn search_for_structural_match_violation<'tcx>(
6063
span: Span,
6164
tcx: TyCtxt<'tcx>,
6265
ty: Ty<'tcx>,
63-
floats_allowed: bool,
66+
valtree_semantics: bool,
6467
) -> Option<NonStructuralMatchTy<'tcx>> {
65-
ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), floats_allowed })
68+
ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), valtree_semantics })
6669
.break_value()
6770
}
6871

@@ -125,7 +128,9 @@ struct Search<'tcx> {
125128
/// we will not recur on them again.
126129
seen: FxHashSet<hir::def_id::DefId>,
127130

128-
floats_allowed: bool,
131+
// Additionally deny things that have been allowed in patterns,
132+
// but are not evaluatable to a valtree, such as floats and fn ptrs.
133+
valtree_semantics: bool,
129134
}
130135

131136
impl<'tcx> Search<'tcx> {
@@ -170,24 +175,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
170175
let kind = NonStructuralMatchTyKind::Generator;
171176
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
172177
}
173-
ty::RawPtr(..) => {
174-
// structural-match ignores substructure of
175-
// `*const _`/`*mut _`, so skip `super_visit_with`.
176-
//
177-
// For example, if you have:
178-
// ```
179-
// struct NonStructural;
180-
// #[derive(PartialEq, Eq)]
181-
// struct T(*const NonStructural);
182-
// const C: T = T(std::ptr::null());
183-
// ```
184-
//
185-
// Even though `NonStructural` does not implement `PartialEq`,
186-
// structural equality on `T` does not recur into the raw
187-
// pointer. Therefore, one can still use `C` in a pattern.
188-
return ControlFlow::CONTINUE;
189-
}
190-
ty::FnDef(..) | ty::FnPtr(..) => {
178+
ty::FnDef(..) => {
191179
// Types of formals and return in `fn(_) -> _` are also irrelevant;
192180
// so we do not recur into them via `super_visit_with`
193181
return ControlFlow::CONTINUE;
@@ -206,8 +194,44 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
206194
return ControlFlow::CONTINUE;
207195
}
208196

197+
ty::FnPtr(..) => {
198+
if !self.valtree_semantics {
199+
return ControlFlow::CONTINUE;
200+
} else {
201+
return ControlFlow::Break(NonStructuralMatchTy {
202+
ty,
203+
kind: NonStructuralMatchTyKind::FnPtr,
204+
});
205+
}
206+
}
207+
208+
ty::RawPtr(..) => {
209+
if !self.valtree_semantics {
210+
// structural-match ignores substructure of
211+
// `*const _`/`*mut _`, so skip `super_visit_with`.
212+
//
213+
// For example, if you have:
214+
// ```
215+
// struct NonStructural;
216+
// #[derive(PartialEq, Eq)]
217+
// struct T(*const NonStructural);
218+
// const C: T = T(std::ptr::null());
219+
// ```
220+
//
221+
// Even though `NonStructural` does not implement `PartialEq`,
222+
// structural equality on `T` does not recur into the raw
223+
// pointer. Therefore, one can still use `C` in a pattern.
224+
return ControlFlow::CONTINUE;
225+
} else {
226+
return ControlFlow::Break(NonStructuralMatchTy {
227+
ty,
228+
kind: NonStructuralMatchTyKind::FnPtr,
229+
});
230+
}
231+
}
232+
209233
ty::Float(_) => {
210-
if self.floats_allowed {
234+
if !self.valtree_semantics {
211235
return ControlFlow::CONTINUE;
212236
} else {
213237
return ControlFlow::Break(NonStructuralMatchTy {

compiler/rustc_typeck/src/check/wfcheck.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -848,29 +848,13 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
848848
let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
849849

850850
if tcx.features().adt_const_params {
851-
let err = match ty.peel_refs().kind() {
852-
ty::FnPtr(_) => Some("function pointers"),
853-
ty::RawPtr(_) => Some("raw pointers"),
854-
_ => None,
855-
};
856-
857-
if let Some(unsupported_type) = err {
858-
tcx.sess.span_err(
859-
hir_ty.span,
860-
&format!(
861-
"using {} as const generic parameters is forbidden",
862-
unsupported_type
863-
),
864-
);
865-
}
866-
867851
if let Some(non_structural_match_ty) =
868-
traits::search_for_structural_match_violation(param.span, tcx, ty, false)
852+
traits::search_for_structural_match_violation(param.span, tcx, ty, true)
869853
{
870854
// We use the same error code in both branches, because this is really the same
871855
// issue: we just special-case the message for type parameters to make it
872856
// clearer.
873-
match ty.peel_refs().kind() {
857+
match non_structural_match_ty.ty.kind() {
874858
ty::Param(_) => {
875859
// Const parameters may not have type parameters as their types,
876860
// because we cannot be sure that the type parameter derives `PartialEq`
@@ -902,6 +886,24 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
902886
.note("floats do not derive `Eq` or `Ord`, which are required for const parameters")
903887
.emit();
904888
}
889+
ty::FnPtr(_) => {
890+
struct_span_err!(
891+
tcx.sess,
892+
hir_ty.span,
893+
E0741,
894+
"using function pointers as const generic parameters is forbidden",
895+
)
896+
.emit();
897+
}
898+
ty::RawPtr(_) => {
899+
struct_span_err!(
900+
tcx.sess,
901+
hir_ty.span,
902+
E0741,
903+
"using raw pointers as const generic parameters is forbidden",
904+
)
905+
.emit();
906+
}
905907
_ => {
906908
let mut diag = struct_span_err!(
907909
tcx.sess,
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
error: using function pointers as const generic parameters is forbidden
1+
error[E0741]: using function pointers as const generic parameters is forbidden
22
--> $DIR/fn-const-param-call.rs:11:25
33
|
44
LL | struct Wrapper<const F: fn() -> u32>;
55
| ^^^^^^^^^^^
66

7-
error: using function pointers as const generic parameters is forbidden
7+
error[E0741]: using function pointers as const generic parameters is forbidden
88
--> $DIR/fn-const-param-call.rs:13:15
99
|
1010
LL | impl<const F: fn() -> u32> Wrapper<F> {
1111
| ^^^^^^^^^^^
1212

1313
error: aborting due to 2 previous errors
1414

15+
For more information about this error, try `rustc --explain E0741`.
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
error: using function pointers as const generic parameters is forbidden
1+
error[E0741]: using function pointers as const generic parameters is forbidden
22
--> $DIR/fn-const-param-infer.rs:6:25
33
|
44
LL | struct Checked<const F: fn(usize) -> bool>;
55
| ^^^^^^^^^^^^^^^^^
66

77
error: aborting due to previous error
88

9+
For more information about this error, try `rustc --explain E0741`.

src/test/ui/const-generics/issues/issue-71381.full.stderr

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,19 @@ error[E0770]: the type of const parameters must not depend on other generic para
1010
LL | const FN: unsafe extern "C" fn(Args),
1111
| ^^^^ the type must not depend on the parameter `Args`
1212

13-
error: using function pointers as const generic parameters is forbidden
13+
error[E0741]: using function pointers as const generic parameters is forbidden
1414
--> $DIR/issue-71381.rs:14:61
1515
|
1616
LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
1717
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
1818

19-
error: using function pointers as const generic parameters is forbidden
19+
error[E0741]: using function pointers as const generic parameters is forbidden
2020
--> $DIR/issue-71381.rs:23:19
2121
|
2222
LL | const FN: unsafe extern "C" fn(Args),
2323
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
2424

2525
error: aborting due to 4 previous errors
2626

27-
For more information about this error, try `rustc --explain E0770`.
27+
Some errors have detailed explanations: E0741, E0770.
28+
For more information about an error, try `rustc --explain E0741`.
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
error: using function pointers as const generic parameters is forbidden
1+
error[E0741]: using function pointers as const generic parameters is forbidden
22
--> $DIR/issue-71382.rs:16:23
33
|
44
LL | fn test<const FN: fn()>(&self) {
55
| ^^^^
66

77
error: aborting due to previous error
88

9+
For more information about this error, try `rustc --explain E0741`.

src/test/ui/const-generics/issues/issue-71611.full.stderr

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ error[E0770]: the type of const parameters must not depend on other generic para
44
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
55
| ^ the type must not depend on the parameter `A`
66

7-
error: using function pointers as const generic parameters is forbidden
7+
error[E0741]: using function pointers as const generic parameters is forbidden
88
--> $DIR/issue-71611.rs:5:21
99
|
1010
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
1111
| ^^^^^^^^^^^^
1212

1313
error: aborting due to 2 previous errors
1414

15-
For more information about this error, try `rustc --explain E0770`.
15+
Some errors have detailed explanations: E0741, E0770.
16+
For more information about an error, try `rustc --explain E0741`.
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
error: using function pointers as const generic parameters is forbidden
1+
error[E0741]: using function pointers as const generic parameters is forbidden
22
--> $DIR/issue-72352.rs:7:42
33
|
44
LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8) -> usize {
55
| ^^^^^^^^^^^^^^^^^^
66

77
error: aborting due to previous error
88

9+
For more information about this error, try `rustc --explain E0741`.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![feature(adt_const_params)]
2+
#![allow(incomplete_features)]
3+
4+
fn main() {
5+
pub struct Color<const WHITE: (fn(),)>;
6+
//~^ ERROR using function pointers
7+
8+
impl<const WHITE: (fn(),)> Color<WHITE> {
9+
//~^ ERROR using function pointers
10+
pub fn new() -> Self {
11+
Color::<WHITE>
12+
}
13+
}
14+
15+
pub const D65: (fn(),) = (|| {},);
16+
17+
Color::<D65>::new();
18+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0741]: using function pointers as const generic parameters is forbidden
2+
--> $DIR/issue-99641.rs:5:35
3+
|
4+
LL | pub struct Color<const WHITE: (fn(),)>;
5+
| ^^^^^^^
6+
7+
error[E0741]: using function pointers as const generic parameters is forbidden
8+
--> $DIR/issue-99641.rs:8:23
9+
|
10+
LL | impl<const WHITE: (fn(),)> Color<WHITE> {
11+
| ^^^^^^^
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0741`.
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
error: using raw pointers as const generic parameters is forbidden
1+
error[E0741]: using raw pointers as const generic parameters is forbidden
22
--> $DIR/raw-ptr-const-param-deref.rs:9:23
33
|
44
LL | struct Const<const P: *const u32>;
55
| ^^^^^^^^^^
66

7-
error: using raw pointers as const generic parameters is forbidden
7+
error[E0741]: using raw pointers as const generic parameters is forbidden
88
--> $DIR/raw-ptr-const-param-deref.rs:11:15
99
|
1010
LL | impl<const P: *const u32> Const<P> {
1111
| ^^^^^^^^^^
1212

1313
error: aborting due to 2 previous errors
1414

15+
For more information about this error, try `rustc --explain E0741`.
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
error: using raw pointers as const generic parameters is forbidden
1+
error[E0741]: using raw pointers as const generic parameters is forbidden
22
--> $DIR/raw-ptr-const-param.rs:6:23
33
|
44
LL | struct Const<const P: *const u32>;
55
| ^^^^^^^^^^
66

77
error: aborting due to previous error
88

9+
For more information about this error, try `rustc --explain E0741`.

src/test/ui/consts/refs_check_const_eq-issue-88384.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// check-pass
2-
31
#![feature(fn_traits)]
42
#![feature(adt_const_params)]
53
//~^ WARNING the feature `adt_const_params` is incomplete
@@ -10,8 +8,10 @@ struct CompileTimeSettings{
108
}
119

1210
struct Foo<const T: CompileTimeSettings>;
11+
//~^ ERROR using function pointers as const generic parameters is forbidden
1312

1413
impl<const T: CompileTimeSettings> Foo<T> {
14+
//~^ ERROR using function pointers as const generic parameters is forbidden
1515
fn call_hooks(){
1616
}
1717
}

0 commit comments

Comments
 (0)