Auto merge of #124972 - matthiaskrgr:rollup-3fablim, r=matthiaskrgr

Rollup of 5 pull requests

Successful merges:

 - #124615 (coverage: Further simplify extraction of mapping info from MIR)
 - #124778 (Fix parse error message for meta items)
 - #124797 (Refactor float `Primitive`s to a separate `Float` type)
 - #124888 (Migrate `run-make/rustdoc-output-path` to rmake)
 - #124957 (Make `Ty::builtin_deref` just return a `Ty`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-05-10 16:04:26 +00:00
commit 6a19a87097
82 changed files with 469 additions and 403 deletions

View file

@ -926,6 +926,41 @@ impl Integer {
} }
} }
/// Floating-point types.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
pub enum Float {
F16,
F32,
F64,
F128,
}
impl Float {
pub fn size(self) -> Size {
use Float::*;
match self {
F16 => Size::from_bits(16),
F32 => Size::from_bits(32),
F64 => Size::from_bits(64),
F128 => Size::from_bits(128),
}
}
pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign {
use Float::*;
let dl = cx.data_layout();
match self {
F16 => dl.f16_align,
F32 => dl.f32_align,
F64 => dl.f64_align,
F128 => dl.f128_align,
}
}
}
/// Fundamental unit of memory access and layout. /// Fundamental unit of memory access and layout.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
@ -938,10 +973,7 @@ pub enum Primitive {
/// a negative integer passed by zero-extension will appear positive in /// a negative integer passed by zero-extension will appear positive in
/// the callee, and most operations on it will produce the wrong values. /// the callee, and most operations on it will produce the wrong values.
Int(Integer, bool), Int(Integer, bool),
F16, Float(Float),
F32,
F64,
F128,
Pointer(AddressSpace), Pointer(AddressSpace),
} }
@ -952,10 +984,7 @@ impl Primitive {
match self { match self {
Int(i, _) => i.size(), Int(i, _) => i.size(),
F16 => Size::from_bits(16), Float(f) => f.size(),
F32 => Size::from_bits(32),
F64 => Size::from_bits(64),
F128 => Size::from_bits(128),
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
// different address spaces can have different sizes // different address spaces can have different sizes
// (but TargetDataLayout doesn't currently parse that part of the DL string) // (but TargetDataLayout doesn't currently parse that part of the DL string)
@ -969,10 +998,7 @@ impl Primitive {
match self { match self {
Int(i, _) => i.align(dl), Int(i, _) => i.align(dl),
F16 => dl.f16_align, Float(f) => f.align(dl),
F32 => dl.f32_align,
F64 => dl.f64_align,
F128 => dl.f128_align,
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
// different address spaces can have different alignments // different address spaces can have different alignments
// (but TargetDataLayout doesn't currently parse that part of the DL string) // (but TargetDataLayout doesn't currently parse that part of the DL string)

View file

@ -1483,10 +1483,9 @@ fn suggest_ampmut<'tcx>(
} else { } else {
// otherwise, suggest that the user annotates the binding; we provide the // otherwise, suggest that the user annotates the binding; we provide the
// type of the local. // type of the local.
let ty_mut = decl_ty.builtin_deref(true).unwrap(); let ty = decl_ty.builtin_deref(true).unwrap();
assert_eq!(ty_mut.mutbl, hir::Mutability::Not);
(false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty_mut.ty)) (false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty))
} }
} }

View file

@ -400,7 +400,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) { } else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity();
let normalized_ty = self.cx.normalize(unnormalized_ty, locations); let normalized_ty = self.cx.normalize(unnormalized_ty, locations);
let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty; let literal_ty = constant.const_.ty().builtin_deref(true).unwrap();
if let Err(terr) = self.cx.eq_types( if let Err(terr) = self.cx.eq_types(
literal_ty, literal_ty,
@ -637,7 +637,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
match pi { match pi {
ProjectionElem::Deref => { ProjectionElem::Deref => {
let deref_ty = base_ty.builtin_deref(true); let deref_ty = base_ty.builtin_deref(true);
PlaceTy::from_ty(deref_ty.map(|t| t.ty).unwrap_or_else(|| { PlaceTy::from_ty(deref_ty.unwrap_or_else(|| {
span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty)
})) }))
} }

View file

@ -670,11 +670,8 @@ fn codegen_stmt<'tcx>(
let to_ty = fx.monomorphize(to_ty); let to_ty = fx.monomorphize(to_ty);
fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.builtin_deref(true).is_some_and( ty.builtin_deref(true)
|ty::TypeAndMut { ty: pointee_ty, mutbl: _ }| { .is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty))
has_ptr_meta(fx.tcx, pointee_ty)
},
)
} }
if is_fat_ptr(fx, from_ty) { if is_fat_ptr(fx, from_ty) {

View file

@ -7,7 +7,7 @@ use rustc_middle::ty::layout::{
use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::TypeFoldable;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_target::abi::call::FnAbi; use rustc_target::abi::call::FnAbi;
use rustc_target::abi::{Integer, Primitive}; use rustc_target::abi::{Float, Integer, Primitive};
use rustc_target::spec::{HasTargetSpec, Target}; use rustc_target::spec::{HasTargetSpec, Target};
use crate::constant::ConstantCx; use crate::constant::ConstantCx;
@ -32,10 +32,12 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type {
Integer::I64 => types::I64, Integer::I64 => types::I64,
Integer::I128 => types::I128, Integer::I128 => types::I128,
}, },
Primitive::F16 => unimplemented!("f16_f128"), Primitive::Float(float) => match float {
Primitive::F32 => types::F32, Float::F16 => unimplemented!("f16_f128"),
Primitive::F64 => types::F64, Float::F32 => types::F32,
Primitive::F128 => unimplemented!("f16_f128"), Float::F64 => types::F64,
Float::F128 => unimplemented!("f16_f128"),
},
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => pointer_ty(tcx), Primitive::Pointer(_) => pointer_ty(tcx),
} }

View file

@ -586,7 +586,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
intrinsic_args!(fx, args => (base, offset); intrinsic); intrinsic_args!(fx, args => (base, offset); intrinsic);
let offset = offset.load_scalar(fx); let offset = offset.load_scalar(fx);
let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty; let pointee_ty = base.layout().ty.builtin_deref(true).unwrap();
let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let pointee_size = fx.layout_of(pointee_ty).size.bytes();
let ptr_diff = if pointee_size != 1 { let ptr_diff = if pointee_size != 1 {
fx.bcx.ins().imul_imm(offset, pointee_size as i64) fx.bcx.ins().imul_imm(offset, pointee_size as i64)
@ -610,7 +610,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let val = val.load_scalar(fx); let val = val.load_scalar(fx);
let count = count.load_scalar(fx); let count = count.load_scalar(fx);
let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap().ty; let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap();
let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let pointee_size = fx.layout_of(pointee_ty).size.bytes();
let count = if pointee_size != 1 { let count = if pointee_size != 1 {
fx.bcx.ins().imul_imm(count, pointee_size as i64) fx.bcx.ins().imul_imm(count, pointee_size as i64)
@ -715,7 +715,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
// Cranelift treats loads as volatile by default // Cranelift treats loads as volatile by default
// FIXME correctly handle unaligned_volatile_load // FIXME correctly handle unaligned_volatile_load
let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty); let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap());
let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout); let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout);
ret.write_cvalue(fx, val); ret.write_cvalue(fx, val);
} }

View file

@ -974,7 +974,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
intrinsic_args!(fx, args => (ptr, offset); intrinsic); intrinsic_args!(fx, args => (ptr, offset); intrinsic);
let (lane_count, ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx); let (lane_count, ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap().ty; let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap();
let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let pointee_size = fx.layout_of(pointee_ty).size.bytes();
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
let ret_lane_layout = fx.layout_of(ret_lane_ty); let ret_lane_layout = fx.layout_of(ret_lane_ty);

View file

@ -95,7 +95,7 @@ mod prelude {
pub(crate) use rustc_middle::mir::{self, *}; pub(crate) use rustc_middle::mir::{self, *};
pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
pub(crate) use rustc_middle::ty::{ pub(crate) use rustc_middle::ty::{
self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, UintTy, self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, UintTy,
}; };
pub(crate) use rustc_span::Span; pub(crate) use rustc_span::Span;
pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT}; pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT};

View file

@ -388,12 +388,8 @@ pub(crate) fn codegen_ptr_binop<'tcx>(
in_lhs: CValue<'tcx>, in_lhs: CValue<'tcx>,
in_rhs: CValue<'tcx>, in_rhs: CValue<'tcx>,
) -> CValue<'tcx> { ) -> CValue<'tcx> {
let is_thin_ptr = in_lhs let is_thin_ptr =
.layout() in_lhs.layout().ty.builtin_deref(true).map(|ty| !has_ptr_meta(fx.tcx, ty)).unwrap_or(true);
.ty
.builtin_deref(true)
.map(|TypeAndMut { ty, mutbl: _ }| !has_ptr_meta(fx.tcx, ty))
.unwrap_or(true);
if is_thin_ptr { if is_thin_ptr {
match bin_op { match bin_op {
@ -404,7 +400,7 @@ pub(crate) fn codegen_ptr_binop<'tcx>(
codegen_compare_bin_op(fx, bin_op, false, lhs, rhs) codegen_compare_bin_op(fx, bin_op, false, lhs, rhs)
} }
BinOp::Offset => { BinOp::Offset => {
let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap().ty; let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap();
let (base, offset) = (in_lhs, in_rhs.load_scalar(fx)); let (base, offset) = (in_lhs, in_rhs.load_scalar(fx));
let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let pointee_size = fx.layout_of(pointee_ty).size.bytes();
let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64); let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);

View file

@ -127,7 +127,7 @@ pub(crate) fn coerce_unsized_into<'tcx>(
let dst_ty = dst.layout().ty; let dst_ty = dst.layout().ty;
let mut coerce_ptr = || { let mut coerce_ptr = || {
let (base, info) = let (base, info) =
if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap().ty).is_unsized() { if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap()).is_unsized() {
let (old_base, old_info) = src.load_scalar_pair(fx); let (old_base, old_info) = src.load_scalar_pair(fx);
unsize_ptr(fx, old_base, src.layout(), dst.layout(), Some(old_info)) unsize_ptr(fx, old_base, src.layout(), dst.layout(), Some(old_info))
} else { } else {

View file

@ -819,7 +819,7 @@ impl<'tcx> CPlace<'tcx> {
} }
pub(crate) fn place_deref(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> CPlace<'tcx> { pub(crate) fn place_deref(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> CPlace<'tcx> {
let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap().ty); let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap());
if has_ptr_meta(fx.tcx, inner_layout.ty) { if has_ptr_meta(fx.tcx, inner_layout.ty) {
let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx); let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx);
CPlace::for_ptr_with_extra(Pointer::new(addr), extra, inner_layout) CPlace::for_ptr_with_extra(Pointer::new(addr), extra, inner_layout)

View file

@ -59,7 +59,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
if let ty::Ref(_, ty, _) = arg.layout().ty.kind() { if let ty::Ref(_, ty, _) = arg.layout().ty.kind() {
if ty.is_dyn_star() { if ty.is_dyn_star() {
let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap().ty); let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap());
let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout); let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout);
let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr(); let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr();
let vtable = let vtable =

View file

@ -8,8 +8,8 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
use rustc_target::abi::{ use rustc_target::abi::{
self, Abi, Align, FieldsShape, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface, self, Abi, Align, FieldsShape, Float, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface,
Variants, F128, F16, F32, F64, Variants,
}; };
use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType}; use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType};
@ -283,10 +283,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
match scalar.primitive() { match scalar.primitive() {
Int(i, true) => cx.type_from_integer(i), Int(i, true) => cx.type_from_integer(i),
Int(i, false) => cx.type_from_unsigned_integer(i), Int(i, false) => cx.type_from_unsigned_integer(i),
F16 => cx.type_f16(), Float(f) => cx.type_from_float(f),
F32 => cx.type_f32(),
F64 => cx.type_f64(),
F128 => cx.type_f128(),
Pointer(address_space) => { Pointer(address_space) => {
// If we know the alignment, pick something better than i8. // If we know the alignment, pick something better than i8.
let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) {

View file

@ -583,7 +583,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
let element_type_index = unsafe { llvm::LLVMRustGetElementTypeArgIndex(callsite) }; let element_type_index = unsafe { llvm::LLVMRustGetElementTypeArgIndex(callsite) };
if element_type_index >= 0 { if element_type_index >= 0 {
let arg_ty = self.args[element_type_index as usize].layout.ty; let arg_ty = self.args[element_type_index as usize].layout.ty;
let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument").ty; let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument");
let element_type_attr = unsafe { let element_type_attr = unsafe {
llvm::LLVMRustCreateElementTypeAttr(bx.llcx, bx.layout_of(pointee_ty).llvm_type(bx)) llvm::LLVMRustCreateElementTypeAttr(bx.llcx, bx.layout_of(pointee_ty).llvm_type(bx))
}; };

View file

@ -904,8 +904,8 @@ fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Ty
Primitive::Int(Integer::I16, _) => cx.type_i16(), Primitive::Int(Integer::I16, _) => cx.type_i16(),
Primitive::Int(Integer::I32, _) => cx.type_i32(), Primitive::Int(Integer::I32, _) => cx.type_i32(),
Primitive::Int(Integer::I64, _) => cx.type_i64(), Primitive::Int(Integer::I64, _) => cx.type_i64(),
Primitive::F32 => cx.type_f32(), Primitive::Float(Float::F32) => cx.type_f32(),
Primitive::F64 => cx.type_f64(), Primitive::Float(Float::F64) => cx.type_f64(),
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => cx.type_from_integer(dl.ptr_sized_integer()), Primitive::Pointer(_) => cx.type_from_integer(dl.ptr_sized_integer()),
_ => unreachable!(), _ => unreachable!(),
@ -950,7 +950,7 @@ fn llvm_fixup_input<'ll, 'tcx>(
bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices))
} }
(InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s))
if s.primitive() == Primitive::F64 => if s.primitive() == Primitive::Float(Float::F64) =>
{ {
bx.bitcast(value, bx.cx.type_i64()) bx.bitcast(value, bx.cx.type_i64())
} }
@ -986,8 +986,8 @@ fn llvm_fixup_input<'ll, 'tcx>(
match s.primitive() { match s.primitive() {
// MIPS only supports register-length arithmetics. // MIPS only supports register-length arithmetics.
Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()), Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()),
Primitive::F32 => bx.bitcast(value, bx.cx.type_i32()), Primitive::Float(Float::F32) => bx.bitcast(value, bx.cx.type_i32()),
Primitive::F64 => bx.bitcast(value, bx.cx.type_i64()), Primitive::Float(Float::F64) => bx.bitcast(value, bx.cx.type_i64()),
_ => value, _ => value,
} }
} }
@ -1027,7 +1027,7 @@ fn llvm_fixup_output<'ll, 'tcx>(
bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices))
} }
(InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s))
if s.primitive() == Primitive::F64 => if s.primitive() == Primitive::Float(Float::F64) =>
{ {
bx.bitcast(value, bx.cx.type_f64()) bx.bitcast(value, bx.cx.type_f64())
} }
@ -1064,8 +1064,8 @@ fn llvm_fixup_output<'ll, 'tcx>(
// MIPS only supports register-length arithmetics. // MIPS only supports register-length arithmetics.
Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()), Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()),
Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()), Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()),
Primitive::F32 => bx.bitcast(value, bx.cx.type_f32()), Primitive::Float(Float::F32) => bx.bitcast(value, bx.cx.type_f32()),
Primitive::F64 => bx.bitcast(value, bx.cx.type_f64()), Primitive::Float(Float::F64) => bx.bitcast(value, bx.cx.type_f64()),
_ => value, _ => value,
} }
} }
@ -1100,7 +1100,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
cx.type_vector(elem_ty, count * 2) cx.type_vector(elem_ty, count * 2)
} }
(InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s))
if s.primitive() == Primitive::F64 => if s.primitive() == Primitive::Float(Float::F64) =>
{ {
cx.type_i64() cx.type_i64()
} }
@ -1136,8 +1136,8 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
match s.primitive() { match s.primitive() {
// MIPS only supports register-length arithmetics. // MIPS only supports register-length arithmetics.
Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(), Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(),
Primitive::F32 => cx.type_i32(), Primitive::Float(Float::F32) => cx.type_i32(),
Primitive::F64 => cx.type_i64(), Primitive::Float(Float::F64) => cx.type_i64(),
_ => layout.llvm_type(cx), _ => layout.llvm_type(cx),
} }
} }

View file

@ -576,7 +576,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
} }
} }
} }
abi::F16 | abi::F32 | abi::F64 | abi::F128 => {} abi::Float(_) => {}
} }
} }

View file

@ -122,10 +122,7 @@ fn tag_base_type<'ll, 'tcx>(
// Niche tags are always normalized to unsized integers of the correct size. // Niche tags are always normalized to unsized integers of the correct size.
match tag.primitive() { match tag.primitive() {
Primitive::Int(t, _) => t, Primitive::Int(t, _) => t,
Primitive::F16 => Integer::I16, Primitive::Float(f) => Integer::from_size(f.size()).unwrap(),
Primitive::F32 => Integer::I32,
Primitive::F64 => Integer::I64,
Primitive::F128 => Integer::I128,
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => { Primitive::Pointer(_) => {
// If the niche is the NULL value of a reference, then `discr_enum_ty` will be // If the niche is the NULL value of a reference, then `discr_enum_ty` will be

View file

@ -18,7 +18,7 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
use rustc_middle::ty::{self, GenericArgsRef, Ty}; use rustc_middle::ty::{self, GenericArgsRef, Ty};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_span::{sym, Span, Symbol}; use rustc_span::{sym, Span, Symbol};
use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size}; use rustc_target::abi::{self, Align, Float, HasDataLayout, Primitive, Size};
use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use rustc_target::spec::{HasTargetSpec, PanicStrategy};
use std::cmp::Ordering; use std::cmp::Ordering;
@ -231,13 +231,17 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
emit_va_arg(self, args[0], ret_ty) emit_va_arg(self, args[0], ret_ty)
} }
} }
Primitive::F16 => bug!("the va_arg intrinsic does not work with `f16`"), Primitive::Float(Float::F16) => {
Primitive::F64 | Primitive::Pointer(_) => { bug!("the va_arg intrinsic does not work with `f16`")
}
Primitive::Float(Float::F64) | Primitive::Pointer(_) => {
emit_va_arg(self, args[0], ret_ty) emit_va_arg(self, args[0], ret_ty)
} }
// `va_arg` should never be used with the return type f32. // `va_arg` should never be used with the return type f32.
Primitive::F32 => bug!("the va_arg intrinsic does not work with `f32`"), Primitive::Float(Float::F32) => {
Primitive::F128 => { bug!("the va_arg intrinsic does not work with `f32`")
}
Primitive::Float(Float::F128) => {
bug!("the va_arg intrinsic does not work with `f128`") bug!("the va_arg intrinsic does not work with `f128`")
} }
} }
@ -2383,7 +2387,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| { let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| {
span_bug!(span, "must be called with a vector of pointer types as first argument") span_bug!(span, "must be called with a vector of pointer types as first argument")
}); });
let layout = bx.layout_of(pointee.ty); let layout = bx.layout_of(pointee);
let ptrs = args[0].immediate(); let ptrs = args[0].immediate();
// The second argument must be a ptr-sized integer. // The second argument must be a ptr-sized integer.
// (We don't care about the signedness, this is wrapping anyway.) // (We don't care about the signedness, this is wrapping anyway.)

View file

@ -6,7 +6,7 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_target::abi::{Abi, Align, FieldsShape}; use rustc_target::abi::{Abi, Align, FieldsShape};
use rustc_target::abi::{Int, Pointer, F128, F16, F32, F64}; use rustc_target::abi::{Float, Int, Pointer};
use rustc_target::abi::{Scalar, Size, Variants}; use rustc_target::abi::{Scalar, Size, Variants};
use std::fmt::Write; use std::fmt::Write;
@ -272,10 +272,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: Scalar) -> &'a Type { fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: Scalar) -> &'a Type {
match scalar.primitive() { match scalar.primitive() {
Int(i, _) => cx.type_from_integer(i), Int(i, _) => cx.type_from_integer(i),
F16 => cx.type_f16(), Float(f) => cx.type_from_float(f),
F32 => cx.type_f32(),
F64 => cx.type_f64(),
F128 => cx.type_f128(),
Pointer(address_space) => cx.type_ptr_ext(address_space), Pointer(address_space) => cx.type_ptr_ext(address_space),
} }
} }

View file

@ -1060,7 +1060,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Make sure that we've actually unwrapped the rcvr down // Make sure that we've actually unwrapped the rcvr down
// to a pointer or ref to `dyn* Trait`. // to a pointer or ref to `dyn* Trait`.
if !op.layout.ty.builtin_deref(true).unwrap().ty.is_dyn_star() { if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() {
span_bug!(span, "can't codegen a virtual call on {:#?}", op); span_bug!(span, "can't codegen a virtual call on {:#?}", op);
} }
let place = op.deref(bx.cx()); let place = op.deref(bx.cx());

View file

@ -120,7 +120,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
{ {
fn deref(&self, bx: &mut Bx) -> Self { fn deref(&self, bx: &mut Bx) -> Self {
bx.cx().layout_of( bx.cx().layout_of(
self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)).ty, self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)),
) )
} }

View file

@ -215,8 +215,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
.layout .layout
.ty .ty
.builtin_deref(true) .builtin_deref(true)
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)) .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self));
.ty;
let (llptr, llextra) = match self.val { let (llptr, llextra) = match self.val {
OperandValue::Immediate(llptr) => (llptr, None), OperandValue::Immediate(llptr) => (llptr, None),
@ -455,8 +454,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
.layout .layout
.ty .ty
.builtin_deref(true) .builtin_deref(true)
.unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)) .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest));
.ty;
let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self
else { else {

View file

@ -306,17 +306,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty); self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
imm = match (from_scalar.primitive(), to_scalar.primitive()) { imm = match (from_scalar.primitive(), to_scalar.primitive()) {
(Int(..) | F16 | F32 | F64 | F128, Int(..) | F16 | F32 | F64 | F128) => { (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
bx.bitcast(imm, to_backend_ty)
}
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm), (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
(Pointer(..), Int(..)) => bx.ptrtoint(imm, to_backend_ty), (Pointer(..), Int(..)) => bx.ptrtoint(imm, to_backend_ty),
(F16 | F32 | F64 | F128, Pointer(..)) => { (Float(_), Pointer(..)) => {
let int_imm = bx.bitcast(imm, bx.cx().type_isize()); let int_imm = bx.bitcast(imm, bx.cx().type_isize());
bx.ptradd(bx.const_null(bx.type_ptr()), int_imm) bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
} }
(Pointer(..), F16 | F32 | F64 | F128) => { (Pointer(..), Float(_)) => {
let int_imm = bx.ptrtoint(imm, bx.cx().type_isize()); let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
bx.bitcast(int_imm, to_backend_ty) bx.bitcast(int_imm, to_backend_ty)
} }
@ -870,8 +868,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::BinOp::Offset => { mir::BinOp::Offset => {
let pointee_type = input_ty let pointee_type = input_ty
.builtin_deref(true) .builtin_deref(true)
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty)) .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty));
.ty;
let pointee_layout = bx.cx().layout_of(pointee_type); let pointee_layout = bx.cx().layout_of(pointee_type);
if pointee_layout.is_zst() { if pointee_layout.is_zst() {
// `Offset` works in terms of the size of pointee, // `Offset` works in terms of the size of pointee,

View file

@ -7,7 +7,7 @@ use rustc_middle::bug;
use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg}; use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg};
use rustc_target::abi::{AddressSpace, Integer}; use rustc_target::abi::{AddressSpace, Float, Integer};
// This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use
// `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves. // `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves.
@ -65,6 +65,16 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
} }
} }
fn type_from_float(&self, f: Float) -> Self::Type {
use Float::*;
match f {
F16 => self.type_f16(),
F32 => self.type_f32(),
F64 => self.type_f64(),
F128 => self.type_f128(),
}
}
fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
ty.needs_drop(self.tcx(), ty::ParamEnv::reveal_all()) ty.needs_drop(self.tcx(), ty::ParamEnv::reveal_all())
} }

View file

@ -222,7 +222,7 @@ pub(super) fn op_to_const<'tcx>(
// This codepath solely exists for `valtree_to_const_value` to not need to generate // This codepath solely exists for `valtree_to_const_value` to not need to generate
// a `ConstValue::Indirect` for wide references, so it is tightly restricted to just // a `ConstValue::Indirect` for wide references, so it is tightly restricted to just
// that case. // that case.
let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap().ty; // `false` = no raw ptrs let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs
debug_assert!( debug_assert!(
matches!( matches!(
ecx.tcx.struct_tail_without_normalization(pointee_ty).kind(), ecx.tcx.struct_tail_without_normalization(pointee_ty).kind(),

View file

@ -605,7 +605,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
nonoverlapping: bool, nonoverlapping: bool,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
let count = self.read_target_usize(count)?; let count = self.read_target_usize(count)?;
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?; let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap())?;
let (size, align) = (layout.size, layout.align.abi); let (size, align) = (layout.size, layout.align.abi);
// `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
// but no actual allocation can be big enough for the difference to be noticeable. // but no actual allocation can be big enough for the difference to be noticeable.
@ -649,7 +649,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
byte: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, byte: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?; let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap())?;
let dst = self.read_pointer(dst)?; let dst = self.read_pointer(dst)?;
let byte = self.read_scalar(byte)?.to_u8()?; let byte = self.read_scalar(byte)?.to_u8()?;
@ -688,7 +688,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
) -> InterpResult<'tcx, Scalar<M::Provenance>> { ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?; let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap())?;
assert!(layout.is_sized()); assert!(layout.is_sized());
let get_bytes = |this: &InterpCx<'mir, 'tcx, M>, let get_bytes = |this: &InterpCx<'mir, 'tcx, M>,

View file

@ -357,7 +357,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Offset => { Offset => {
let ptr = left.to_scalar().to_pointer(self)?; let ptr = left.to_scalar().to_pointer(self)?;
let offset_count = right.to_scalar().to_target_isize(self)?; let offset_count = right.to_scalar().to_target_isize(self)?;
let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
// We cannot overflow i64 as a type's size must be <= isize::MAX. // We cannot overflow i64 as a type's size must be <= isize::MAX.
let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();

View file

@ -415,7 +415,7 @@ where
val: &ImmTy<'tcx, M::Provenance>, val: &ImmTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
let pointee_type = let pointee_type =
val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type");
let layout = self.layout_of(pointee_type)?; let layout = self.layout_of(pointee_type)?;
let (ptr, meta) = val.to_scalar_and_meta(); let (ptr, meta) = val.to_scalar_and_meta();

View file

@ -1291,7 +1291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
)) => { )) => {
let src_ty = src.ty(&self.body.local_decls, self.tcx); let src_ty = src.ty(&self.body.local_decls, self.tcx);
let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) { let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) {
src_deref.ty src_deref
} else { } else {
self.fail( self.fail(
location, location,
@ -1301,7 +1301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}; };
let dst_ty = dst.ty(&self.body.local_decls, self.tcx); let dst_ty = dst.ty(&self.body.local_decls, self.tcx);
let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) { let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) {
dst_deref.ty dst_deref
} else { } else {
self.fail( self.fail(
location, location,

View file

@ -115,7 +115,7 @@ fn might_permit_raw_init_lax<'tcx>(
// Special magic check for references and boxes (i.e., special pointer types). // Special magic check for references and boxes (i.e., special pointer types).
if let Some(pointee) = this.ty.builtin_deref(false) { if let Some(pointee) = this.ty.builtin_deref(false) {
let pointee = cx.layout_of(pointee.ty)?; let pointee = cx.layout_of(pointee)?;
// We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied. // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied.
if pointee.align.abi.bytes() > 1 { if pointee.align.abi.bytes() > 1 {
// 0x01-filling is not aligned. // 0x01-filling is not aligned.

View file

@ -68,9 +68,8 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
} }
// Otherwise, deref if type is derefable: // Otherwise, deref if type is derefable:
let (kind, new_ty) = if let Some(ty::TypeAndMut { ty, .. }) = let (kind, new_ty) =
self.state.cur_ty.builtin_deref(self.include_raw_pointers) if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
{
debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
// NOTE: we may still need to normalize the built-in deref in case // NOTE: we may still need to normalize the built-in deref in case
// we have some type like `&<Ty as Trait>::Assoc`, since users of // we have some type like `&<Ty as Trait>::Assoc`, since users of

View file

@ -624,10 +624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// returns a type of `&T`, but the actual type we assign to the /// returns a type of `&T`, but the actual type we assign to the
/// *expression* is `T`. So this function just peels off the return /// *expression* is `T`. So this function just peels off the return
/// type by one layer to yield `T`. /// type by one layer to yield `T`.
pub(crate) fn make_overloaded_place_return_type( pub(crate) fn make_overloaded_place_return_type(&self, method: MethodCallee<'tcx>) -> Ty<'tcx> {
&self,
method: MethodCallee<'tcx>,
) -> ty::TypeAndMut<'tcx> {
// extract method return type, which will be &T; // extract method return type, which will be &T;
let ret_ty = method.sig.output(); let ret_ty = method.sig.output();

View file

@ -207,7 +207,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
// but what we want here is the type of the underlying value being borrowed. // but what we want here is the type of the underlying value being borrowed.
// So peel off one-level, turning the &T into T. // So peel off one-level, turning the &T into T.
match base_ty.builtin_deref(false) { match base_ty.builtin_deref(false) {
Some(t) => Ok(t.ty), Some(ty) => Ok(ty),
None => { None => {
debug!("By-ref binding of non-derefable type"); debug!("By-ref binding of non-derefable type");
Err(()) Err(())
@ -485,7 +485,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
) -> McResult<PlaceWithHirId<'tcx>> { ) -> McResult<PlaceWithHirId<'tcx>> {
let base_curr_ty = base_place.place.ty(); let base_curr_ty = base_place.place.ty();
let deref_ty = match base_curr_ty.builtin_deref(true) { let deref_ty = match base_curr_ty.builtin_deref(true) {
Some(mt) => mt.ty, Some(pointee_ty) => pointee_ty,
None => { None => {
debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
return Err(()); return Err(());

View file

@ -918,8 +918,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
inner: &Pat<'_>, inner: &Pat<'_>,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
if let PatKind::Binding(..) = inner.kind if let PatKind::Binding(..) = inner.kind
&& let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
&& let ty::Dynamic(..) = mt.ty.kind() && let ty::Dynamic(..) = pointee_ty.kind()
{ {
// This is "x = dyn SomeTrait" being reduced from // This is "x = dyn SomeTrait" being reduced from
// "let &x = &dyn SomeTrait" or "let box x = Box<dyn SomeTrait>", an error. // "let &x = &dyn SomeTrait" or "let box x = Box<dyn SomeTrait>", an error.

View file

@ -19,8 +19,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
oprnd_expr: &'tcx hir::Expr<'tcx>, oprnd_expr: &'tcx hir::Expr<'tcx>,
oprnd_ty: Ty<'tcx>, oprnd_ty: Ty<'tcx>,
) -> Option<Ty<'tcx>> { ) -> Option<Ty<'tcx>> {
if let Some(mt) = oprnd_ty.builtin_deref(true) { if let Some(ty) = oprnd_ty.builtin_deref(true) {
return Some(mt.ty); return Some(ty);
} }
let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?; let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?;
@ -36,7 +36,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else { } else {
span_bug!(expr.span, "input to deref is not a ref?"); span_bug!(expr.span, "input to deref is not a ref?");
} }
let ty = self.make_overloaded_place_return_type(method).ty; let ty = self.make_overloaded_place_return_type(method);
self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
Some(ty) Some(ty)
} }
@ -173,7 +173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
return Some((input_ty, self.make_overloaded_place_return_type(method).ty)); return Some((input_ty, self.make_overloaded_place_return_type(method)));
} }
} }
@ -342,8 +342,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.borrow() .borrow()
.expr_ty_adjusted(base_expr) .expr_ty_adjusted(base_expr)
.builtin_deref(false) .builtin_deref(false)
.expect("place op takes something that is not a ref") .expect("place op takes something that is not a ref");
.ty;
let arg_ty = match op { let arg_ty = match op {
PlaceOp::Deref => None, PlaceOp::Deref => None,

View file

@ -78,13 +78,9 @@ impl<'tcx> PlaceTy<'tcx> {
} }
let answer = match *elem { let answer = match *elem {
ProjectionElem::Deref => { ProjectionElem::Deref => {
let ty = self let ty = self.ty.builtin_deref(true).unwrap_or_else(|| {
.ty
.builtin_deref(true)
.unwrap_or_else(|| {
bug!("deref projection of non-dereferenceable ty {:?}", self) bug!("deref projection of non-dereferenceable ty {:?}", self)
}) });
.ty;
PlaceTy::from_ty(ty) PlaceTy::from_ty(ty)
} }
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {

View file

@ -114,16 +114,35 @@ impl Integer {
} }
} }
#[extension(pub trait FloatExt)]
impl Float {
#[inline]
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match *self {
F16 => tcx.types.f16,
F32 => tcx.types.f32,
F64 => tcx.types.f64,
F128 => tcx.types.f128,
}
}
fn from_float_ty(fty: ty::FloatTy) -> Self {
match fty {
ty::FloatTy::F16 => F16,
ty::FloatTy::F32 => F32,
ty::FloatTy::F64 => F64,
ty::FloatTy::F128 => F128,
}
}
}
#[extension(pub trait PrimitiveExt)] #[extension(pub trait PrimitiveExt)]
impl Primitive { impl Primitive {
#[inline] #[inline]
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match *self { match *self {
Int(i, signed) => i.to_ty(tcx, signed), Int(i, signed) => i.to_ty(tcx, signed),
F16 => tcx.types.f16, Float(f) => f.to_ty(tcx),
F32 => tcx.types.f32,
F64 => tcx.types.f64,
F128 => tcx.types.f128,
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Pointer(_) => Ty::new_mut_ptr(tcx, tcx.types.unit), Pointer(_) => Ty::new_mut_ptr(tcx, tcx.types.unit),
} }
@ -140,7 +159,7 @@ impl Primitive {
let signed = false; let signed = false;
tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed) tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed)
} }
F16 | F32 | F64 | F128 => bug!("floats do not have an int type"), Float(_) => bug!("floats do not have an int type"),
} }
} }
} }

View file

@ -2164,13 +2164,11 @@ impl<'tcx> Ty<'tcx> {
/// ///
/// The parameter `explicit` indicates if this is an *explicit* dereference. /// The parameter `explicit` indicates if this is an *explicit* dereference.
/// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly.
pub fn builtin_deref(self, explicit: bool) -> Option<TypeAndMut<'tcx>> { pub fn builtin_deref(self, explicit: bool) -> Option<Ty<'tcx>> {
match self.kind() { match *self.kind() {
Adt(def, _) if def.is_box() => { Adt(def, _) if def.is_box() => Some(self.boxed_ty()),
Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not }) Ref(_, ty, _) => Some(ty),
} RawPtr(ty, _) if explicit => Some(ty),
Ref(_, ty, mutbl) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
RawPtr(ty, mutbl) if explicit => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
_ => None, _ => None,
} }
} }

View file

@ -2,7 +2,7 @@
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::query::{IntoQueryParam, Providers}; use crate::query::{IntoQueryParam, Providers};
use crate::ty::layout::IntegerExt; use crate::ty::layout::{FloatExt, IntegerExt};
use crate::ty::{ use crate::ty::{
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitableExt, TypeVisitableExt,
@ -20,7 +20,7 @@ use rustc_index::bit_set::GrowableBitSet;
use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable}; use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable};
use rustc_session::Limit; use rustc_session::Limit;
use rustc_span::sym; use rustc_span::sym;
use rustc_target::abi::{Integer, IntegerType, Primitive, Size}; use rustc_target::abi::{Float, Integer, IntegerType, Size};
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use std::{fmt, iter}; use std::{fmt, iter};
@ -1145,8 +1145,7 @@ impl<'tcx> Ty<'tcx> {
ty::Char => Size::from_bytes(4), ty::Char => Size::from_bytes(4),
ty::Int(ity) => Integer::from_int_ty(&tcx, ity).size(), ty::Int(ity) => Integer::from_int_ty(&tcx, ity).size(),
ty::Uint(uty) => Integer::from_uint_ty(&tcx, uty).size(), ty::Uint(uty) => Integer::from_uint_ty(&tcx, uty).size(),
ty::Float(ty::FloatTy::F32) => Primitive::F32.size(&tcx), ty::Float(fty) => Float::from_float_ty(fty).size(),
ty::Float(ty::FloatTy::F64) => Primitive::F64.size(&tcx),
_ => bug!("non primitive type"), _ => bug!("non primitive type"),
} }
} }

View file

@ -106,7 +106,7 @@ impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> {
} }
let pointee_ty = let pointee_ty =
pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer").ty; pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer");
// Ideally we'd support this in the future, but for now we are limited to sized types. // Ideally we'd support this in the future, but for now we are limited to sized types.
if !pointee_ty.is_sized(self.tcx, self.param_env) { if !pointee_ty.is_sized(self.tcx, self.param_env) {
debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty); debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty);

View file

@ -52,48 +52,40 @@ pub(super) struct MCDCDecision {
pub(super) decision_depth: u16, pub(super) decision_depth: u16,
} }
pub(super) struct CoverageSpans { #[derive(Default)]
bcb_has_mappings: BitSet<BasicCoverageBlock>, pub(super) struct ExtractedMappings {
pub(super) code_mappings: Vec<CodeMapping>, pub(super) code_mappings: Vec<CodeMapping>,
pub(super) branch_pairs: Vec<BranchPair>, pub(super) branch_pairs: Vec<BranchPair>,
test_vector_bitmap_bytes: u32, pub(super) mcdc_bitmap_bytes: u32,
pub(super) mcdc_branches: Vec<MCDCBranch>, pub(super) mcdc_branches: Vec<MCDCBranch>,
pub(super) mcdc_decisions: Vec<MCDCDecision>, pub(super) mcdc_decisions: Vec<MCDCDecision>,
} }
impl CoverageSpans {
pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool {
self.bcb_has_mappings.contains(bcb)
}
pub(super) fn test_vector_bitmap_bytes(&self) -> u32 {
self.test_vector_bitmap_bytes
}
}
/// Extracts coverage-relevant spans from MIR, and associates them with /// Extracts coverage-relevant spans from MIR, and associates them with
/// their corresponding BCBs. /// their corresponding BCBs.
/// pub(super) fn extract_all_mapping_info_from_mir(
/// Returns `None` if no coverage-relevant spans could be extracted.
pub(super) fn generate_coverage_spans(
mir_body: &mir::Body<'_>, mir_body: &mir::Body<'_>,
hir_info: &ExtractedHirInfo, hir_info: &ExtractedHirInfo,
basic_coverage_blocks: &CoverageGraph, basic_coverage_blocks: &CoverageGraph,
) -> Option<CoverageSpans> { ) -> ExtractedMappings {
let mut code_mappings = vec![];
let mut branch_pairs = vec![];
let mut mcdc_branches = vec![];
let mut mcdc_decisions = vec![];
if hir_info.is_async_fn { if hir_info.is_async_fn {
// An async function desugars into a function that returns a future, // An async function desugars into a function that returns a future,
// with the user code wrapped in a closure. Any spans in the desugared // with the user code wrapped in a closure. Any spans in the desugared
// outer function will be unhelpful, so just keep the signature span // outer function will be unhelpful, so just keep the signature span
// and ignore all of the spans in the MIR body. // and ignore all of the spans in the MIR body.
let mut mappings = ExtractedMappings::default();
if let Some(span) = hir_info.fn_sig_span_extended { if let Some(span) = hir_info.fn_sig_span_extended {
code_mappings.push(CodeMapping { span, bcb: START_BCB }); mappings.code_mappings.push(CodeMapping { span, bcb: START_BCB });
} }
} else { return mappings;
}
let mut code_mappings = vec![];
let mut branch_pairs = vec![];
let mut mcdc_bitmap_bytes = 0;
let mut mcdc_branches = vec![];
let mut mcdc_decisions = vec![];
extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings); extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks)); branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks));
@ -102,54 +94,62 @@ pub(super) fn generate_coverage_spans(
mir_body, mir_body,
hir_info.body_span, hir_info.body_span,
basic_coverage_blocks, basic_coverage_blocks,
&mut mcdc_bitmap_bytes,
&mut mcdc_branches, &mut mcdc_branches,
&mut mcdc_decisions, &mut mcdc_decisions,
); );
}
if code_mappings.is_empty() ExtractedMappings {
&& branch_pairs.is_empty()
&& mcdc_branches.is_empty()
&& mcdc_decisions.is_empty()
{
return None;
}
// Identify which BCBs have one or more mappings.
let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes());
let mut insert = |bcb| {
bcb_has_mappings.insert(bcb);
};
for &CodeMapping { span: _, bcb } in &code_mappings {
insert(bcb);
}
for &BranchPair { true_bcb, false_bcb, .. } in &branch_pairs {
insert(true_bcb);
insert(false_bcb);
}
for &MCDCBranch { true_bcb, false_bcb, .. } in &mcdc_branches {
insert(true_bcb);
insert(false_bcb);
}
// Determine the length of the test vector bitmap.
let test_vector_bitmap_bytes = mcdc_decisions
.iter()
.map(|&MCDCDecision { bitmap_idx, conditions_num, .. }| {
bitmap_idx + (1_u32 << u32::from(conditions_num)).div_ceil(8)
})
.max()
.unwrap_or(0);
Some(CoverageSpans {
bcb_has_mappings,
code_mappings, code_mappings,
branch_pairs, branch_pairs,
test_vector_bitmap_bytes, mcdc_bitmap_bytes,
mcdc_branches, mcdc_branches,
mcdc_decisions, mcdc_decisions,
}) }
}
impl ExtractedMappings {
pub(super) fn all_bcbs_with_counter_mappings(
&self,
basic_coverage_blocks: &CoverageGraph, // Only used for allocating a correctly-sized set
) -> BitSet<BasicCoverageBlock> {
// Fully destructure self to make sure we don't miss any fields that have mappings.
let Self {
code_mappings,
branch_pairs,
mcdc_bitmap_bytes: _,
mcdc_branches,
mcdc_decisions,
} = self;
// Identify which BCBs have one or more mappings.
let mut bcbs_with_counter_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes());
let mut insert = |bcb| {
bcbs_with_counter_mappings.insert(bcb);
};
for &CodeMapping { span: _, bcb } in code_mappings {
insert(bcb);
}
for &BranchPair { true_bcb, false_bcb, .. } in branch_pairs {
insert(true_bcb);
insert(false_bcb);
}
for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_branches {
insert(true_bcb);
insert(false_bcb);
}
// MC/DC decisions refer to BCBs, but don't require those BCBs to have counters.
if bcbs_with_counter_mappings.is_empty() {
debug_assert!(
mcdc_decisions.is_empty(),
"A function with no counter mappings shouldn't have any decisions: {mcdc_decisions:?}",
);
}
bcbs_with_counter_mappings
}
} }
fn resolve_block_markers( fn resolve_block_markers(
@ -215,6 +215,7 @@ pub(super) fn extract_mcdc_mappings(
mir_body: &mir::Body<'_>, mir_body: &mir::Body<'_>,
body_span: Span, body_span: Span,
basic_coverage_blocks: &CoverageGraph, basic_coverage_blocks: &CoverageGraph,
mcdc_bitmap_bytes: &mut u32,
mcdc_branches: &mut impl Extend<MCDCBranch>, mcdc_branches: &mut impl Extend<MCDCBranch>,
mcdc_decisions: &mut impl Extend<MCDCDecision>, mcdc_decisions: &mut impl Extend<MCDCDecision>,
) { ) {
@ -253,8 +254,6 @@ pub(super) fn extract_mcdc_mappings(
}, },
)); ));
let mut next_bitmap_idx = 0;
mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map( mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map(
|decision: &mir::coverage::MCDCDecisionSpan| { |decision: &mir::coverage::MCDCDecisionSpan| {
let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?; let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?;
@ -265,8 +264,11 @@ pub(super) fn extract_mcdc_mappings(
.map(|&marker| bcb_from_marker(marker)) .map(|&marker| bcb_from_marker(marker))
.collect::<Option<_>>()?; .collect::<Option<_>>()?;
let bitmap_idx = next_bitmap_idx; // Each decision containing N conditions needs 2^N bits of space in
next_bitmap_idx += (1_u32 << decision.conditions_num).div_ceil(8); // the bitmap, rounded up to a whole number of bytes.
// The decision's "bitmap index" points to its first byte in the bitmap.
let bitmap_idx = *mcdc_bitmap_bytes;
*mcdc_bitmap_bytes += (1_u32 << decision.conditions_num).div_ceil(8);
Some(MCDCDecision { Some(MCDCDecision {
span, span,

View file

@ -7,13 +7,9 @@ mod spans;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use self::counters::{CounterIncrementSite, CoverageCounters}; use rustc_middle::mir::coverage::{
use self::graph::{BasicCoverageBlock, CoverageGraph}; CodeRegion, CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind,
use self::mappings::CoverageSpans; };
use crate::MirPass;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::{ use rustc_middle::mir::{
self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator, self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator,
TerminatorKind, TerminatorKind,
@ -23,6 +19,11 @@ use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::SourceMap; use rustc_span::source_map::SourceMap;
use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol}; use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol};
use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
use crate::coverage::mappings::ExtractedMappings;
use crate::MirPass;
/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
/// to construct the coverage map. /// to construct the coverage map.
@ -69,24 +70,27 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
// Compute coverage spans from the `CoverageGraph`. // Extract coverage spans and other mapping info from MIR.
let Some(coverage_spans) = let extracted_mappings =
mappings::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks) mappings::extract_all_mapping_info_from_mir(mir_body, &hir_info, &basic_coverage_blocks);
else {
// No relevant spans were found in MIR, so skip instrumenting this function.
return;
};
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
// Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
// every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock`
// and all `Expression` dependencies (operands) are also generated, for any other // and all `Expression` dependencies (operands) are also generated, for any other
// `BasicCoverageBlock`s not already associated with a coverage span. // `BasicCoverageBlock`s not already associated with a coverage span.
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); let bcbs_with_counter_mappings =
let coverage_counters = extracted_mappings.all_bcbs_with_counter_mappings(&basic_coverage_blocks);
CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans); if bcbs_with_counter_mappings.is_empty() {
// No relevant spans were found in MIR, so skip instrumenting this function.
return;
}
let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters); let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings.contains(bcb);
let coverage_counters =
CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings);
let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters);
if mappings.is_empty() { if mappings.is_empty() {
// No spans could be converted into valid mappings, so skip this function. // No spans could be converted into valid mappings, so skip this function.
debug!("no spans could be converted into valid mappings; skipping"); debug!("no spans could be converted into valid mappings; skipping");
@ -96,13 +100,13 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
inject_coverage_statements( inject_coverage_statements(
mir_body, mir_body,
&basic_coverage_blocks, &basic_coverage_blocks,
bcb_has_coverage_spans, bcb_has_counter_mappings,
&coverage_counters, &coverage_counters,
); );
inject_mcdc_statements(mir_body, &basic_coverage_blocks, &coverage_spans); inject_mcdc_statements(mir_body, &basic_coverage_blocks, &extracted_mappings);
let mcdc_num_condition_bitmaps = coverage_spans let mcdc_num_condition_bitmaps = extracted_mappings
.mcdc_decisions .mcdc_decisions
.iter() .iter()
.map(|&mappings::MCDCDecision { decision_depth, .. }| decision_depth) .map(|&mappings::MCDCDecision { decision_depth, .. }| decision_depth)
@ -112,7 +116,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
function_source_hash: hir_info.function_source_hash, function_source_hash: hir_info.function_source_hash,
num_counters: coverage_counters.num_counters(), num_counters: coverage_counters.num_counters(),
mcdc_bitmap_bytes: coverage_spans.test_vector_bitmap_bytes(), mcdc_bitmap_bytes: extracted_mappings.mcdc_bitmap_bytes,
expressions: coverage_counters.into_expressions(), expressions: coverage_counters.into_expressions(),
mappings, mappings,
mcdc_num_condition_bitmaps, mcdc_num_condition_bitmaps,
@ -127,7 +131,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
fn create_mappings<'tcx>( fn create_mappings<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
hir_info: &ExtractedHirInfo, hir_info: &ExtractedHirInfo,
coverage_spans: &CoverageSpans, extracted_mappings: &ExtractedMappings,
coverage_counters: &CoverageCounters, coverage_counters: &CoverageCounters,
) -> Vec<Mapping> { ) -> Vec<Mapping> {
let source_map = tcx.sess.source_map(); let source_map = tcx.sess.source_map();
@ -148,9 +152,18 @@ fn create_mappings<'tcx>(
}; };
let region_for_span = |span: Span| make_code_region(source_map, file_name, span, body_span); let region_for_span = |span: Span| make_code_region(source_map, file_name, span, body_span);
// Fully destructure the mappings struct to make sure we don't miss any kinds.
let ExtractedMappings {
code_mappings,
branch_pairs,
mcdc_bitmap_bytes: _,
mcdc_branches,
mcdc_decisions,
} = extracted_mappings;
let mut mappings = Vec::new(); let mut mappings = Vec::new();
mappings.extend(coverage_spans.code_mappings.iter().filter_map( mappings.extend(code_mappings.iter().filter_map(
// Ordinary code mappings are the simplest kind.
|&mappings::CodeMapping { span, bcb }| { |&mappings::CodeMapping { span, bcb }| {
let code_region = region_for_span(span)?; let code_region = region_for_span(span)?;
let kind = MappingKind::Code(term_for_bcb(bcb)); let kind = MappingKind::Code(term_for_bcb(bcb));
@ -158,7 +171,7 @@ fn create_mappings<'tcx>(
}, },
)); ));
mappings.extend(coverage_spans.branch_pairs.iter().filter_map( mappings.extend(branch_pairs.iter().filter_map(
|&mappings::BranchPair { span, true_bcb, false_bcb }| { |&mappings::BranchPair { span, true_bcb, false_bcb }| {
let true_term = term_for_bcb(true_bcb); let true_term = term_for_bcb(true_bcb);
let false_term = term_for_bcb(false_bcb); let false_term = term_for_bcb(false_bcb);
@ -168,7 +181,7 @@ fn create_mappings<'tcx>(
}, },
)); ));
mappings.extend(coverage_spans.mcdc_branches.iter().filter_map( mappings.extend(mcdc_branches.iter().filter_map(
|&mappings::MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth: _ }| { |&mappings::MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth: _ }| {
let code_region = region_for_span(span)?; let code_region = region_for_span(span)?;
let true_term = term_for_bcb(true_bcb); let true_term = term_for_bcb(true_bcb);
@ -181,7 +194,7 @@ fn create_mappings<'tcx>(
}, },
)); ));
mappings.extend(coverage_spans.mcdc_decisions.iter().filter_map( mappings.extend(mcdc_decisions.iter().filter_map(
|&mappings::MCDCDecision { span, bitmap_idx, conditions_num, .. }| { |&mappings::MCDCDecision { span, bitmap_idx, conditions_num, .. }| {
let code_region = region_for_span(span)?; let code_region = region_for_span(span)?;
let kind = MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num }); let kind = MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num });
@ -249,12 +262,8 @@ fn inject_coverage_statements<'tcx>(
fn inject_mcdc_statements<'tcx>( fn inject_mcdc_statements<'tcx>(
mir_body: &mut mir::Body<'tcx>, mir_body: &mut mir::Body<'tcx>,
basic_coverage_blocks: &CoverageGraph, basic_coverage_blocks: &CoverageGraph,
coverage_spans: &CoverageSpans, extracted_mappings: &ExtractedMappings,
) { ) {
if coverage_spans.test_vector_bitmap_bytes() == 0 {
return;
}
// Inject test vector update first because `inject_statement` always insert new statement at head. // Inject test vector update first because `inject_statement` always insert new statement at head.
for &mappings::MCDCDecision { for &mappings::MCDCDecision {
span: _, span: _,
@ -262,7 +271,7 @@ fn inject_mcdc_statements<'tcx>(
bitmap_idx, bitmap_idx,
conditions_num: _, conditions_num: _,
decision_depth, decision_depth,
} in &coverage_spans.mcdc_decisions } in &extracted_mappings.mcdc_decisions
{ {
for end in end_bcbs { for end in end_bcbs {
let end_bb = basic_coverage_blocks[*end].leader_bb(); let end_bb = basic_coverage_blocks[*end].leader_bb();
@ -275,7 +284,7 @@ fn inject_mcdc_statements<'tcx>(
} }
for &mappings::MCDCBranch { span: _, true_bcb, false_bcb, condition_info, decision_depth } in for &mappings::MCDCBranch { span: _, true_bcb, false_bcb, condition_info, decision_depth } in
&coverage_spans.mcdc_branches &extracted_mappings.mcdc_branches
{ {
let Some(condition_info) = condition_info else { continue }; let Some(condition_info) = condition_info else { continue };
let id = condition_info.condition_id; let id = condition_info.condition_id;

View file

@ -202,7 +202,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
if let Some(target_len) = self.map().find_len(target.as_ref()) if let Some(target_len) = self.map().find_len(target.as_ref())
&& let operand_ty = operand.ty(self.local_decls, self.tcx) && let operand_ty = operand.ty(self.local_decls, self.tcx)
&& let Some(operand_ty) = operand_ty.builtin_deref(true) && let Some(operand_ty) = operand_ty.builtin_deref(true)
&& let ty::Array(_, len) = operand_ty.ty.kind() && let ty::Array(_, len) = operand_ty.kind()
&& let Some(len) = Const::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env) && let Some(len) = Const::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env)
{ {
state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map()); state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map());

View file

@ -594,7 +594,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
let ty = place.ty(self.local_decls, self.tcx).ty; let ty = place.ty(self.local_decls, self.tcx).ty;
if let Some(Mutability::Not) = ty.ref_mutability() if let Some(Mutability::Not) = ty.ref_mutability()
&& let Some(pointee_ty) = ty.builtin_deref(true) && let Some(pointee_ty) = ty.builtin_deref(true)
&& pointee_ty.ty.is_freeze(self.tcx, self.param_env) && pointee_ty.is_freeze(self.tcx, self.param_env)
{ {
// An immutable borrow `_x` always points to the same value for the // An immutable borrow `_x` always points to the same value for the
// lifetime of the borrow, so we can merge all instances of `*_x`. // lifetime of the borrow, so we can merge all instances of `*_x`.
@ -1133,9 +1133,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
if let Value::Cast { kind, from, to, .. } = self.get(inner) if let Value::Cast { kind, from, to, .. } = self.get(inner)
&& let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind
&& let Some(from) = from.builtin_deref(true) && let Some(from) = from.builtin_deref(true)
&& let ty::Array(_, len) = from.ty.kind() && let ty::Array(_, len) = from.kind()
&& let Some(to) = to.builtin_deref(true) && let Some(to) = to.builtin_deref(true)
&& let ty::Slice(..) = to.ty.kind() && let ty::Slice(..) = to.kind()
{ {
return self.insert_constant(Const::from_ty_const(*len, self.tcx)); return self.insert_constant(Const::from_ty_const(*len, self.tcx));
} }

View file

@ -79,8 +79,8 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
// add everything that may involve a vtable. // add everything that may involve a vtable.
let source_ty = operand.ty(self.body, self.tcx); let source_ty = operand.ty(self.body, self.tcx);
let may_involve_vtable = match ( let may_involve_vtable = match (
source_ty.builtin_deref(true).map(|t| t.ty.kind()), source_ty.builtin_deref(true).map(|t| t.kind()),
target_ty.builtin_deref(true).map(|t| t.ty.kind()), target_ty.builtin_deref(true).map(|t| t.kind()),
) { ) {
(Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, // &str/&[T] unsizing (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, // &str/&[T] unsizing
_ => true, _ => true,

View file

@ -48,9 +48,9 @@ fn compute_slice_length<'tcx>(
let operand_ty = operand.ty(body, tcx); let operand_ty = operand.ty(body, tcx);
debug!(?operand_ty); debug!(?operand_ty);
if let Some(operand_ty) = operand_ty.builtin_deref(true) if let Some(operand_ty) = operand_ty.builtin_deref(true)
&& let ty::Array(_, len) = operand_ty.ty.kind() && let ty::Array(_, len) = operand_ty.kind()
&& let Some(cast_ty) = cast_ty.builtin_deref(true) && let Some(cast_ty) = cast_ty.builtin_deref(true)
&& let ty::Slice(..) = cast_ty.ty.kind() && let ty::Slice(..) = cast_ty.kind()
{ {
slice_lengths[local] = Some(*len); slice_lengths[local] = Some(*len);
} }

View file

@ -401,10 +401,8 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
.use_amp_amp_for_conjunction = use `&&` to perform logical conjunction .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
.use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}` parse_invalid_meta_item = expected unsuffixed literal, found `{$token}`
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
parse_invalid_meta_item_unquoted_ident = expected unsuffixed literal, found `{$token}`
.suggestion = surround the identifier with quotation marks to parse it as a string
parse_invalid_offset_of = offset_of expects dot-separated field and variant names parse_invalid_offset_of = offset_of expects dot-separated field and variant names

View file

@ -978,21 +978,13 @@ pub(crate) struct InvalidMetaItem {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
pub token: Token, pub token: Token,
}
#[derive(Diagnostic)]
#[diag(parse_invalid_meta_item_unquoted_ident)]
pub(crate) struct InvalidMetaItemUnquotedIdent {
#[primary_span]
pub span: Span,
pub token: Token,
#[subdiagnostic] #[subdiagnostic]
pub sugg: InvalidMetaItemSuggQuoteIdent, pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
} }
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] #[multipart_suggestion(parse_quote_ident_sugg, applicability = "machine-applicable")]
pub(crate) struct InvalidMetaItemSuggQuoteIdent { pub(crate) struct InvalidMetaItemQuoteIdentSugg {
#[suggestion_part(code = "\"")] #[suggestion_part(code = "\"")]
pub before: Span, pub before: Span,
#[suggestion_part(code = "\"")] #[suggestion_part(code = "\"")]

View file

@ -1,7 +1,4 @@
use crate::errors::{ use crate::errors;
InvalidMetaItem, InvalidMetaItemSuggQuoteIdent, InvalidMetaItemUnquotedIdent,
SuffixedLiteralInAttribute,
};
use crate::fluent_generated as fluent; use crate::fluent_generated as fluent;
use crate::maybe_whole; use crate::maybe_whole;
@ -318,7 +315,7 @@ impl<'a> Parser<'a> {
debug!("checking if {:?} is unsuffixed", lit); debug!("checking if {:?} is unsuffixed", lit);
if !lit.kind.is_unsuffixed() { if !lit.kind.is_unsuffixed() {
self.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span }); self.dcx().emit_err(errors::SuffixedLiteralInAttribute { span: lit.span });
} }
Ok(lit) Ok(lit)
@ -356,10 +353,11 @@ impl<'a> Parser<'a> {
Ok(nmis) Ok(nmis)
} }
/// Matches the following grammar (per RFC 1559). /// Parse a meta item per RFC 1559.
///
/// ```ebnf /// ```ebnf
/// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; /// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ;
/// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; /// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ;
/// ``` /// ```
pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
// We can't use `maybe_whole` here because it would bump in the `None` // We can't use `maybe_whole` here because it would bump in the `None`
@ -387,7 +385,6 @@ impl<'a> Parser<'a> {
Ok(if self.eat(&token::Eq) { Ok(if self.eat(&token::Eq) {
ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?) ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?)
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
// Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?; let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
ast::MetaItemKind::List(list) ast::MetaItemKind::List(list)
} else { } else {
@ -395,38 +392,45 @@ impl<'a> Parser<'a> {
}) })
} }
/// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`. /// Parse an inner meta item per RFC 1559.
///
/// ```ebnf
/// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
/// ```
fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
match self.parse_unsuffixed_meta_item_lit() { match self.parse_unsuffixed_meta_item_lit() {
Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)), Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)),
Err(err) => err.cancel(), Err(err) => err.cancel(), // we provide a better error below
} }
match self.parse_meta_item() { match self.parse_meta_item() {
Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)), Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
Err(err) => err.cancel(), Err(err) => err.cancel(), // we provide a better error below
} }
let token = self.token.clone(); let mut err = errors::InvalidMetaItem {
span: self.token.span,
token: self.token.clone(),
quote_ident_sugg: None,
};
// Check for unquoted idents in meta items, e.g.: #[cfg(key = foo)] // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
// `from_expansion()` ensures we don't suggest for cases such as // don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
// `#[cfg(feature = $expr)]` in macros // when macro metavariables are involved.
if self.prev_token == token::Eq && !self.token.span.from_expansion() { if self.prev_token == token::Eq
&& let token::Ident(..) = self.token.kind
{
let before = self.token.span.shrink_to_lo(); let before = self.token.span.shrink_to_lo();
while matches!(self.token.kind, token::Ident(..)) { while let token::Ident(..) = self.token.kind {
self.bump(); self.bump();
} }
let after = self.prev_token.span.shrink_to_hi(); err.quote_ident_sugg = Some(errors::InvalidMetaItemQuoteIdentSugg {
let sugg = InvalidMetaItemSuggQuoteIdent { before, after }; before,
return Err(self.dcx().create_err(InvalidMetaItemUnquotedIdent { after: self.prev_token.span.shrink_to_hi(),
span: token.span, });
token,
sugg,
}));
} }
Err(self.dcx().create_err(InvalidMetaItem { span: token.span, token })) Err(self.dcx().create_err(err))
} }
} }

View file

@ -256,10 +256,9 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Primitive {
rustc_abi::Primitive::Int(length, signed) => { rustc_abi::Primitive::Int(length, signed) => {
Primitive::Int { length: length.stable(tables), signed: *signed } Primitive::Int { length: length.stable(tables), signed: *signed }
} }
rustc_abi::Primitive::F16 => Primitive::Float { length: FloatLength::F16 }, rustc_abi::Primitive::Float(length) => {
rustc_abi::Primitive::F32 => Primitive::Float { length: FloatLength::F32 }, Primitive::Float { length: length.stable(tables) }
rustc_abi::Primitive::F64 => Primitive::Float { length: FloatLength::F64 }, }
rustc_abi::Primitive::F128 => Primitive::Float { length: FloatLength::F128 },
rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables)), rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables)),
} }
} }
@ -287,6 +286,19 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Integer {
} }
} }
impl<'tcx> Stable<'tcx> for rustc_abi::Float {
type T = FloatLength;
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
match self {
rustc_abi::Float::F16 => FloatLength::F16,
rustc_abi::Float::F32 => FloatLength::F32,
rustc_abi::Float::F64 => FloatLength::F64,
rustc_abi::Float::F128 => FloatLength::F128,
}
}
}
impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange { impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange {
type T = WrappingRange; type T = WrappingRange;

View file

@ -630,8 +630,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
let pointee_ty = ct let pointee_ty = ct
.ty() .ty()
.builtin_deref(true) .builtin_deref(true)
.expect("tried to dereference on non-ptr type") .expect("tried to dereference on non-ptr type");
.ty;
// FIXME(const_generics): add an assert that we only do this for valtrees. // FIXME(const_generics): add an assert that we only do this for valtrees.
let dereferenced_const = self.tcx.mk_ct_from_kind(ct.kind(), pointee_ty); let dereferenced_const = self.tcx.mk_ct_from_kind(ct.kind(), pointee_ty);
dereferenced_const.print(self)?; dereferenced_const.print(self)?;

View file

@ -59,7 +59,7 @@ where
_ => return Err(CannotUseFpConv), _ => return Err(CannotUseFpConv),
} }
} }
abi::F16 | abi::F32 | abi::F64 | abi::F128 => { abi::Float(_) => {
if arg_layout.size.bits() > flen { if arg_layout.size.bits() > flen {
return Err(CannotUseFpConv); return Err(CannotUseFpConv);
} }

View file

@ -26,8 +26,8 @@ where
{ {
match ret.layout.field(cx, i).abi { match ret.layout.field(cx, i).abi {
abi::Abi::Scalar(scalar) => match scalar.primitive() { abi::Abi::Scalar(scalar) => match scalar.primitive() {
abi::F32 => Some(Reg::f32()), abi::Float(abi::F32) => Some(Reg::f32()),
abi::F64 => Some(Reg::f64()), abi::Float(abi::F64) => Some(Reg::f64()),
_ => None, _ => None,
}, },
_ => None, _ => None,
@ -110,7 +110,7 @@ where
// We only care about aligned doubles // We only care about aligned doubles
if let abi::Abi::Scalar(scalar) = field.abi { if let abi::Abi::Scalar(scalar) = field.abi {
if let abi::F64 = scalar.primitive() { if scalar.primitive() == abi::Float(abi::F64) {
if offset.is_aligned(dl.f64_align.abi) { if offset.is_aligned(dl.f64_align.abi) {
// Insert enough integers to cover [last_offset, offset) // Insert enough integers to cover [last_offset, offset)
assert!(last_offset.is_aligned(dl.f64_align.abi)); assert!(last_offset.is_aligned(dl.f64_align.abi));

View file

@ -443,7 +443,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Abi::Scalar(scalar) => { Abi::Scalar(scalar) => {
let kind = match scalar.primitive() { let kind = match scalar.primitive() {
abi::Int(..) | abi::Pointer(_) => RegKind::Integer, abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
abi::F16 | abi::F32 | abi::F64 | abi::F128 => RegKind::Float, abi::Float(_) => RegKind::Float,
}; };
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
} }

View file

@ -65,7 +65,7 @@ where
_ => return Err(CannotUseFpConv), _ => return Err(CannotUseFpConv),
} }
} }
abi::F16 | abi::F32 | abi::F64 | abi::F128 => { abi::Float(_) => {
if arg_layout.size.bits() > flen { if arg_layout.size.bits() > flen {
return Err(CannotUseFpConv); return Err(CannotUseFpConv);
} }

View file

@ -20,7 +20,7 @@ where
{ {
let dl = cx.data_layout(); let dl = cx.data_layout();
if !matches!(scalar.primitive(), abi::F32 | abi::F64) { if !matches!(scalar.primitive(), abi::Float(abi::F32 | abi::F64)) {
return data; return data;
} }
@ -56,7 +56,7 @@ where
return data; return data;
} }
if scalar.primitive() == abi::F32 { if scalar.primitive() == abi::Float(abi::F32) {
data.arg_attribute = ArgAttribute::InReg; data.arg_attribute = ArgAttribute::InReg;
data.prefix[data.prefix_index] = Some(Reg::f32()); data.prefix[data.prefix_index] = Some(Reg::f32());
data.last_offset = offset + Reg::f32().size; data.last_offset = offset + Reg::f32().size;
@ -80,14 +80,14 @@ where
{ {
data = arg_scalar(cx, scalar1, offset, data); data = arg_scalar(cx, scalar1, offset, data);
match (scalar1.primitive(), scalar2.primitive()) { match (scalar1.primitive(), scalar2.primitive()) {
(abi::F32, _) => offset += Reg::f32().size, (abi::Float(abi::F32), _) => offset += Reg::f32().size,
(_, abi::F64) => offset += Reg::f64().size, (_, abi::Float(abi::F64)) => offset += Reg::f64().size,
(abi::Int(i, _signed), _) => offset += i.size(), (abi::Int(i, _signed), _) => offset += i.size(),
(abi::Pointer(_), _) => offset += Reg::i64().size, (abi::Pointer(_), _) => offset += Reg::i64().size,
_ => {} _ => {}
} }
if (offset.bytes() % 4) != 0 && matches!(scalar2.primitive(), abi::F32 | abi::F64) { if (offset.bytes() % 4) != 0 && matches!(scalar2.primitive(), abi::Float(abi::F32 | abi::F64)) {
offset += Size::from_bytes(4 - (offset.bytes() % 4)); offset += Size::from_bytes(4 - (offset.bytes() % 4));
} }
data = arg_scalar(cx, scalar2, offset, data); data = arg_scalar(cx, scalar2, offset, data);

View file

@ -51,7 +51,7 @@ where
Abi::Scalar(scalar) => match scalar.primitive() { Abi::Scalar(scalar) => match scalar.primitive() {
abi::Int(..) | abi::Pointer(_) => Class::Int, abi::Int(..) | abi::Pointer(_) => Class::Int,
abi::F16 | abi::F32 | abi::F64 | abi::F128 => Class::Sse, abi::Float(_) => Class::Sse,
}, },
Abi::Vector { .. } => Class::Sse, Abi::Vector { .. } => Class::Sse,

View file

@ -1,4 +1,5 @@
use rustc_data_structures::intern::Interned; use rustc_data_structures::intern::Interned;
pub use Float::*;
pub use Integer::*; pub use Integer::*;
pub use Primitive::*; pub use Primitive::*;
@ -11,7 +12,8 @@ use rustc_macros::HashStable_Generic;
pub mod call; pub mod call;
pub use rustc_abi::*; // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
pub use rustc_abi::{Float, *};
impl ToJson for Endian { impl ToJson for Endian {
fn to_json(&self) -> Json { fn to_json(&self) -> Json {
@ -207,7 +209,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
C: HasDataLayout, C: HasDataLayout,
{ {
match self.abi { match self.abi {
Abi::Scalar(scalar) => matches!(scalar.primitive(), F32 | F64), Abi::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)),
Abi::Aggregate { .. } => { Abi::Aggregate { .. } => {
if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
self.field(cx, 0).is_single_fp_element(cx) self.field(cx, 0).is_single_fp_element(cx)

View file

@ -5,7 +5,7 @@ use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::{CoroutineLayout, CoroutineSavedLocal}; use rustc_middle::mir::{CoroutineLayout, CoroutineSavedLocal};
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::ty::layout::{ use rustc_middle::ty::layout::{
IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES, FloatExt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
}; };
use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{ use rustc_middle::ty::{
@ -180,12 +180,7 @@ fn layout_of_uncached<'tcx>(
)), )),
ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)), ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)),
ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)), ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)),
ty::Float(fty) => scalar(match fty { ty::Float(fty) => scalar(Float(Float::from_float_ty(fty))),
ty::FloatTy::F16 => F16,
ty::FloatTy::F32 => F32,
ty::FloatTy::F64 => F64,
ty::FloatTy::F128 => F128,
}),
ty::FnPtr(_) => { ty::FnPtr(_) => {
let mut ptr = scalar_unit(Pointer(dl.instruction_address_space)); let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
ptr.valid_range_mut().start = 1; ptr.valid_range_mut().start = 1;

View file

@ -6,7 +6,7 @@ use rustc_errors::{Applicability, Diag};
use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource};
use rustc_lint::{LateContext, LintContext}; use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut}; use rustc_middle::ty::{GenericArgKind, Ty};
use rustc_span::Span; use rustc_span::Span;
use super::SIGNIFICANT_DROP_IN_SCRUTINEE; use super::SIGNIFICANT_DROP_IN_SCRUTINEE;
@ -234,9 +234,9 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
} }
let ty = self.sig_drop_checker.get_type(expr); let ty = self.sig_drop_checker.get_type(expr);
if ty.is_ref() { if ty.is_ref() {
// We checked that the type was ref, so builtin_deref will return Some TypeAndMut, // We checked that the type was ref, so builtin_deref will return Some,
// but let's avoid any chance of an ICE // but let's avoid any chance of an ICE.
if let Some(TypeAndMut { ty, .. }) = ty.builtin_deref(true) { if let Some(ty) = ty.builtin_deref(true) {
if ty.is_trivially_pure_clone_copy() { if ty.is_trivially_pure_clone_copy() {
self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndDerefToCopy); self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndDerefToCopy);
} else if allow_move_and_clone { } else if allow_move_and_clone {

View file

@ -70,7 +70,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default();
let with_deref = arg_ty let with_deref = arg_ty
.builtin_deref(true) .builtin_deref(true)
.and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty)) .and_then(|ty| symmetric_partial_eq(cx, ty, other_ty))
.unwrap_or_default(); .unwrap_or_default();
if !with_deref.is_implemented() && !without_deref.is_implemented() { if !with_deref.is_implemented() && !without_deref.is_implemented() {

View file

@ -134,7 +134,7 @@ fn check_rvalue<'tcx>(
) => Err((span, "function pointer casts are not allowed in const fn".into())), ) => Err((span, "function pointer casts are not allowed in const fn".into())),
Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => { Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => {
let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) { let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) {
deref_ty.ty deref_ty
} else { } else {
// We cannot allow this for now. // We cannot allow this for now.
return Err((span, "unsizing casts are only allowed for references right now".into())); return Err((span, "unsizing casts are only allowed for references right now".into()));

View file

@ -136,7 +136,7 @@ impl NewPermission {
cx: &crate::MiriInterpCx<'_, 'tcx>, cx: &crate::MiriInterpCx<'_, 'tcx>,
) -> Self { ) -> Self {
// `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling). // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling).
let pointee = ty.builtin_deref(true).unwrap().ty; let pointee = ty.builtin_deref(true).unwrap();
if pointee.is_unpin(*cx.tcx, cx.param_env()) { if pointee.is_unpin(*cx.tcx, cx.param_env()) {
// A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only
// a weak protector). // a weak protector).

View file

@ -173,7 +173,7 @@ impl<'tcx> NewPermission {
cx: &crate::MiriInterpCx<'_, 'tcx>, cx: &crate::MiriInterpCx<'_, 'tcx>,
zero_size: bool, zero_size: bool,
) -> Option<Self> { ) -> Option<Self> {
let pointee = ty.builtin_deref(true).unwrap().ty; let pointee = ty.builtin_deref(true).unwrap();
pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| { pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| {
// Regular `Unpin` box, give it `noalias` but only a weak protector // Regular `Unpin` box, give it `noalias` but only a weak protector
// because it is valid to deallocate it within the function. // because it is valid to deallocate it within the function.

View file

@ -117,7 +117,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"write_bytes" | "volatile_set_memory" => { "write_bytes" | "volatile_set_memory" => {
let [ptr, val_byte, count] = check_arg_count(args)?; let [ptr, val_byte, count] = check_arg_count(args)?;
let ty = ptr.layout.ty.builtin_deref(true).unwrap().ty; let ty = ptr.layout.ty.builtin_deref(true).unwrap();
let ty_layout = this.layout_of(ty)?; let ty_layout = this.layout_of(ty)?;
let val_byte = this.read_scalar(val_byte)?.to_u8()?; let val_byte = this.read_scalar(val_byte)?.to_u8()?;
let ptr = this.read_pointer(ptr)?; let ptr = this.read_pointer(ptr)?;

View file

@ -267,7 +267,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Op::WrappingOffset => { Op::WrappingOffset => {
let ptr = left.to_scalar().to_pointer(this)?; let ptr = left.to_scalar().to_pointer(this)?;
let offset_count = right.to_scalar().to_target_isize(this)?; let offset_count = right.to_scalar().to_target_isize(this)?;
let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap();
let offset_bytes = offset_count.wrapping_mul(pointee_size); let offset_bytes = offset_count.wrapping_mul(pointee_size);

View file

@ -378,8 +378,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
.builtin_deref(true) .builtin_deref(true)
.ok_or_else(|| err_ub_format!( .ok_or_else(|| err_ub_format!(
"wrong signature used for `pthread_key_create`: first argument must be a raw pointer." "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
))? ))?;
.ty;
let key_layout = this.layout_of(key_type)?; let key_layout = this.layout_of(key_type)?;
// Create key and write it into the memory where `key_ptr` wants it. // Create key and write it into the memory where `key_ptr` wants it.

View file

@ -6,8 +6,8 @@ use base_db::salsa::Cycle;
use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
use hir_def::{ use hir_def::{
layout::{ layout::{
Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size, Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions,
StructKind, TargetDataLayout, WrappingRange, Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
}, },
LocalFieldId, StructId, LocalFieldId, StructId,
}; };
@ -264,10 +264,10 @@ pub fn layout_of_ty_query(
), ),
chalk_ir::Scalar::Float(f) => scalar( chalk_ir::Scalar::Float(f) => scalar(
dl, dl,
match f { Primitive::Float(match f {
FloatTy::F32 => Primitive::F32, FloatTy::F32 => Float::F32,
FloatTy::F64 => Primitive::F64, FloatTy::F64 => Float::F64,
}, }),
), ),
}, },
TyKind::Tuple(len, tys) => { TyKind::Tuple(len, tys) => {

View file

@ -245,7 +245,6 @@ run-make/rlib-format-packed-bundled-libs/Makefile
run-make/rmeta-preferred/Makefile run-make/rmeta-preferred/Makefile
run-make/rustc-macro-dep-files/Makefile run-make/rustc-macro-dep-files/Makefile
run-make/rustdoc-io-error/Makefile run-make/rustdoc-io-error/Makefile
run-make/rustdoc-output-path/Makefile
run-make/rustdoc-scrape-examples-invalid-expr/Makefile run-make/rustdoc-scrape-examples-invalid-expr/Makefile
run-make/rustdoc-scrape-examples-macros/Makefile run-make/rustdoc-scrape-examples-macros/Makefile
run-make/rustdoc-scrape-examples-multiple/Makefile run-make/rustdoc-scrape-examples-multiple/Makefile

View file

@ -1,4 +0,0 @@
include ../tools.mk
all:
$(RUSTDOC) -o "$(TMPDIR)/foo/bar/doc" foo.rs

View file

@ -0,0 +1,9 @@
// Checks that if the output folder doesn't exist, rustdoc will create it.
use run_make_support::{rustdoc, tmp_dir};
fn main() {
let out_dir = tmp_dir().join("foo/bar/doc");
rustdoc().input("foo.rs").output(&out_dir).run();
assert!(out_dir.exists());
}

View file

@ -576,7 +576,9 @@ error: ABIs are not compatible
}, },
abi: Scalar( abi: Scalar(
Initialized { Initialized {
value: F32, value: Float(
F32,
),
valid_range: $FULL, valid_range: $FULL,
}, },
), ),

View file

@ -5,7 +5,7 @@
macro_rules! pass_nonterminal { macro_rules! pass_nonterminal {
($n:expr) => { ($n:expr) => {
#[repr(align($n))] #[repr(align($n))]
//~^ ERROR expected unsuffixed literal or identifier, found `n!()` //~^ ERROR expected unsuffixed literal, found `n!()`
struct S; struct S;
}; };
} }

View file

@ -1,4 +1,4 @@
error: expected unsuffixed literal or identifier, found `n!()` error: expected unsuffixed literal, found `n!()`
--> $DIR/nonterminal-expansion.rs:7:22 --> $DIR/nonterminal-expansion.rs:7:22
| |
LL | #[repr(align($n))] LL | #[repr(align($n))]

View file

@ -28,8 +28,8 @@ struct S9;
macro_rules! generate_s10 { macro_rules! generate_s10 {
($expr: expr) => { ($expr: expr) => {
#[cfg(feature = $expr)] #[cfg(feature = $expr)]
//~^ ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")` //~^ ERROR expected unsuffixed literal, found `concat!("nonexistent")`
//~| ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")` //~| ERROR expected unsuffixed literal, found `concat!("nonexistent")`
struct S10; struct S10;
} }
} }

View file

@ -54,7 +54,7 @@ LL | #[cfg(a = b"hi")]
| | | |
| help: consider removing the prefix | help: consider removing the prefix
error: expected unsuffixed literal or identifier, found `concat!("nonexistent")` error: expected unsuffixed literal, found `concat!("nonexistent")`
--> $DIR/cfg-attr-syntax-validation.rs:30:25 --> $DIR/cfg-attr-syntax-validation.rs:30:25
| |
LL | #[cfg(feature = $expr)] LL | #[cfg(feature = $expr)]
@ -65,7 +65,7 @@ LL | generate_s10!(concat!("nonexistent"));
| |
= note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected unsuffixed literal or identifier, found `concat!("nonexistent")` error: expected unsuffixed literal, found `concat!("nonexistent")`
--> $DIR/cfg-attr-syntax-validation.rs:30:25 --> $DIR/cfg-attr-syntax-validation.rs:30:25
| |
LL | #[cfg(feature = $expr)] LL | #[cfg(feature = $expr)]

View file

@ -4,7 +4,7 @@ error: expected unsuffixed literal, found `test`
LL | #[deprecated(note = test)] LL | #[deprecated(note = test)]
| ^^^^ | ^^^^
| |
help: surround the identifier with quotation marks to parse it as a string help: surround the identifier with quotation marks to make it into a string literal
| |
LL | #[deprecated(note = "test")] LL | #[deprecated(note = "test")]
| + + | + +

View file

@ -1,12 +1,17 @@
macro_rules! mac { macro_rules! mac {
($attr_item: meta) => { ($attr_item: meta) => {
#[cfg($attr_item)] #[cfg($attr_item)]
//~^ ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)` //~^ ERROR expected unsuffixed literal, found `an(arbitrary token stream)`
//~| ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)` //~| ERROR expected unsuffixed literal, found `an(arbitrary token stream)`
struct S; struct S;
} }
} }
mac!(an(arbitrary token stream)); mac!(an(arbitrary token stream));
#[cfg(feature = -1)]
//~^ ERROR expected unsuffixed literal, found `-`
//~| ERROR expected unsuffixed literal, found `-`
fn handler() {}
fn main() {} fn main() {}

View file

@ -1,4 +1,10 @@
error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)` error: expected unsuffixed literal, found `-`
--> $DIR/attr-bad-meta-4.rs:12:17
|
LL | #[cfg(feature = -1)]
| ^
error: expected unsuffixed literal, found `an(arbitrary token stream)`
--> $DIR/attr-bad-meta-4.rs:3:15 --> $DIR/attr-bad-meta-4.rs:3:15
| |
LL | #[cfg($attr_item)] LL | #[cfg($attr_item)]
@ -9,7 +15,7 @@ LL | mac!(an(arbitrary token stream));
| |
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)` error: expected unsuffixed literal, found `an(arbitrary token stream)`
--> $DIR/attr-bad-meta-4.rs:3:15 --> $DIR/attr-bad-meta-4.rs:3:15
| |
LL | #[cfg($attr_item)] LL | #[cfg($attr_item)]
@ -21,5 +27,13 @@ LL | mac!(an(arbitrary token stream));
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors error: expected unsuffixed literal, found `-`
--> $DIR/attr-bad-meta-4.rs:12:17
|
LL | #[cfg(feature = -1)]
| ^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 4 previous errors

View file

@ -1,17 +0,0 @@
//@ compile-flags: -Zdeduplicate-diagnostics=yes
//@ run-rustfix
#![allow(unexpected_cfgs)]
fn main() {
#[cfg(key="foo")]
//~^ ERROR expected unsuffixed literal, found `foo`
//~| HELP surround the identifier with quotation marks to parse it as a string
println!();
#[cfg(key="bar")]
println!();
#[cfg(key="foo bar baz")]
//~^ ERROR expected unsuffixed literal, found `foo`
//~| HELP surround the identifier with quotation marks to parse it as a string
println!();
}

View file

@ -1,17 +1,25 @@
//@ compile-flags: -Zdeduplicate-diagnostics=yes //@ compile-flags: -Zdeduplicate-diagnostics=yes
//@ run-rustfix
#![allow(unexpected_cfgs)] #![allow(unexpected_cfgs)]
fn main() { fn main() {
#[cfg(key=foo)] #[cfg(key=foo)]
//~^ ERROR expected unsuffixed literal, found `foo` //~^ ERROR expected unsuffixed literal, found `foo`
//~| HELP surround the identifier with quotation marks to parse it as a string //~| HELP surround the identifier with quotation marks to make it into a string literal
println!(); println!();
#[cfg(key="bar")] #[cfg(key="bar")]
println!(); println!();
#[cfg(key=foo bar baz)] #[cfg(key=foo bar baz)]
//~^ ERROR expected unsuffixed literal, found `foo` //~^ ERROR expected unsuffixed literal, found `foo`
//~| HELP surround the identifier with quotation marks to parse it as a string //~| HELP surround the identifier with quotation marks to make it into a string literal
println!(); println!();
} }
// Don't suggest surrounding `$name` or `nickname` with quotes:
macro_rules! make {
($name:ident) => { #[doc(alias = $name)] pub struct S; }
//~^ ERROR expected unsuffixed literal, found `nickname`
}
make!(nickname); //~ NOTE in this expansion

View file

@ -1,24 +1,35 @@
error: expected unsuffixed literal, found `foo` error: expected unsuffixed literal, found `foo`
--> $DIR/attr-unquoted-ident.rs:7:15 --> $DIR/attr-unquoted-ident.rs:6:15
| |
LL | #[cfg(key=foo)] LL | #[cfg(key=foo)]
| ^^^ | ^^^
| |
help: surround the identifier with quotation marks to parse it as a string help: surround the identifier with quotation marks to make it into a string literal
| |
LL | #[cfg(key="foo")] LL | #[cfg(key="foo")]
| + + | + +
error: expected unsuffixed literal, found `foo` error: expected unsuffixed literal, found `foo`
--> $DIR/attr-unquoted-ident.rs:13:15 --> $DIR/attr-unquoted-ident.rs:12:15
| |
LL | #[cfg(key=foo bar baz)] LL | #[cfg(key=foo bar baz)]
| ^^^ | ^^^
| |
help: surround the identifier with quotation marks to parse it as a string help: surround the identifier with quotation marks to make it into a string literal
| |
LL | #[cfg(key="foo bar baz")] LL | #[cfg(key="foo bar baz")]
| + + | + +
error: aborting due to 2 previous errors error: expected unsuffixed literal, found `nickname`
--> $DIR/attr-unquoted-ident.rs:21:38
|
LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; }
| ^^^^^
...
LL | make!(nickname);
| --------------- in this macro invocation
|
= note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 3 previous errors