Skip to content

Commit

Permalink
Lint on function pointers used in patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Sep 20, 2020
1 parent 3795886 commit aba5ea1
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 3 deletions.
19 changes: 18 additions & 1 deletion compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Expand Up @@ -351,10 +351,27 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => {
PatKind::Constant { value: cv }
}
ty::RawPtr(pointee) if pointee.ty.is_sized(tcx.at(span), param_env) => {
PatKind::Constant { value: cv }
}
// FIXME: these can have very suprising behaviour where optimization levels or other
// compilation choices change the runtime behaviour of the match.
// See https://github.com/rust-lang/rust/issues/70861 for examples.
ty::FnPtr(..) | ty::RawPtr(..) => PatKind::Constant { value: cv },
ty::FnPtr(..) | ty::RawPtr(..) => {
if self.include_lint_checks && !self.saw_const_match_error.get() {
self.saw_const_match_error.set(true);
let msg = "function pointers and unsized pointers in patterns do not behave \
deterministically. \
See https://github.com/rust-lang/rust/issues/70861 for details.";
tcx.struct_span_lint_hir(
lint::builtin::POINTER_STRUCTURAL_MATCH,
id,
span,
|lint| lint.build(&msg).emit(),
);
}
PatKind::Constant { value: cv }
}
_ => {
tcx.sess.delay_span_bug(span, &format!("cannot make a pattern out of {}", cv.ty));
PatKind::Wild
Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_session/src/lint/builtin.rs
Expand Up @@ -2197,6 +2197,32 @@ declare_lint! {
report_in_external_macro
}

declare_lint! {
/// The `pointer_structural_match` lint detects pointers used in patterns that do not
/// behave deterministically across optimizations.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(pointer_structural_match)]
/// fn foo(a: usize, b: usize) -> usize { a + b }
/// const FOO: fn(usize, usize) -> usize = foo;
/// fn main() {
/// match FOO {
/// FOO => {},
/// _ => {},
/// }
/// }
/// ```
pub POINTER_STRUCTURAL_MATCH,
Allow,
"pointers are not structural-match",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #62411 <https://github.com/rust-lang/rust/issues/70861>",
edition: None,
};
}

declare_lint! {
/// The `ambiguous_associated_items` lint detects ambiguity between
/// [associated items] and [enum variants].
Expand Down Expand Up @@ -2630,6 +2656,7 @@ declare_lint_pass! {
AMBIGUOUS_ASSOCIATED_ITEMS,
MUTABLE_BORROW_RESERVATION_CONFLICT,
INDIRECT_STRUCTURAL_MATCH,
POINTER_STRUCTURAL_MATCH,
SOFT_UNSTABLE,
INLINE_NO_SANITIZE,
ASM_SUB_REGISTER,
Expand Down
9 changes: 7 additions & 2 deletions src/test/ui/issues/issue-44333.rs
@@ -1,4 +1,7 @@
// run-pass

#![warn(pointer_structural_match)]

type Func = fn(usize, usize) -> usize;

fn foo(a: usize, b: usize) -> usize { a + b }
Expand All @@ -13,8 +16,10 @@ const BAR: Func = bar;

fn main() {
match test(std::env::consts::ARCH.len()) {
FOO => println!("foo"),
BAR => println!("bar"),
FOO => println!("foo"), //~ WARN pointers in patterns do not behave deterministically
//~^ WARN will become a hard error
BAR => println!("bar"), //~ WARN pointers in patterns do not behave deterministically
//~^ WARN will become a hard error
_ => unreachable!(),
}
}
25 changes: 25 additions & 0 deletions src/test/ui/issues/issue-44333.stderr
@@ -0,0 +1,25 @@
warning: function pointers and unsized pointers in patterns do not behave deterministically. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/issue-44333.rs:19:9
|
LL | FOO => println!("foo"),
| ^^^
|
note: the lint level is defined here
--> $DIR/issue-44333.rs:3:9
|
LL | #![warn(pointer_structural_match)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>

warning: function pointers and unsized pointers in patterns do not behave deterministically. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/issue-44333.rs:21:9
|
LL | BAR => println!("bar"),
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>

warning: 2 warnings emitted

4 changes: 4 additions & 0 deletions src/test/ui/rfc1445/issue-63479-match-fnptr.rs
Expand Up @@ -5,6 +5,8 @@
// cover the case this hit; I've since expanded it accordingly, but the
// experience left me wary of leaving this regression test out.)

#![warn(pointer_structural_match)]

#[derive(Eq)]
struct A {
a: i64
Expand All @@ -31,6 +33,8 @@ fn main() {
let s = B(my_fn);
match s {
B(TEST) => println!("matched"),
//~^ WARN pointers in patterns do not behave deterministically
//~| WARN this was previously accepted by the compiler but is being phased out
_ => panic!("didn't match")
};
}
16 changes: 16 additions & 0 deletions src/test/ui/rfc1445/issue-63479-match-fnptr.stderr
@@ -0,0 +1,16 @@
warning: function pointers and unsized pointers in patterns do not behave deterministically. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/issue-63479-match-fnptr.rs:35:7
|
LL | B(TEST) => println!("matched"),
| ^^^^
|
note: the lint level is defined here
--> $DIR/issue-63479-match-fnptr.rs:8:9
|
LL | #![warn(pointer_structural_match)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>

warning: 1 warning emitted

0 comments on commit aba5ea1

Please sign in to comment.