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.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[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
/// the callee, and most operations on it will produce the wrong values.
Int(Integer, bool),
F16,
F32,
F64,
F128,
Float(Float),
Pointer(AddressSpace),
}
@ -952,10 +984,7 @@ impl Primitive {
match self {
Int(i, _) => i.size(),
F16 => Size::from_bits(16),
F32 => Size::from_bits(32),
F64 => Size::from_bits(64),
F128 => Size::from_bits(128),
Float(f) => f.size(),
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
// different address spaces can have different sizes
// (but TargetDataLayout doesn't currently parse that part of the DL string)
@ -969,10 +998,7 @@ impl Primitive {
match self {
Int(i, _) => i.align(dl),
F16 => dl.f16_align,
F32 => dl.f32_align,
F64 => dl.f64_align,
F128 => dl.f128_align,
Float(f) => f.align(dl),
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
// different address spaces can have different alignments
// (but TargetDataLayout doesn't currently parse that part of the DL string)

View File

@ -1483,10 +1483,9 @@ fn suggest_ampmut<'tcx>(
} else {
// otherwise, suggest that the user annotates the binding; we provide the
// type of the local.
let ty_mut = decl_ty.builtin_deref(true).unwrap();
assert_eq!(ty_mut.mutbl, hir::Mutability::Not);
let ty = decl_ty.builtin_deref(true).unwrap();
(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) {
let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity();
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(
literal_ty,
@ -637,7 +637,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
match pi {
ProjectionElem::Deref => {
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)
}))
}

View File

@ -670,11 +670,8 @@ fn codegen_stmt<'tcx>(
let to_ty = fx.monomorphize(to_ty);
fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.builtin_deref(true).is_some_and(
|ty::TypeAndMut { ty: pointee_ty, mutbl: _ }| {
has_ptr_meta(fx.tcx, pointee_ty)
},
)
ty.builtin_deref(true)
.is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_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_span::source_map::Spanned;
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 crate::constant::ConstantCx;
@ -32,10 +32,12 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type {
Integer::I64 => types::I64,
Integer::I128 => types::I128,
},
Primitive::F16 => unimplemented!("f16_f128"),
Primitive::F32 => types::F32,
Primitive::F64 => types::F64,
Primitive::F128 => unimplemented!("f16_f128"),
Primitive::Float(float) => match float {
Float::F16 => unimplemented!("f16_f128"),
Float::F32 => types::F32,
Float::F64 => types::F64,
Float::F128 => unimplemented!("f16_f128"),
},
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => pointer_ty(tcx),
}

View File

@ -586,7 +586,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
intrinsic_args!(fx, args => (base, offset); intrinsic);
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 ptr_diff = if pointee_size != 1 {
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 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 count = if pointee_size != 1 {
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
// 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);
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);
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 (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);

View File

@ -95,7 +95,7 @@ mod prelude {
pub(crate) use rustc_middle::mir::{self, *};
pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
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_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_rhs: CValue<'tcx>,
) -> CValue<'tcx> {
let is_thin_ptr = in_lhs
.layout()
.ty
.builtin_deref(true)
.map(|TypeAndMut { ty, mutbl: _ }| !has_ptr_meta(fx.tcx, ty))
.unwrap_or(true);
let is_thin_ptr =
in_lhs.layout().ty.builtin_deref(true).map(|ty| !has_ptr_meta(fx.tcx, ty)).unwrap_or(true);
if is_thin_ptr {
match bin_op {
@ -404,7 +400,7 @@ pub(crate) fn codegen_ptr_binop<'tcx>(
codegen_compare_bin_op(fx, bin_op, false, lhs, rhs)
}
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 pointee_size = fx.layout_of(pointee_ty).size.bytes();
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 mut coerce_ptr = || {
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);
unsize_ptr(fx, old_base, src.layout(), dst.layout(), Some(old_info))
} else {

View File

@ -819,7 +819,7 @@ impl<'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) {
let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx);
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 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 ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr();
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_target::abi::call::{CastTarget, FnAbi, Reg};
use rustc_target::abi::{
self, Abi, Align, FieldsShape, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface,
Variants, F128, F16, F32, F64,
self, Abi, Align, FieldsShape, Float, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface,
Variants,
};
use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType};
@ -283,10 +283,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
match scalar.primitive() {
Int(i, true) => cx.type_from_integer(i),
Int(i, false) => cx.type_from_unsigned_integer(i),
F16 => cx.type_f16(),
F32 => cx.type_f32(),
F64 => cx.type_f64(),
F128 => cx.type_f128(),
Float(f) => cx.type_from_float(f),
Pointer(address_space) => {
// If we know the alignment, pick something better than i8.
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) };
if element_type_index >= 0 {
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 {
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::I32, _) => cx.type_i32(),
Primitive::Int(Integer::I64, _) => cx.type_i64(),
Primitive::F32 => cx.type_f32(),
Primitive::F64 => cx.type_f64(),
Primitive::Float(Float::F32) => cx.type_f32(),
Primitive::Float(Float::F64) => cx.type_f64(),
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => cx.type_from_integer(dl.ptr_sized_integer()),
_ => unreachable!(),
@ -950,7 +950,7 @@ fn llvm_fixup_input<'ll, 'tcx>(
bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices))
}
(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())
}
@ -986,8 +986,8 @@ fn llvm_fixup_input<'ll, 'tcx>(
match s.primitive() {
// MIPS only supports register-length arithmetics.
Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()),
Primitive::F32 => bx.bitcast(value, bx.cx.type_i32()),
Primitive::F64 => bx.bitcast(value, bx.cx.type_i64()),
Primitive::Float(Float::F32) => bx.bitcast(value, bx.cx.type_i32()),
Primitive::Float(Float::F64) => bx.bitcast(value, bx.cx.type_i64()),
_ => value,
}
}
@ -1027,7 +1027,7 @@ fn llvm_fixup_output<'ll, 'tcx>(
bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices))
}
(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())
}
@ -1064,8 +1064,8 @@ fn llvm_fixup_output<'ll, 'tcx>(
// MIPS only supports register-length arithmetics.
Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()),
Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()),
Primitive::F32 => bx.bitcast(value, bx.cx.type_f32()),
Primitive::F64 => bx.bitcast(value, bx.cx.type_f64()),
Primitive::Float(Float::F32) => bx.bitcast(value, bx.cx.type_f32()),
Primitive::Float(Float::F64) => bx.bitcast(value, bx.cx.type_f64()),
_ => value,
}
}
@ -1100,7 +1100,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
cx.type_vector(elem_ty, count * 2)
}
(InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s))
if s.primitive() == Primitive::F64 =>
if s.primitive() == Primitive::Float(Float::F64) =>
{
cx.type_i64()
}
@ -1136,8 +1136,8 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
match s.primitive() {
// MIPS only supports register-length arithmetics.
Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(),
Primitive::F32 => cx.type_i32(),
Primitive::F64 => cx.type_i64(),
Primitive::Float(Float::F32) => cx.type_i32(),
Primitive::Float(Float::F64) => cx.type_i64(),
_ => 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.
match tag.primitive() {
Primitive::Int(t, _) => t,
Primitive::F16 => Integer::I16,
Primitive::F32 => Integer::I32,
Primitive::F64 => Integer::I64,
Primitive::F128 => Integer::I128,
Primitive::Float(f) => Integer::from_size(f.size()).unwrap(),
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => {
// 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::{bug, span_bug};
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 std::cmp::Ordering;
@ -231,13 +231,17 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
emit_va_arg(self, args[0], ret_ty)
}
}
Primitive::F16 => bug!("the va_arg intrinsic does not work with `f16`"),
Primitive::F64 | Primitive::Pointer(_) => {
Primitive::Float(Float::F16) => {
bug!("the va_arg intrinsic does not work with `f16`")
}
Primitive::Float(Float::F64) | Primitive::Pointer(_) => {
emit_va_arg(self, args[0], ret_ty)
}
// `va_arg` should never be used with the return type f32.
Primitive::F32 => bug!("the va_arg intrinsic does not work with `f32`"),
Primitive::F128 => {
Primitive::Float(Float::F32) => {
bug!("the va_arg intrinsic does not work with `f32`")
}
Primitive::Float(Float::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(|| {
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();
// The second argument must be a ptr-sized integer.
// (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::{self, Ty, TypeVisitableExt};
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 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 {
match scalar.primitive() {
Int(i, _) => cx.type_from_integer(i),
F16 => cx.type_f16(),
F32 => cx.type_f32(),
F64 => cx.type_f64(),
F128 => cx.type_f128(),
Float(f) => cx.type_from_float(f),
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
// 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);
}
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 {
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
.ty
.builtin_deref(true)
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", self))
.ty;
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", self));
let (llptr, llextra) = match self.val {
OperandValue::Immediate(llptr) => (llptr, None),
@ -455,8 +454,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
.layout
.ty
.builtin_deref(true)
.unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest))
.ty;
.unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest));
let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self
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);
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
(Int(..) | F16 | F32 | F64 | F128, Int(..) | F16 | F32 | F64 | F128) => {
bx.bitcast(imm, to_backend_ty)
}
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
(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());
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());
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 => {
let pointee_type = input_ty
.builtin_deref(true)
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty))
.ty;
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty));
let pointee_layout = bx.cx().layout_of(pointee_type);
if pointee_layout.is_zst() {
// `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::{self, Ty};
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
// `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 {
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
// a `ConstValue::Indirect` for wide references, so it is tightly restricted to just
// 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!(
matches!(
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,
) -> InterpResult<'tcx> {
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);
// `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.
@ -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>,
count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
) -> 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 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>,
rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::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());
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 => {
let ptr = left.to_scalar().to_pointer(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.
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>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
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 (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 op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) {
src_deref.ty
src_deref
} else {
self.fail(
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 op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) {
dst_deref.ty
dst_deref
} else {
self.fail(
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).
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.
if pointee.align.abi.bytes() > 1 {
// 0x01-filling is not aligned.

View File

@ -68,28 +68,27 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
}
// Otherwise, deref if type is derefable:
let (kind, new_ty) = if let Some(ty::TypeAndMut { ty, .. }) =
self.state.cur_ty.builtin_deref(self.include_raw_pointers)
{
debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
// 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
// autoderef expect this type to have been structurally normalized.
if self.infcx.next_trait_solver()
&& let ty::Alias(..) = ty.kind()
{
let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
self.state.obligations.extend(obligations);
(AutoderefKind::Builtin, normalized_ty)
let (kind, new_ty) =
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));
// 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
// autoderef expect this type to have been structurally normalized.
if self.infcx.next_trait_solver()
&& let ty::Alias(..) = ty.kind()
{
let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
self.state.obligations.extend(obligations);
(AutoderefKind::Builtin, normalized_ty)
} else {
(AutoderefKind::Builtin, ty)
}
} else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
// The overloaded deref check already normalizes the pointee type.
(AutoderefKind::Overloaded, ty)
} else {
(AutoderefKind::Builtin, ty)
}
} else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
// The overloaded deref check already normalizes the pointee type.
(AutoderefKind::Overloaded, ty)
} else {
return None;
};
return None;
};
self.state.steps.push((self.state.cur_ty, kind));
debug!(

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
/// *expression* is `T`. So this function just peels off the return
/// type by one layer to yield `T`.
pub(crate) fn make_overloaded_place_return_type(
&self,
method: MethodCallee<'tcx>,
) -> ty::TypeAndMut<'tcx> {
pub(crate) fn make_overloaded_place_return_type(&self, method: MethodCallee<'tcx>) -> Ty<'tcx> {
// extract method return type, which will be &T;
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.
// So peel off one-level, turning the &T into T.
match base_ty.builtin_deref(false) {
Some(t) => Ok(t.ty),
Some(ty) => Ok(ty),
None => {
debug!("By-ref binding of non-derefable type");
Err(())
@ -485,7 +485,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
) -> McResult<PlaceWithHirId<'tcx>> {
let base_curr_ty = base_place.place.ty();
let deref_ty = match base_curr_ty.builtin_deref(true) {
Some(mt) => mt.ty,
Some(pointee_ty) => pointee_ty,
None => {
debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
return Err(());

View File

@ -918,8 +918,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
inner: &Pat<'_>,
) -> Result<(), ErrorGuaranteed> {
if let PatKind::Binding(..) = inner.kind
&& let Some(mt) = self.shallow_resolve(expected).builtin_deref(true)
&& let ty::Dynamic(..) = mt.ty.kind()
&& let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
&& let ty::Dynamic(..) = pointee_ty.kind()
{
// This is "x = dyn SomeTrait" being reduced from
// "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_ty: Ty<'tcx>,
) -> Option<Ty<'tcx>> {
if let Some(mt) = oprnd_ty.builtin_deref(true) {
return Some(mt.ty);
if let Some(ty) = oprnd_ty.builtin_deref(true) {
return Some(ty);
}
let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?;
@ -36,7 +36,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
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);
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);
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()
.expr_ty_adjusted(base_expr)
.builtin_deref(false)
.expect("place op takes something that is not a ref")
.ty;
.expect("place op takes something that is not a ref");
let arg_ty = match op {
PlaceOp::Deref => None,

View File

@ -78,13 +78,9 @@ impl<'tcx> PlaceTy<'tcx> {
}
let answer = match *elem {
ProjectionElem::Deref => {
let ty = self
.ty
.builtin_deref(true)
.unwrap_or_else(|| {
bug!("deref projection of non-dereferenceable ty {:?}", self)
})
.ty;
let ty = self.ty.builtin_deref(true).unwrap_or_else(|| {
bug!("deref projection of non-dereferenceable ty {:?}", self)
});
PlaceTy::from_ty(ty)
}
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)]
impl Primitive {
#[inline]
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match *self {
Int(i, signed) => i.to_ty(tcx, signed),
F16 => tcx.types.f16,
F32 => tcx.types.f32,
F64 => tcx.types.f64,
F128 => tcx.types.f128,
Float(f) => f.to_ty(tcx),
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Pointer(_) => Ty::new_mut_ptr(tcx, tcx.types.unit),
}
@ -140,7 +159,7 @@ impl Primitive {
let signed = false;
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.
/// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly.
pub fn builtin_deref(self, explicit: bool) -> Option<TypeAndMut<'tcx>> {
match self.kind() {
Adt(def, _) if def.is_box() => {
Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not })
}
Ref(_, ty, mutbl) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
RawPtr(ty, mutbl) if explicit => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
pub fn builtin_deref(self, explicit: bool) -> Option<Ty<'tcx>> {
match *self.kind() {
Adt(def, _) if def.is_box() => Some(self.boxed_ty()),
Ref(_, ty, _) => Some(ty),
RawPtr(ty, _) if explicit => Some(ty),
_ => None,
}
}

View File

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

View File

@ -106,7 +106,7 @@ impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> {
}
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.
if !pointee_ty.is_sized(self.tcx, self.param_env) {
debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty);

View File

@ -52,104 +52,104 @@ pub(super) struct MCDCDecision {
pub(super) decision_depth: u16,
}
pub(super) struct CoverageSpans {
bcb_has_mappings: BitSet<BasicCoverageBlock>,
#[derive(Default)]
pub(super) struct ExtractedMappings {
pub(super) code_mappings: Vec<CodeMapping>,
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_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
/// their corresponding BCBs.
///
/// Returns `None` if no coverage-relevant spans could be extracted.
pub(super) fn generate_coverage_spans(
pub(super) fn extract_all_mapping_info_from_mir(
mir_body: &mir::Body<'_>,
hir_info: &ExtractedHirInfo,
basic_coverage_blocks: &CoverageGraph,
) -> Option<CoverageSpans> {
let mut code_mappings = vec![];
let mut branch_pairs = vec![];
let mut mcdc_branches = vec![];
let mut mcdc_decisions = vec![];
) -> ExtractedMappings {
if hir_info.is_async_fn {
// An async function desugars into a function that returns a future,
// with the user code wrapped in a closure. Any spans in the desugared
// outer function will be unhelpful, so just keep the signature span
// 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 {
code_mappings.push(CodeMapping { span, bcb: START_BCB });
mappings.code_mappings.push(CodeMapping { span, bcb: START_BCB });
}
} else {
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));
extract_mcdc_mappings(
mir_body,
hir_info.body_span,
basic_coverage_blocks,
&mut mcdc_branches,
&mut mcdc_decisions,
);
return mappings;
}
if code_mappings.is_empty()
&& branch_pairs.is_empty()
&& mcdc_branches.is_empty()
&& mcdc_decisions.is_empty()
{
return None;
}
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![];
// 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);
};
extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
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);
}
branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks));
// 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);
extract_mcdc_mappings(
mir_body,
hir_info.body_span,
basic_coverage_blocks,
&mut mcdc_bitmap_bytes,
&mut mcdc_branches,
&mut mcdc_decisions,
);
Some(CoverageSpans {
bcb_has_mappings,
ExtractedMappings {
code_mappings,
branch_pairs,
test_vector_bitmap_bytes,
mcdc_bitmap_bytes,
mcdc_branches,
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(
@ -215,6 +215,7 @@ pub(super) fn extract_mcdc_mappings(
mir_body: &mir::Body<'_>,
body_span: Span,
basic_coverage_blocks: &CoverageGraph,
mcdc_bitmap_bytes: &mut u32,
mcdc_branches: &mut impl Extend<MCDCBranch>,
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(
|decision: &mir::coverage::MCDCDecisionSpan| {
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))
.collect::<Option<_>>()?;
let bitmap_idx = next_bitmap_idx;
next_bitmap_idx += (1_u32 << decision.conditions_num).div_ceil(8);
// Each decision containing N conditions needs 2^N bits of space in
// 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 {
span,

View File

@ -7,13 +7,9 @@ mod spans;
#[cfg(test)]
mod tests;
use self::counters::{CounterIncrementSite, CoverageCounters};
use self::graph::{BasicCoverageBlock, CoverageGraph};
use self::mappings::CoverageSpans;
use crate::MirPass;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::coverage::{
CodeRegion, CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind,
};
use rustc_middle::mir::{
self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator,
TerminatorKind,
@ -23,6 +19,11 @@ use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::SourceMap;
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
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
/// 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);
////////////////////////////////////////////////////
// Compute coverage spans from the `CoverageGraph`.
let Some(coverage_spans) =
mappings::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks)
else {
// No relevant spans were found in MIR, so skip instrumenting this function.
return;
};
// Extract coverage spans and other mapping info from MIR.
let extracted_mappings =
mappings::extract_all_mapping_info_from_mir(mir_body, &hir_info, &basic_coverage_blocks);
////////////////////////////////////////////////////
// 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`
// and all `Expression` dependencies (operands) are also generated, for any other
// `BasicCoverageBlock`s not already associated with a coverage span.
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
let coverage_counters =
CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans);
let bcbs_with_counter_mappings =
extracted_mappings.all_bcbs_with_counter_mappings(&basic_coverage_blocks);
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() {
// No spans could be converted into valid mappings, so skip this function.
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(
mir_body,
&basic_coverage_blocks,
bcb_has_coverage_spans,
bcb_has_counter_mappings,
&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
.iter()
.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 {
function_source_hash: hir_info.function_source_hash,
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(),
mappings,
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>(
tcx: TyCtxt<'tcx>,
hir_info: &ExtractedHirInfo,
coverage_spans: &CoverageSpans,
extracted_mappings: &ExtractedMappings,
coverage_counters: &CoverageCounters,
) -> Vec<Mapping> {
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);
// 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();
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 }| {
let code_region = region_for_span(span)?;
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 }| {
let true_term = term_for_bcb(true_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: _ }| {
let code_region = region_for_span(span)?;
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, .. }| {
let code_region = region_for_span(span)?;
let kind = MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num });
@ -249,12 +262,8 @@ fn inject_coverage_statements<'tcx>(
fn inject_mcdc_statements<'tcx>(
mir_body: &mut mir::Body<'tcx>,
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.
for &mappings::MCDCDecision {
span: _,
@ -262,7 +271,7 @@ fn inject_mcdc_statements<'tcx>(
bitmap_idx,
conditions_num: _,
decision_depth,
} in &coverage_spans.mcdc_decisions
} in &extracted_mappings.mcdc_decisions
{
for end in end_bcbs {
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
&coverage_spans.mcdc_branches
&extracted_mappings.mcdc_branches
{
let Some(condition_info) = condition_info else { continue };
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())
&& let operand_ty = operand.ty(self.local_decls, self.tcx)
&& 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)
{
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;
if let Some(Mutability::Not) = ty.ref_mutability()
&& 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
// 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)
&& let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind
&& 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 ty::Slice(..) = to.ty.kind()
&& let ty::Slice(..) = to.kind()
{
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.
let source_ty = operand.ty(self.body, self.tcx);
let may_involve_vtable = match (
source_ty.builtin_deref(true).map(|t| t.ty.kind()),
target_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.kind()),
) {
(Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, // &str/&[T] unsizing
_ => true,

View File

@ -48,9 +48,9 @@ fn compute_slice_length<'tcx>(
let operand_ty = operand.ty(body, tcx);
debug!(?operand_ty);
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 ty::Slice(..) = cast_ty.ty.kind()
&& let ty::Slice(..) = cast_ty.kind()
{
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_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
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_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_offset_of = offset_of expects dot-separated field and variant names

View File

@ -978,21 +978,13 @@ pub(crate) struct InvalidMetaItem {
#[primary_span]
pub span: Span,
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]
pub sugg: InvalidMetaItemSuggQuoteIdent,
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
pub(crate) struct InvalidMetaItemSuggQuoteIdent {
#[multipart_suggestion(parse_quote_ident_sugg, applicability = "machine-applicable")]
pub(crate) struct InvalidMetaItemQuoteIdentSugg {
#[suggestion_part(code = "\"")]
pub before: Span,
#[suggestion_part(code = "\"")]

View File

@ -1,7 +1,4 @@
use crate::errors::{
InvalidMetaItem, InvalidMetaItemSuggQuoteIdent, InvalidMetaItemUnquotedIdent,
SuffixedLiteralInAttribute,
};
use crate::errors;
use crate::fluent_generated as fluent;
use crate::maybe_whole;
@ -318,7 +315,7 @@ impl<'a> Parser<'a> {
debug!("checking if {:?} is unsuffixed", lit);
if !lit.kind.is_unsuffixed() {
self.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span });
self.dcx().emit_err(errors::SuffixedLiteralInAttribute { span: lit.span });
}
Ok(lit)
@ -356,10 +353,11 @@ impl<'a> Parser<'a> {
Ok(nmis)
}
/// Matches the following grammar (per RFC 1559).
/// Parse a meta item per RFC 1559.
///
/// ```ebnf
/// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
/// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
/// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ;
/// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ;
/// ```
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`
@ -387,7 +385,6 @@ impl<'a> Parser<'a> {
Ok(if self.eat(&token::Eq) {
ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?)
} 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())?;
ast::MetaItemKind::List(list)
} 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> {
match self.parse_unsuffixed_meta_item_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() {
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)]
// `from_expansion()` ensures we don't suggest for cases such as
// `#[cfg(feature = $expr)]` in macros
if self.prev_token == token::Eq && !self.token.span.from_expansion() {
// Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
// don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
// when macro metavariables are involved.
if self.prev_token == token::Eq
&& let token::Ident(..) = self.token.kind
{
let before = self.token.span.shrink_to_lo();
while matches!(self.token.kind, token::Ident(..)) {
while let token::Ident(..) = self.token.kind {
self.bump();
}
let after = self.prev_token.span.shrink_to_hi();
let sugg = InvalidMetaItemSuggQuoteIdent { before, after };
return Err(self.dcx().create_err(InvalidMetaItemUnquotedIdent {
span: token.span,
token,
sugg,
}));
err.quote_ident_sugg = Some(errors::InvalidMetaItemQuoteIdentSugg {
before,
after: self.prev_token.span.shrink_to_hi(),
});
}
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) => {
Primitive::Int { length: length.stable(tables), signed: *signed }
}
rustc_abi::Primitive::F16 => Primitive::Float { length: FloatLength::F16 },
rustc_abi::Primitive::F32 => Primitive::Float { length: FloatLength::F32 },
rustc_abi::Primitive::F64 => Primitive::Float { length: FloatLength::F64 },
rustc_abi::Primitive::F128 => Primitive::Float { length: FloatLength::F128 },
rustc_abi::Primitive::Float(length) => {
Primitive::Float { length: length.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 {
type T = WrappingRange;

View File

@ -630,8 +630,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
let pointee_ty = ct
.ty()
.builtin_deref(true)
.expect("tried to dereference on non-ptr type")
.ty;
.expect("tried to dereference on non-ptr type");
// 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);
dereferenced_const.print(self)?;

View File

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

View File

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

View File

@ -443,7 +443,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Abi::Scalar(scalar) => {
let kind = match scalar.primitive() {
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 }))
}

View File

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

View File

@ -20,7 +20,7 @@ where
{
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;
}
@ -56,7 +56,7 @@ where
return data;
}
if scalar.primitive() == abi::F32 {
if scalar.primitive() == abi::Float(abi::F32) {
data.arg_attribute = ArgAttribute::InReg;
data.prefix[data.prefix_index] = Some(Reg::f32());
data.last_offset = offset + Reg::f32().size;
@ -80,14 +80,14 @@ where
{
data = arg_scalar(cx, scalar1, offset, data);
match (scalar1.primitive(), scalar2.primitive()) {
(abi::F32, _) => offset += Reg::f32().size,
(_, abi::F64) => offset += Reg::f64().size,
(abi::Float(abi::F32), _) => offset += Reg::f32().size,
(_, abi::Float(abi::F64)) => offset += Reg::f64().size,
(abi::Int(i, _signed), _) => offset += i.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));
}
data = arg_scalar(cx, scalar2, offset, data);

View File

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

View File

@ -1,4 +1,5 @@
use rustc_data_structures::intern::Interned;
pub use Float::*;
pub use Integer::*;
pub use Primitive::*;
@ -11,7 +12,8 @@ use rustc_macros::HashStable_Generic;
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 {
fn to_json(&self) -> Json {
@ -207,7 +209,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
C: HasDataLayout,
{
match self.abi {
Abi::Scalar(scalar) => matches!(scalar.primitive(), F32 | F64),
Abi::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)),
Abi::Aggregate { .. } => {
if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
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::query::Providers;
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::{
@ -180,12 +180,7 @@ fn layout_of_uncached<'tcx>(
)),
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::Float(fty) => scalar(match fty {
ty::FloatTy::F16 => F16,
ty::FloatTy::F32 => F32,
ty::FloatTy::F64 => F64,
ty::FloatTy::F128 => F128,
}),
ty::Float(fty) => scalar(Float(Float::from_float_ty(fty))),
ty::FnPtr(_) => {
let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
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::{Arm, Expr, ExprKind, MatchSource};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut};
use rustc_middle::ty::{GenericArgKind, Ty};
use rustc_span::Span;
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);
if ty.is_ref() {
// We checked that the type was ref, so builtin_deref will return Some TypeAndMut,
// but let's avoid any chance of an ICE
if let Some(TypeAndMut { ty, .. }) = ty.builtin_deref(true) {
// We checked that the type was ref, so builtin_deref will return Some,
// but let's avoid any chance of an ICE.
if let Some(ty) = ty.builtin_deref(true) {
if ty.is_trivially_pure_clone_copy() {
self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndDerefToCopy);
} 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 with_deref = arg_ty
.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();
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())),
Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => {
let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) {
deref_ty.ty
deref_ty
} else {
// We cannot allow this for now.
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>,
) -> Self {
// `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()) {
// A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only
// a weak protector).

View File

@ -173,7 +173,7 @@ impl<'tcx> NewPermission {
cx: &crate::MiriInterpCx<'_, 'tcx>,
zero_size: bool,
) -> 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(|()| {
// Regular `Unpin` box, give it `noalias` but only a weak protector
// 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" => {
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 val_byte = this.read_scalar(val_byte)?.to_u8()?;
let ptr = this.read_pointer(ptr)?;

View File

@ -267,7 +267,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Op::WrappingOffset => {
let ptr = left.to_scalar().to_pointer(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 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)
.ok_or_else(|| err_ub_format!(
"wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
))?
.ty;
))?;
let key_layout = this.layout_of(key_type)?;
// 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 hir_def::{
layout::{
Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size,
StructKind, TargetDataLayout, WrappingRange,
Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions,
Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
},
LocalFieldId, StructId,
};
@ -264,10 +264,10 @@ pub fn layout_of_ty_query(
),
chalk_ir::Scalar::Float(f) => scalar(
dl,
match f {
FloatTy::F32 => Primitive::F32,
FloatTy::F64 => Primitive::F64,
},
Primitive::Float(match f {
FloatTy::F32 => Float::F32,
FloatTy::F64 => Float::F64,
}),
),
},
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/rustc-macro-dep-files/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-macros/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(
Initialized {
value: F32,
value: Float(
F32,
),
valid_range: $FULL,
},
),

View File

@ -5,7 +5,7 @@
macro_rules! pass_nonterminal {
($n:expr) => {
#[repr(align($n))]
//~^ ERROR expected unsuffixed literal or identifier, found `n!()`
//~^ ERROR expected unsuffixed literal, found `n!()`
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
|
LL | #[repr(align($n))]

View File

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

View File

@ -54,7 +54,7 @@ LL | #[cfg(a = b"hi")]
| |
| 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
|
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)
error: expected unsuffixed literal or identifier, found `concat!("nonexistent")`
error: expected unsuffixed literal, found `concat!("nonexistent")`
--> $DIR/cfg-attr-syntax-validation.rs:30:25
|
LL | #[cfg(feature = $expr)]

View File

@ -4,7 +4,7 @@ error: expected unsuffixed literal, found `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")]
| + +

View File

@ -1,12 +1,17 @@
macro_rules! mac {
($attr_item: meta) => {
#[cfg($attr_item)]
//~^ ERROR expected unsuffixed literal or identifier, 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)`
//~| ERROR expected unsuffixed literal, found `an(arbitrary token stream)`
struct S;
}
}
mac!(an(arbitrary token stream));
#[cfg(feature = -1)]
//~^ ERROR expected unsuffixed literal, found `-`
//~| ERROR expected unsuffixed literal, found `-`
fn handler() {}
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
|
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)
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
|
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: 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
//@ 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
//~| HELP surround the identifier with quotation marks to make it into a string literal
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
//~| HELP surround the identifier with quotation marks to make it into a string literal
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`
--> $DIR/attr-unquoted-ident.rs:7:15
--> $DIR/attr-unquoted-ident.rs:6:15
|
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")]
| + +
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)]
| ^^^
|
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")]
| + +
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