1
Fork 0

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:
bors 2023-11-08 20:42:32 +00:00
commit fdaaaf9f92
18 changed files with 375 additions and 98 deletions

View file

@ -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

View file

@ -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);