Skip to content
Closed
Show file tree
Hide file tree
Changes from 8 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
5 changes: 5 additions & 0 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2103,6 +2103,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ProjectionElem::Deref => {
let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty;

let base_ty = match *base_ty.kind() {
ty::Pat(inner, _) => inner,
_ => base_ty,
};

// Check the kind of deref to decide
match base_ty.kind() {
ty::Ref(_, _, mutbl) => {
Expand Down
82 changes: 78 additions & 4 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
}
}

#[instrument(level = "trace", skip(self))]
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
self.super_rvalue(rvalue, location);
let rval_ty = rvalue.ty(self.body(), self.tcx());
Expand Down Expand Up @@ -517,14 +518,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {

/// Checks that the types internal to the `place` match up with
/// what would be expected.
#[instrument(level = "trace", skip(self), ret)]
fn sanitize_place(
&mut self,
place: &Place<'tcx>,
location: Location,
context: PlaceContext,
) -> PlaceTy<'tcx> {
debug!("sanitize_place: {:?}", place);

let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty);

for elem in place.projection.iter() {
Expand Down Expand Up @@ -630,14 +630,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
}

#[instrument(level = "trace", skip(self), ret)]
fn sanitize_projection(
&mut self,
base: PlaceTy<'tcx>,
pi: PlaceElem<'tcx>,
place: &Place<'tcx>,
location: Location,
) -> PlaceTy<'tcx> {
debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place);
let tcx = self.tcx();
let base_ty = base.ty;
match pi {
Expand Down Expand Up @@ -742,9 +742,17 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
ProjectionElem::OpaqueCast(ty) => {
let ty = self.sanitize_type(place, ty);
let ty = self.cx.normalize(ty, location);
let compare_ty = match *base.ty.kind() {
ty::Alias(ty::Opaque, _) => base.ty,
ty::Pat(inner, _) => inner,
_ => {
span_mirbug!(self, place, "tried to cast {} to {ty}", base.ty);
base.ty
}
};
self.cx
.eq_types(
base.ty,
compare_ty,
ty,
location.to_locations(),
ConstraintCategory::TypeAnnotation,
Expand Down Expand Up @@ -1310,6 +1318,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.check_operand(discr, term_location);

let switch_ty = discr.ty(body, tcx);
let switch_ty = switch_ty.strip_pattern().unwrap_or(switch_ty);
if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() {
span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty);
}
Expand Down Expand Up @@ -2107,6 +2116,66 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
}
CastKind::Patternize => {
let ty_from = op.ty(body, tcx);
let cast_ty_to = CastTy::from_ty(*ty);
match cast_ty_to {
Some(CastTy::Pat(to)) => {
if let Err(terr) = self.eq_types(
ty_from,
to,
location.to_locations(),
ConstraintCategory::Cast,
) {
span_mirbug!(
self,
rvalue,
"relating {:?} with {:?} yields {:?}",
ty_from,
to,
terr
)
}
}
_ => {
span_mirbug!(
self,
rvalue,
"Invalid Patternize cast {ty_from} -> {ty}",
)
}
}
}
CastKind::StripPattern => {
let ty_from = op.ty(body, tcx);
let cast_ty_from = CastTy::from_ty(ty_from);
match cast_ty_from {
Some(CastTy::Pat(from)) => {
if let Err(terr) = self.eq_types(
*ty,
from,
location.to_locations(),
ConstraintCategory::Cast,
) {
span_mirbug!(
self,
rvalue,
"relating {:?} with {:?} yields {:?}",
ty,
from,
terr
)
}
}
_ => {
span_mirbug!(
self,
rvalue,
"Invalid StripPattern cast {ty_from} -> {ty}",
)
}
}
}
CastKind::IntToFloat => {
let ty_from = op.ty(body, tcx);
let cast_ty_from = CastTy::from_ty(ty_from);
Expand Down Expand Up @@ -2427,6 +2496,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ProjectionElem::Deref => {
let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty;

let base_ty = match *base_ty.kind() {
ty::Pat(inner, _) => inner,
_ => base_ty,
};

debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
match base_ty.kind() {
ty::Ref(ref_region, _, mutbl) => {
Expand Down
18 changes: 7 additions & 11 deletions compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,17 +610,13 @@ fn codegen_stmt<'tcx>(
}
}
Rvalue::Cast(
CastKind::Pointer(PointerCast::UnsafeFnPointer),
ref operand,
to_ty,
)
| Rvalue::Cast(
CastKind::Pointer(PointerCast::MutToConstPointer),
ref operand,
to_ty,
)
| Rvalue::Cast(
CastKind::Pointer(PointerCast::ArrayToPointer),
CastKind::StripPattern
| CastKind::Patternize
| CastKind::Pointer(
PointerCast::UnsafeFnPointer
| PointerCast::MutToConstPointer
| PointerCast::ArrayToPointer,
),
ref operand,
to_ty,
) => {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
// Type parameters from polymorphized functions.
ty::Param(_) => build_param_type_di_node(cx, t),
ty::Pat(inner, _) => return type_di_node(cx, inner),
_ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t),
};

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
(bx.bitcast(lldata, lldata_ty), bx.bitcast(llextra, llextra_ty))
}
(&ty::Pat(a, a_pat), &ty::Pat(b, b_pat)) if a_pat == b_pat => {
unsize_ptr(bx, src, a, b, old_info)
}
_ => bug!("unsize_ptr: called on bad types"),
}
}
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ fn push_debuginfo_type_name<'tcx>(
}
}
}
ty::Pat(inner_type, pat) => {
if cpp_like_debuginfo {
output.push_str("pat$<");
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
write!(output, ",{:?}>", pat).unwrap();
} else {
write!(output, "{:?}", t).unwrap();
}
}
ty::Slice(inner_type) => {
if cpp_like_debuginfo {
output.push_str("slice2$<");
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
}
}
mir::CastKind::Pointer(PointerCast::UnsafeFnPointer) => {
mir::CastKind::Patternize
| mir::CastKind::StripPattern
| mir::CastKind::Pointer(PointerCast::UnsafeFnPointer) => {
// This is a no-op at the LLVM level.
operand.val
}
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
Ok(ty::ValTree::Leaf(val.assert_int()))
}

ty::Pat(..) => const_to_valtree_inner(ecx, &ecx.mplace_field(&place, 0).unwrap(), num_nodes),

// Raw pointers are not allowed in type level constants, as we cannot properly test them for
// equality at compile-time (see `ptr_guaranteed_cmp`).
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
Expand Down Expand Up @@ -265,7 +267,7 @@ pub fn valtree_to_const_value<'tcx>(
let (param_env, ty) = param_env_ty.into_parts();
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);

match ty.kind() {
match *ty.kind() {
ty::FnDef(..) => {
assert!(valtree.unwrap_branch().is_empty());
ConstValue::ZeroSized
Expand All @@ -276,6 +278,7 @@ pub fn valtree_to_const_value<'tcx>(
"ValTrees for Bool, Int, Uint, Float or Char should have the form ValTree::Leaf"
),
},
ty::Pat(ty, _) => valtree_to_const_value(tcx, param_env.and(ty), valtree),
ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
let mut place = match ty.kind() {
ty::Ref(_, inner_ty, _) => {
Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
use rustc_middle::mir::CastKind::*;
// FIXME: In which cases should we trigger UB when the source is uninit?
match cast_kind {
Patternize | StripPattern => {
self.copy_op(src, dest, true)?;
}

Pointer(PointerCast::Unsize) => {
let cast_ty = self.layout_of(cast_ty)?;
self.unsize_into(src, cast_ty, dest)?;
Expand Down Expand Up @@ -368,10 +372,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
dest: &PlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty);
match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
let (src_ty, target_ty) = match (src.layout.ty.kind(), cast_ty.ty.kind()) {
(&ty::Pat(a, pat_a), &ty::Pat(b, pat_b)) if pat_a == pat_b => (a, b),
_ => (src.layout.ty, cast_ty.ty),
};
match (src_ty.kind(), target_ty.kind()) {
(&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. }))
| (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => {
self.unsize_into_ptr(src, dest, *s, *c)
self.unsize_into_ptr(src, dest, s, c)
}
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
assert_eq!(def_a, def_b);
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
throw_inval!(TooGeneric)
}
ty::Pat(..) => {
unimplemented!("pattern types need to calculate pattern from their pattern")
Copy link
Member

Choose a reason for hiding this comment

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

I can't parse this panic message... too many patterns?^^

}
ty::Bound(_, _) => bug!("bound ty during ctfe"),
ty::Bool
| ty::Char
Expand Down
30 changes: 25 additions & 5 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,27 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
) -> InterpResult<'tcx, bool> {
// Go over all the primitive types
let ty = value.layout.ty;
match ty.kind() {
match *ty.kind() {
ty::Pat(inner, _) => {
let mut value = value.clone();
value.layout.ty = inner;
// First visit the inner type to report more targetted errors
// if the value is already not valid at the inner type.
self.visit_value(&value)?;
// Then check the extra pattern restrictions.
let scalar = self.read_immediate(&value, "initialized scalar value")?;
match (*scalar, value.layout.abi) {
(Immediate::Scalar(scalar), Abi::Scalar(s))
| (Immediate::ScalarPair(scalar, _), Abi::ScalarPair(s, _)) => {
self.visit_scalar(scalar, s)?
}
other => span_bug!(
self.ecx.cur_span(),
"invalid abi {other:?} for pattern type {ty:?}"
),
}
Comment on lines +501 to +512
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this duplicating the scalar range check after this match?

I assume for now patterns are restricted to things that can be actually represented in the Scalar ABI? If 0 | 5 | 10 is accepted as a pattern then we should properly check it here...

Ok(true)
}
ty::Bool => {
let value = self.read_scalar(value, "a boolean")?;
try_validation!(
Expand Down Expand Up @@ -545,11 +565,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
}
ty::Ref(_, ty, mutbl) => {
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
&& *mutbl == Mutability::Mut
&& mutbl == Mutability::Mut
{
// A mutable reference inside a const? That does not seem right (except if it is
// a ZST).
let layout = self.ecx.layout_of(*ty)?;
let layout = self.ecx.layout_of(ty)?;
if !layout.is_zst() {
throw_validation_failure!(self.path, { "mutable reference in a `const`" });
}
Expand Down Expand Up @@ -778,7 +798,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
Abi::Scalar(scalar_layout) => {
if !scalar_layout.is_uninit_valid() {
// There is something to check here.
let scalar = self.read_scalar(op, "initiailized scalar value")?;
let scalar = self.read_scalar(op, "initialized scalar value")?;
self.visit_scalar(scalar, scalar_layout)?;
}
}
Expand All @@ -788,7 +808,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
// the other must be init.
if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() {
let (a, b) =
self.read_immediate(op, "initiailized scalar value")?.to_scalar_pair();
self.read_immediate(op, "initialized scalar value")?.to_scalar_pair();
self.visit_scalar(a, a_layout)?;
self.visit_scalar(b, b_layout)?;
}
Expand Down
Loading