patterns: reject raw pointers that are not just integers
This commit is contained in:
parent
3089c315b1
commit
bec88ad4aa
@ -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()),
|
||||
|
@ -2217,13 +2217,14 @@
|
||||
///
|
||||
/// ### 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,
|
||||
"pointers are not structural-match",
|
||||
|
@ -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
|
||||
|
||||
|
@ -123,6 +123,8 @@ fn to_pat(
|
||||
});
|
||||
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(_)
|
||||
@ -238,7 +240,9 @@ fn to_pat(
|
||||
}
|
||||
} 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::RawPtr(..) if have_valtree => {
|
||||
// This is a good raw pointer, it was accepted by valtree construction.
|
||||
}
|
||||
ty::FnPtr(..) | ty::RawPtr(..) => {
|
||||
self.tcx().emit_spanned_lint(
|
||||
lint::builtin::POINTER_STRUCTURAL_MATCH,
|
||||
@ -389,11 +393,19 @@ fn recur(
|
||||
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 +492,15 @@ fn recur(
|
||||
}
|
||||
}
|
||||
},
|
||||
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,12 +1,11 @@
|
||||
// run-pass
|
||||
|
||||
#![warn(pointer_structural_match)]
|
||||
#![deny(pointer_structural_match)]
|
||||
#![allow(dead_code)]
|
||||
const C: *const u8 = &0;
|
||||
|
||||
fn foo(x: *const u8) {
|
||||
match x {
|
||||
C => {}
|
||||
C => {} //~ERROR: behave unpredictably
|
||||
//~| previously accepted
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -15,7 +14,8 @@ fn foo(x: *const u8) {
|
||||
|
||||
fn main() {
|
||||
match D {
|
||||
D => {}
|
||||
D => {} //~ERROR: behave unpredictably
|
||||
//~| previously accepted
|
||||
_ => {}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
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:7: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:17: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 2 previous errors
|
||||
|
@ -16,9 +16,9 @@ fn test(x: usize) -> Func {
|
||||
|
||||
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!(),
|
||||
}
|
||||
|
@ -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"),
|
||||
|
@ -33,7 +33,7 @@ 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")
|
||||
};
|
||||
|
@ -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-63479-match-fnptr.rs:35:7
|
||||
|
|
||||
LL | B(TEST) => println!("matched"),
|
||||
|
Loading…
Reference in New Issue
Block a user