Skip to content

patterns: reject raw pointers that are not just integers #116930

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 8, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 27 additions & 10 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
@@ -97,11 +97,27 @@ 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`).
ty::RawPtr(_) => {
// Not all raw pointers are allowed, as we cannot properly test them for
// equality at compile-time (see `ptr_guaranteed_cmp`).
// However we allow those that are just integers in disguise.
// (We could allow wide raw pointers where both sides are integers in the future,
// but for now we reject them.)
let Ok(val) = ecx.read_scalar(place) else {
return Err(ValTreeCreationError::Other);
};
// We are in the CTFE machine, so ptr-to-int casts will fail.
// This can only be `Ok` if `val` already is an integer.
let Ok(val) = val.try_to_int() else {
return Err(ValTreeCreationError::Other);
};
// It's just a ScalarInt!
Ok(ty::ValTree::Leaf(val))
}

// 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::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType),

ty::Ref(_, _, _) => {
let Ok(derefd_place)= ecx.deref_pointer(place) else {
@@ -222,12 +238,14 @@ pub fn valtree_to_const_value<'tcx>(
assert!(valtree.unwrap_branch().is_empty());
mir::ConstValue::ZeroSized
}
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => match valtree {
ty::ValTree::Leaf(scalar_int) => mir::ConstValue::Scalar(Scalar::Int(scalar_int)),
ty::ValTree::Branch(_) => bug!(
"ValTrees for Bool, Int, Uint, Float or Char should have the form ValTree::Leaf"
),
},
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(_) => {
match valtree {
ty::ValTree::Leaf(scalar_int) => mir::ConstValue::Scalar(Scalar::Int(scalar_int)),
ty::ValTree::Branch(_) => bug!(
"ValTrees for Bool, Int, Uint, Float, Char or RawPtr should have the form ValTree::Leaf"
),
}
}
ty::Ref(_, inner_ty, _) => {
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty);
@@ -281,7 +299,6 @@ pub fn valtree_to_const_value<'tcx>(
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::FnPtr(_)
| ty::RawPtr(_)
| ty::Str
| ty::Slice(_)
| ty::Dynamic(..) => bug!("no ValTree should have been created for type {:?}", ty.kind()),
7 changes: 4 additions & 3 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
@@ -2217,15 +2217,16 @@ declare_lint! {
///
/// ### Explanation
///
/// Previous versions of Rust allowed function pointers and wide raw pointers in patterns.
/// Previous versions of Rust allowed function pointers and all raw pointers in patterns.
/// While these work in many cases as expected by users, it is possible that due to
/// optimizations pointers are "not equal to themselves" or pointers to different functions
/// compare as equal during runtime. This is because LLVM optimizations can deduplicate
/// functions if their bodies are the same, thus also making pointers to these functions point
/// to the same location. Additionally functions may get duplicated if they are instantiated
/// in different crates and not deduplicated again via LTO.
/// in different crates and not deduplicated again via LTO. Pointer identity for memory
/// created by `const` is similarly unreliable.
pub POINTER_STRUCTURAL_MATCH,
Allow,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize this lint is still allow-by-default oO. Seems high time we make it warn-by-default?

Warn,
"pointers are not structural-match",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/messages.ftl
Original file line number Diff line number Diff line change
@@ -242,7 +242,7 @@ mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpo
mir_build_pattern_not_covered = refutable pattern in {$origin}
.pattern_ty = the matched value is of type `{$pattern_ty}`

mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
mir_build_pointer_pattern = function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.

mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future

61 changes: 31 additions & 30 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
@@ -123,6 +123,8 @@ impl<'tcx> ConstToPat<'tcx> {
});
debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation);

let have_valtree =
matches!(cv, mir::Const::Ty(c) if matches!(c.kind(), ty::ConstKind::Value(_)));
let inlined_const_as_pat = match cv {
mir::Const::Ty(c) => match c.kind() {
ty::ConstKind::Param(_)
@@ -209,16 +211,6 @@ impl<'tcx> ConstToPat<'tcx> {
} else if !self.saw_const_match_lint.get() {
if let Some(mir_structural_match_violation) = mir_structural_match_violation {
match non_sm_ty.kind() {
ty::RawPtr(pointee)
if pointee.ty.is_sized(self.tcx(), self.param_env) => {}
ty::FnPtr(..) | ty::RawPtr(..) => {
self.tcx().emit_spanned_lint(
lint::builtin::POINTER_STRUCTURAL_MATCH,
self.id,
self.span,
PointerPattern,
);
}
ty::Adt(..) if mir_structural_match_violation => {
self.tcx().emit_spanned_lint(
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
@@ -236,19 +228,15 @@ impl<'tcx> ConstToPat<'tcx> {
}
}
}
} else if !self.saw_const_match_lint.get() {
match cv.ty().kind() {
ty::RawPtr(pointee) if pointee.ty.is_sized(self.tcx(), self.param_env) => {}
ty::FnPtr(..) | ty::RawPtr(..) => {
self.tcx().emit_spanned_lint(
lint::builtin::POINTER_STRUCTURAL_MATCH,
self.id,
self.span,
PointerPattern,
);
}
_ => {}
}
} else if !have_valtree && !self.saw_const_match_lint.get() {
// The only way valtree construction can fail without the structural match
// checker finding a violation is if there is a pointer somewhere.
self.tcx().emit_spanned_lint(
lint::builtin::POINTER_STRUCTURAL_MATCH,
self.id,
self.span,
PointerPattern,
);
}

// Always check for `PartialEq`, even if we emitted other lints. (But not if there were
@@ -389,11 +377,19 @@ impl<'tcx> ConstToPat<'tcx> {
subpatterns: self
.field_pats(cv.unwrap_branch().iter().copied().zip(fields.iter()))?,
},
ty::Adt(def, args) => PatKind::Leaf {
subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip(
def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx(), args)),
))?,
},
ty::Adt(def, args) => {
assert!(!def.is_union()); // Valtree construction would never succeed for unions.
PatKind::Leaf {
subpatterns: self.field_pats(
cv.unwrap_branch().iter().copied().zip(
def.non_enum_variant()
.fields
.iter()
.map(|field| field.ty(self.tcx(), args)),
),
)?,
}
}
ty::Slice(elem_ty) => PatKind::Slice {
prefix: cv
.unwrap_branch()
@@ -480,10 +476,15 @@ impl<'tcx> ConstToPat<'tcx> {
}
}
},
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
// The raw pointers we see here have been "vetted" by valtree construction to be
// just integers, so we simply allow them.
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
}
ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(),
ty::FnPtr(..) => {
// Valtree construction would never succeed for these, so this is unreachable.
unreachable!()
}
_ => {
let err = InvalidPattern { span, non_sm_ty: ty };
let e = tcx.sess.emit_err(err);
1 change: 1 addition & 0 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
@@ -247,6 +247,7 @@ marker_impls! {
///
/// const CFN: Wrap<fn(&())> = Wrap(higher_order);
///
/// #[allow(pointer_structural_match)]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW these entire trait docs are outdated; that's tracked in #115881.

/// fn main() {
/// match CFN {
/// CFN => {}
Original file line number Diff line number Diff line change
@@ -26,7 +26,8 @@ pub fn edge_case_str(event: String) {
pub fn edge_case_raw_ptr(event: *const i32) {
let _ = || {
match event {
NUMBER_POINTER => (),
NUMBER_POINTER => (), //~WARN behave unpredictably
//~| previously accepted
_ => (),
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/match-edge-cases_1.rs:29:13
|
LL | NUMBER_POINTER => (),
| ^^^^^^^^^^^^^^
|
= 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>
= note: `#[warn(pointer_structural_match)]` on by default

warning: 1 warning emitted

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#![deny(pointer_structural_match)]
#![allow(dead_code)]

const C: *const u8 = &0;
// Make sure we also find pointers nested in other types.
const C_INNER: (*const u8, u8) = (C, 0);

fn foo(x: *const u8) {
match x {
C => {} //~ERROR: behave unpredictably
//~| previously accepted
_ => {}
}
}

fn foo2(x: *const u8) {
match (x, 1) {
C_INNER => {} //~ERROR: behave unpredictably
//~| previously accepted
_ => {}
}
}

const D: *const [u8; 4] = b"abcd";

fn main() {
match D {
D => {} //~ERROR: behave unpredictably
//~| previously accepted
_ => {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:10:9
|
LL | C => {}
| ^
|
= 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>
note: the lint level is defined here
--> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9
|
LL | #![deny(pointer_structural_match)]
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:18:9
|
LL | C_INNER => {}
| ^^^^^^^
|
= 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>

error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:28:9
|
LL | D => {}
| ^
|
= 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>

error: aborting due to 3 previous errors

4 changes: 2 additions & 2 deletions tests/ui/consts/const_in_pattern/issue-44333.rs
Original file line number Diff line number Diff line change
@@ -16,9 +16,9 @@ const BAR: Func = bar;

fn main() {
match test(std::env::consts::ARCH.len()) {
FOO => println!("foo"), //~ WARN pointers in patterns behave unpredictably
FOO => println!("foo"), //~ WARN behave unpredictably
//~^ WARN will become a hard error
BAR => println!("bar"), //~ WARN pointers in patterns behave unpredictably
BAR => println!("bar"), //~ WARN behave unpredictably
//~^ WARN will become a hard error
_ => unreachable!(),
}
4 changes: 2 additions & 2 deletions tests/ui/consts/const_in_pattern/issue-44333.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/issue-44333.rs:19:9
|
LL | FOO => println!("foo"),
@@ -12,7 +12,7 @@ note: the lint level is defined here
LL | #![warn(pointer_structural_match)]
| ^^^^^^^^^^^^^^^^^^^^^^^^

warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/issue-44333.rs:21:9
|
LL | BAR => println!("bar"),
21 changes: 0 additions & 21 deletions tests/ui/consts/issue-34784.rs

This file was deleted.

24 changes: 16 additions & 8 deletions tests/ui/pattern/usefulness/consts-opaque.rs
Original file line number Diff line number Diff line change
@@ -95,8 +95,10 @@ fn main() {
const QUUX: Quux = quux;

match QUUX {
QUUX => {}
QUUX => {}
QUUX => {} //~WARN behave unpredictably
//~| previously accepted
QUUX => {} //~WARN behave unpredictably
//~| previously accepted
_ => {}
}

@@ -105,14 +107,17 @@ fn main() {
const WRAPQUUX: Wrap<Quux> = Wrap(quux);

match WRAPQUUX {
WRAPQUUX => {}
WRAPQUUX => {}
WRAPQUUX => {} //~WARN behave unpredictably
//~| previously accepted
WRAPQUUX => {} //~WARN behave unpredictably
//~| previously accepted
Wrap(_) => {}
}

match WRAPQUUX {
Wrap(_) => {}
WRAPQUUX => {}
WRAPQUUX => {} //~WARN behave unpredictably
//~| previously accepted
}

match WRAPQUUX {
@@ -121,7 +126,8 @@ fn main() {

match WRAPQUUX {
//~^ ERROR: non-exhaustive patterns: `Wrap(_)` not covered
WRAPQUUX => {}
WRAPQUUX => {} //~WARN behave unpredictably
//~| previously accepted
}

#[derive(PartialEq, Eq)]
@@ -132,9 +138,11 @@ fn main() {
const WHOKNOWSQUUX: WhoKnows<Quux> = WhoKnows::Yay(quux);

match WHOKNOWSQUUX {
WHOKNOWSQUUX => {}
WHOKNOWSQUUX => {} //~WARN behave unpredictably
//~| previously accepted
WhoKnows::Yay(_) => {}
WHOKNOWSQUUX => {}
WHOKNOWSQUUX => {} //~WARN behave unpredictably
//~| previously accepted
WhoKnows::Nope => {}
}
}
84 changes: 78 additions & 6 deletions tests/ui/pattern/usefulness/consts-opaque.stderr
Original file line number Diff line number Diff line change
@@ -91,24 +91,96 @@ LL | BAZ => {}
= note: the traits must be derived, manual `impl`s are not sufficient
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details

warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/consts-opaque.rs:98:9
|
LL | QUUX => {}
| ^^^^
|
= 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>
= note: `#[warn(pointer_structural_match)]` on by default

warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/consts-opaque.rs:100:9
|
LL | QUUX => {}
| ^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/consts-opaque.rs:110:9
|
LL | WRAPQUUX => {}
| ^^^^^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/consts-opaque.rs:112:9
|
LL | WRAPQUUX => {}
| ^^^^^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/consts-opaque.rs:119:9
|
LL | WRAPQUUX => {}
| ^^^^^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/consts-opaque.rs:129:9
|
LL | WRAPQUUX => {}
| ^^^^^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/consts-opaque.rs:141:9
|
LL | WHOKNOWSQUUX => {}
| ^^^^^^^^^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/consts-opaque.rs:144:9
|
LL | WHOKNOWSQUUX => {}
| ^^^^^^^^^^^^
|
= 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>

error[E0004]: non-exhaustive patterns: `Wrap(_)` not covered
--> $DIR/consts-opaque.rs:122:11
--> $DIR/consts-opaque.rs:127:11
|
LL | match WRAPQUUX {
| ^^^^^^^^ pattern `Wrap(_)` not covered
|
note: `Wrap<fn(usize, usize) -> usize>` defined here
--> $DIR/consts-opaque.rs:104:12
--> $DIR/consts-opaque.rs:106:12
|
LL | struct Wrap<T>(T);
| ^^^^
= note: the matched value is of type `Wrap<fn(usize, usize) -> usize>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ WRAPQUUX => {},
LL + Wrap(_) => todo!()
|
LL | WRAPQUUX => {}, Wrap(_) => todo!()
| ++++++++++++++++++++

error: aborting due to 10 previous errors; 1 warning emitted
error: aborting due to 10 previous errors; 9 warnings emitted

For more information about this error, try `rustc --explain E0004`.
Original file line number Diff line number Diff line change
@@ -40,71 +40,80 @@ fn main() {
const CFN1: Wrap<fn()> = Wrap(trivial);
let input: Wrap<fn()> = Wrap(trivial);
match Wrap(input) {
Wrap(CFN1) => count += 1,
Wrap(CFN1) => count += 1, //~WARN behave unpredictably
//~| previously accepted
Wrap(_) => {}
};

// Check that fn(T) is structural-match when T is too.
const CFN2: Wrap<fn(SM)> = Wrap(sm_to);
let input: Wrap<fn(SM)> = Wrap(sm_to);
match Wrap(input) {
Wrap(CFN2) => count += 1,
Wrap(CFN2) => count += 1, //~WARN behave unpredictably
//~| previously accepted
Wrap(_) => {}
};

// Check that fn() -> T is structural-match when T is too.
const CFN3: Wrap<fn() -> SM> = Wrap(to_sm);
let input: Wrap<fn() -> SM> = Wrap(to_sm);
match Wrap(input) {
Wrap(CFN3) => count += 1,
Wrap(CFN3) => count += 1, //~WARN behave unpredictably
//~| previously accepted
Wrap(_) => {}
};

// Check that fn(T) is structural-match even if T is not.
const CFN4: Wrap<fn(NotSM)> = Wrap(not_sm_to);
let input: Wrap<fn(NotSM)> = Wrap(not_sm_to);
match Wrap(input) {
Wrap(CFN4) => count += 1,
Wrap(CFN4) => count += 1, //~WARN behave unpredictably
//~| previously accepted
Wrap(_) => {}
};

// Check that fn() -> T is structural-match even if T is not.
const CFN5: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
let input: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
match Wrap(input) {
Wrap(CFN5) => count += 1,
Wrap(CFN5) => count += 1, //~WARN behave unpredictably
//~| previously accepted
Wrap(_) => {}
};

// Check that fn(&T) is structural-match when T is too.
const CFN6: Wrap<fn(&SM)> = Wrap(r_sm_to);
let input: Wrap<fn(&SM)> = Wrap(r_sm_to);
match Wrap(input) {
Wrap(CFN6) => count += 1,
Wrap(CFN6) => count += 1, //~WARN behave unpredictably
//~| previously accepted
Wrap(_) => {}
};

// Check that fn() -> &T is structural-match when T is too.
const CFN7: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
let input: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
match Wrap(input) {
Wrap(CFN7) => count += 1,
Wrap(CFN7) => count += 1, //~WARN behave unpredictably
//~| previously accepted
Wrap(_) => {}
};

// Check that fn(T) is structural-match even if T is not.
const CFN8: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
let input: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
match Wrap(input) {
Wrap(CFN8) => count += 1,
Wrap(CFN8) => count += 1, //~WARN behave unpredictably
//~| previously accepted
Wrap(_) => {}
};

// Check that fn() -> T is structural-match even if T is not.
const CFN9: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
let input: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
match Wrap(input) {
Wrap(CFN9) => count += 1,
Wrap(CFN9) => count += 1, //~WARN behave unpredictably
//~| previously accepted
Wrap(_) => {}
};

@@ -126,7 +135,8 @@ fn main() {

let input = Foo { alpha: not_sm_to, beta: to_not_sm, gamma: sm_to, delta: to_sm };
match input {
CFOO => count += 1,
CFOO => count += 1, //~WARN behave unpredictably
//~| previously accepted
Foo { .. } => {}
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/fn-ptr-is-structurally-matchable.rs:43:14
|
LL | Wrap(CFN1) => count += 1,
| ^^^^
|
= 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>
= note: `#[warn(pointer_structural_match)]` on by default

warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/fn-ptr-is-structurally-matchable.rs:52:14
|
LL | Wrap(CFN2) => count += 1,
| ^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/fn-ptr-is-structurally-matchable.rs:61:14
|
LL | Wrap(CFN3) => count += 1,
| ^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/fn-ptr-is-structurally-matchable.rs:70:14
|
LL | Wrap(CFN4) => count += 1,
| ^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/fn-ptr-is-structurally-matchable.rs:79:14
|
LL | Wrap(CFN5) => count += 1,
| ^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/fn-ptr-is-structurally-matchable.rs:88:14
|
LL | Wrap(CFN6) => count += 1,
| ^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/fn-ptr-is-structurally-matchable.rs:97:14
|
LL | Wrap(CFN7) => count += 1,
| ^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/fn-ptr-is-structurally-matchable.rs:106:14
|
LL | Wrap(CFN8) => count += 1,
| ^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/fn-ptr-is-structurally-matchable.rs:115:14
|
LL | Wrap(CFN9) => count += 1,
| ^^^^
|
= 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 raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/fn-ptr-is-structurally-matchable.rs:138:9
|
LL | CFOO => count += 1,
| ^^^^
|
= 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: 10 warnings emitted

Original file line number Diff line number Diff line change
@@ -26,15 +26,22 @@ fn my_fn(_args: &[A]) {
}

const TEST: Fn = my_fn;
const TEST2: (Fn, u8) = (TEST, 0);

struct B(Fn);

fn main() {
let s = B(my_fn);
match s {
B(TEST) => println!("matched"),
//~^ WARN pointers in patterns behave unpredictably
//~^ WARN behave unpredictably
//~| WARN this was previously accepted by the compiler but is being phased out
_ => panic!("didn't match")
};
match (s.0, 0) {
TEST2 => println!("matched"),
//~^ WARN behave unpredictably
//~| WARN this was previously accepted by the compiler but is being phased out
_ => panic!("didn't match")
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/issue-63479-match-fnptr.rs:35:7
warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/issue-63479-match-fnptr.rs:36:7
|
LL | B(TEST) => println!("matched"),
| ^^^^
@@ -12,5 +12,14 @@ note: the lint level is defined here
LL | #![warn(pointer_structural_match)]
| ^^^^^^^^^^^^^^^^^^^^^^^^

warning: 1 warning emitted
warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
--> $DIR/issue-63479-match-fnptr.rs:42:5
|
LL | TEST2 => println!("matched"),
| ^^^^^
|
= 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