Auto merge of #116930 - RalfJung:raw-ptr-match, r=davidtwco
patterns: reject raw pointers that are not just integers Matching against `0 as *const i32` is fine, matching against `&42 as *const i32` is not. This extends the existing check against function pointers and wide pointers: we now uniformly reject all these pointer types during valtree construction, and then later lint because of that. See [here](https://github.com/rust-lang/rust/pull/116930#issuecomment-1784654073) for some more explanation and context. Also fixes https://github.com/rust-lang/rust/issues/116929. Cc `@oli-obk` `@lcnr`
This commit is contained in:
commit
fdaaaf9f92
18 changed files with 375 additions and 98 deletions
|
@ -247,7 +247,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 @@ 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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue