Merge remote-tracking branch 'origin/master'

This commit is contained in:
kangarooCoder 2022-04-05 21:50:12 -05:00
commit c62d2106da
274 changed files with 2125 additions and 896 deletions

View file

@ -2068,7 +2068,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::GenericParam {
hir_id,
name,
span: self.lower_span(param.ident.span),
span: self.lower_span(param.span()),
pure_wrt_drop: self.sess.contains_name(&param.attrs, sym::may_dangle),
bounds: self.arena.alloc_from_iter(bounds),
kind,

View file

@ -772,14 +772,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Some((issued_span, span)),
);
self.suggest_using_local_if_applicable(
&mut err,
location,
(place, span),
gen_borrow_kind,
issued_borrow,
explanation,
);
self.suggest_using_local_if_applicable(&mut err, location, issued_borrow, explanation);
err
}
@ -789,8 +782,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&self,
err: &mut Diagnostic,
location: Location,
(place, span): (Place<'tcx>, Span),
gen_borrow_kind: BorrowKind,
issued_borrow: &BorrowData<'tcx>,
explanation: BorrowExplanation,
) {
@ -822,7 +813,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return;
};
let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local);
let Some((inner_call_loc,inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| {
let Some((inner_call_loc, inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| {
let Either::Right(term) = self.body.stmt_at(loc) else {
debug!("{:?} is a statement, so it can't be a call", loc);
return None;
@ -833,7 +824,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
};
debug!("checking call args for uses of inner_param: {:?}", args);
if args.contains(&Operand::Move(inner_param)) {
Some((loc,term))
Some((loc, term))
} else {
None
}

View file

@ -21,7 +21,7 @@ pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type {
}
pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type {
match scalar.value {
match scalar.primitive() {
Primitive::Int(int, _sign) => match int {
Integer::I8 => types::I8,
Integer::I16 => types::I16,

View file

@ -105,7 +105,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
// Decode the discriminant (specifically if it's niche-encoded).
match *tag_encoding {
TagEncoding::Direct => {
let signed = match tag_scalar.value {
let signed = match tag_scalar.primitive() {
Int(_, signed) => signed,
_ => false,
};

View file

@ -50,7 +50,7 @@ fn codegen_field<'tcx>(
}
fn scalar_pair_calculate_b_offset(tcx: TyCtxt<'_>, a_scalar: Scalar, b_scalar: Scalar) -> Offset32 {
let b_offset = a_scalar.value.size(&tcx).align_to(b_scalar.value.align(&tcx).abi);
let b_offset = a_scalar.size(&tcx).align_to(b_scalar.align(&tcx).abi);
Offset32::new(b_offset.bytes().try_into().unwrap())
}

View file

@ -694,11 +694,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
}
fn scalar_load_metadata<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, load: RValue<'gcc>, scalar: &abi::Scalar) {
let vr = scalar.valid_range.clone();
match scalar.value {
let vr = scalar.valid_range(bx);
match scalar.primitive() {
abi::Int(..) => {
if !scalar.is_always_valid(bx) {
bx.range_metadata(load, scalar.valid_range);
bx.range_metadata(load, vr);
}
}
abi::Pointer if vr.start < vr.end && !vr.contains(0) => {
@ -720,7 +720,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
OperandValue::Immediate(self.to_immediate(load, place.layout))
}
else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
let b_offset = a.size(self).align_to(b.align(self).abi);
let pair_type = place.layout.gcc_type(self, false);
let mut load = |i, scalar: &abi::Scalar, align| {

View file

@ -158,14 +158,14 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
}
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() };
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
match cv {
Scalar::Int(ScalarInt::ZST) => {
assert_eq!(0, layout.value.size(self).bytes());
assert_eq!(0, layout.size(self).bytes());
self.const_undef(self.type_ix(0))
}
Scalar::Int(int) => {
let data = int.assert_bits(layout.value.size(self));
let data = int.assert_bits(layout.size(self));
// FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
// the paths for floating-point values.
@ -209,7 +209,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
let base_addr = self.const_bitcast(base_addr, self.usize_type);
let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
let ptr = self.const_bitcast(base_addr + offset, ptr_type);
if layout.value != Pointer {
if layout.primitive() != Pointer {
self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
}
else {

View file

@ -328,7 +328,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
&cx.tcx,
),
abi::Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } },
abi::Scalar::Initialized { value: Primitive::Pointer, valid_range: WrappingRange::full(dl.pointer_size) },
cx.type_i8p(),
));
next_offset = offset + pointer_size;

View file

@ -224,7 +224,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
}
fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc> {
match scalar.value {
match scalar.primitive() {
Int(i, true) => cx.type_from_integer(i),
Int(i, false) => cx.type_from_unsigned_integer(i),
F32 => cx.type_f32(),
@ -282,7 +282,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
Size::ZERO
}
else {
a.value.size(cx).align_to(b.value.align(cx).abi)
a.size(cx).align_to(b.align(cx).abi)
};
self.scalar_gcc_type_at(cx, scalar, offset)
}

View file

@ -510,9 +510,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
// If the value is a boolean, the range is 0..2 and that ultimately
// become 0..0 when the type becomes i1, which would be rejected
// by the LLVM verifier.
if let Int(..) = scalar.value {
if let Int(..) = scalar.primitive() {
if !scalar.is_bool() && !scalar.is_always_valid(bx) {
bx.range_metadata(callsite, scalar.valid_range);
bx.range_metadata(callsite, scalar.valid_range(bx));
}
}
}

View file

@ -753,7 +753,7 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
/// Helper function to get the LLVM type for a Scalar. Pointers are returned as
/// the equivalent integer type.
fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Type {
match scalar.value {
match scalar.primitive() {
Primitive::Int(Integer::I8, _) => cx.type_i8(),
Primitive::Int(Integer::I16, _) => cx.type_i16(),
Primitive::Int(Integer::I32, _) => cx.type_i32(),
@ -774,7 +774,7 @@ fn llvm_fixup_input<'ll, 'tcx>(
) -> &'ll Value {
match (reg, layout.abi) {
(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
if let Primitive::Int(Integer::I8, _) = s.value {
if let Primitive::Int(Integer::I8, _) = s.primitive() {
let vec_ty = bx.cx.type_vector(bx.cx.type_i8(), 8);
bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0))
} else {
@ -785,7 +785,7 @@ fn llvm_fixup_input<'ll, 'tcx>(
let elem_ty = llvm_asm_scalar_type(bx.cx, s);
let count = 16 / layout.size.bytes();
let vec_ty = bx.cx.type_vector(elem_ty, count);
if let Primitive::Pointer = s.value {
if let Primitive::Pointer = s.primitive() {
value = bx.ptrtoint(value, bx.cx.type_isize());
}
bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0))
@ -800,7 +800,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.value == Primitive::F64 =>
if s.primitive() == Primitive::F64 =>
{
bx.bitcast(value, bx.cx.type_i64())
}
@ -812,7 +812,7 @@ fn llvm_fixup_input<'ll, 'tcx>(
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16),
Abi::Scalar(s),
) => {
if let Primitive::Int(Integer::I32, _) = s.value {
if let Primitive::Int(Integer::I32, _) = s.primitive() {
bx.bitcast(value, bx.cx.type_f32())
} else {
value
@ -826,19 +826,21 @@ fn llvm_fixup_input<'ll, 'tcx>(
),
Abi::Scalar(s),
) => {
if let Primitive::Int(Integer::I64, _) = s.value {
if let Primitive::Int(Integer::I64, _) = s.primitive() {
bx.bitcast(value, bx.cx.type_f64())
} else {
value
}
}
(InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value {
// 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()),
_ => value,
},
(InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => {
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()),
_ => value,
}
}
_ => value,
}
}
@ -852,7 +854,7 @@ fn llvm_fixup_output<'ll, 'tcx>(
) -> &'ll Value {
match (reg, layout.abi) {
(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
if let Primitive::Int(Integer::I8, _) = s.value {
if let Primitive::Int(Integer::I8, _) = s.primitive() {
bx.extract_element(value, bx.const_i32(0))
} else {
value
@ -860,7 +862,7 @@ fn llvm_fixup_output<'ll, 'tcx>(
}
(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) => {
value = bx.extract_element(value, bx.const_i32(0));
if let Primitive::Pointer = s.value {
if let Primitive::Pointer = s.primitive() {
value = bx.inttoptr(value, layout.llvm_type(bx.cx));
}
value
@ -875,7 +877,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.value == Primitive::F64 =>
if s.primitive() == Primitive::F64 =>
{
bx.bitcast(value, bx.cx.type_f64())
}
@ -887,7 +889,7 @@ fn llvm_fixup_output<'ll, 'tcx>(
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16),
Abi::Scalar(s),
) => {
if let Primitive::Int(Integer::I32, _) = s.value {
if let Primitive::Int(Integer::I32, _) = s.primitive() {
bx.bitcast(value, bx.cx.type_i32())
} else {
value
@ -901,20 +903,22 @@ fn llvm_fixup_output<'ll, 'tcx>(
),
Abi::Scalar(s),
) => {
if let Primitive::Int(Integer::I64, _) = s.value {
if let Primitive::Int(Integer::I64, _) = s.primitive() {
bx.bitcast(value, bx.cx.type_i64())
} else {
value
}
}
(InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value {
// 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()),
_ => value,
},
(InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => {
match s.primitive() {
// 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()),
_ => value,
}
}
_ => value,
}
}
@ -927,7 +931,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
) -> &'ll Type {
match (reg, layout.abi) {
(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
if let Primitive::Int(Integer::I8, _) = s.value {
if let Primitive::Int(Integer::I8, _) = s.primitive() {
cx.type_vector(cx.type_i8(), 8)
} else {
layout.llvm_type(cx)
@ -946,7 +950,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.value == Primitive::F64 =>
if s.primitive() == Primitive::F64 =>
{
cx.type_i64()
}
@ -958,7 +962,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16),
Abi::Scalar(s),
) => {
if let Primitive::Int(Integer::I32, _) = s.value {
if let Primitive::Int(Integer::I32, _) = s.primitive() {
cx.type_f32()
} else {
layout.llvm_type(cx)
@ -972,19 +976,21 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
),
Abi::Scalar(s),
) => {
if let Primitive::Int(Integer::I64, _) = s.value {
if let Primitive::Int(Integer::I64, _) = s.primitive() {
cx.type_f64()
} else {
layout.llvm_type(cx)
}
}
(InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value {
// 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(),
_ => layout.llvm_type(cx),
},
(InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => {
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(),
_ => layout.llvm_type(cx),
}
}
_ => layout.llvm_type(cx),
}
}

View file

@ -484,14 +484,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
bx.noundef_metadata(load);
}
match scalar.value {
match scalar.primitive() {
abi::Int(..) => {
if !scalar.is_always_valid(bx) {
bx.range_metadata(load, scalar.valid_range);
bx.range_metadata(load, scalar.valid_range(bx));
}
}
abi::Pointer => {
if !scalar.valid_range.contains(0) {
if !scalar.valid_range(bx).contains(0) {
bx.nonnull_metadata(load);
}
@ -525,7 +525,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
});
OperandValue::Immediate(self.to_immediate(llval, place.layout))
} else if let abi::Abi::ScalarPair(a, b) = place.layout.abi {
let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
let b_offset = a.size(self).align_to(b.align(self).abi);
let pair_ty = place.layout.llvm_type(self);
let mut load = |i, scalar: abi::Scalar, layout, align, offset| {

View file

@ -221,16 +221,16 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value {
let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() };
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
match cv {
Scalar::Int(ScalarInt::ZST) => {
assert_eq!(0, layout.value.size(self).bytes());
assert_eq!(0, layout.size(self).bytes());
self.const_undef(self.type_ix(0))
}
Scalar::Int(int) => {
let data = int.assert_bits(layout.value.size(self));
let data = int.assert_bits(layout.size(self));
let llval = self.const_uint_big(self.type_ix(bitsize), data);
if layout.value == Pointer {
if layout.primitive() == Pointer {
unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
} else {
self.const_bitcast(llval, llty)
@ -269,7 +269,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
1,
)
};
if layout.value != Pointer {
if layout.primitive() != Pointer {
unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
} else {
self.const_bitcast(llval, llty)

View file

@ -109,7 +109,10 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
&cx.tcx,
),
Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } },
Scalar::Initialized {
value: Primitive::Pointer,
valid_range: WrappingRange::full(dl.pointer_size),
},
cx.type_i8p_ext(address_space),
));
next_offset = offset + pointer_size;

View file

@ -118,7 +118,7 @@ fn tag_base_type<'ll, 'tcx>(
Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
// Niche tags are always normalized to unsized integers of the correct size.
match tag.value {
match tag.primitive() {
Primitive::Int(t, _) => t,
Primitive::F32 => Integer::I32,
Primitive::F64 => Integer::I64,
@ -136,7 +136,7 @@ fn tag_base_type<'ll, 'tcx>(
Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => {
// Direct tags preserve the sign.
tag.value.to_ty(cx.tcx)
tag.primitive().to_ty(cx.tcx)
}
}
}
@ -425,7 +425,7 @@ fn compute_discriminant_value<'ll, 'tcx>(
let value = (variant_index.as_u32() as u128)
.wrapping_sub(niche_variants.start().as_u32() as u128)
.wrapping_add(niche_start);
let value = tag.value.size(cx).truncate(value);
let value = tag.size(cx).truncate(value);
// NOTE(eddyb) do *NOT* remove this assert, until
// we pass the full 128-bit value to LLVM, otherwise
// truncation will be silent and remain undetected.

View file

@ -134,7 +134,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
sym::va_arg => {
match fn_abi.ret.layout.abi {
abi::Abi::Scalar(scalar) => {
match scalar.value {
match scalar.primitive() {
Primitive::Int(..) => {
if self.cx().size_of(ret_ty).bytes() < 4 {
// `va_arg` should not be called on an integer type

View file

@ -309,7 +309,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
scalar: Scalar,
offset: Size,
) -> &'a Type {
match scalar.value {
match scalar.primitive() {
Int(i, _) => cx.type_from_integer(i),
F32 => cx.type_f32(),
F64 => cx.type_f64(),
@ -362,8 +362,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
return cx.type_i1();
}
let offset =
if index == 0 { Size::ZERO } else { a.value.size(cx).align_to(b.value.align(cx).abi) };
let offset = if index == 0 { Size::ZERO } else { a.size(cx).align_to(b.align(cx).abi) };
self.scalar_llvm_type_at(cx, scalar, offset)
}

View file

@ -464,13 +464,13 @@ fn push_debuginfo_type_name<'tcx>(
// calculate the range of values for the dataful variant
let dataful_discriminant_range =
dataful_variant_layout.largest_niche().unwrap().scalar.valid_range;
dataful_variant_layout.largest_niche().unwrap().valid_range;
let min = dataful_discriminant_range.start;
let min = tag.value.size(&tcx).truncate(min);
let min = tag.size(&tcx).truncate(min);
let max = dataful_discriminant_range.end;
let max = tag.value.size(&tcx).truncate(max);
let max = tag.size(&tcx).truncate(max);
let dataful_variant_name = variant_name(*dataful_variant);
write!(output, ", {}, {}, {}", min, max, dataful_variant_name).unwrap();

View file

@ -1572,7 +1572,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
match (src.layout.abi, dst.layout.abi) {
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
if (src_scalar.value == abi::Pointer) == (dst_scalar.value == abi::Pointer) {
if (src_scalar.primitive() == abi::Pointer)
== (dst_scalar.primitive() == abi::Pointer)
{
assert_eq!(src.layout.size, dst.layout.size);
// NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`

View file

@ -207,11 +207,11 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
// Extract a scalar component from a pair.
(OperandValue::Pair(a_llval, b_llval), Abi::ScalarPair(a, b)) => {
if offset.bytes() == 0 {
assert_eq!(field.size, a.value.size(bx.cx()));
assert_eq!(field.size, a.size(bx.cx()));
OperandValue::Immediate(a_llval)
} else {
assert_eq!(offset, a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi));
assert_eq!(field.size, b.value.size(bx.cx()));
assert_eq!(offset, a.size(bx.cx()).align_to(b.align(bx.cx()).abi));
assert_eq!(field.size, b.size(bx.cx()));
OperandValue::Immediate(b_llval)
}
}
@ -316,7 +316,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout);
};
let ty = bx.backend_type(dest.layout);
let b_offset = a_scalar.value.size(bx).align_to(b_scalar.value.align(bx).abi);
let b_offset = a_scalar.size(bx).align_to(b_scalar.align(bx).abi);
let llptr = bx.struct_gep(ty, dest.llval, 0);
let val = bx.from_immediate(a);

View file

@ -100,7 +100,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
self.llval
}
Abi::ScalarPair(a, b)
if offset == a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi) =>
if offset == a.size(bx.cx()).align_to(b.align(bx.cx()).abi) =>
{
// Offset matches second field.
let ty = bx.backend_type(self.layout);
@ -234,7 +234,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
// Decode the discriminant (specifically if it's niche-encoded).
match *tag_encoding {
TagEncoding::Direct => {
let signed = match tag_scalar.value {
let signed = match tag_scalar.primitive() {
// We use `i1` for bytes that are always `0` or `1`,
// e.g., `#[repr(i8)] enum E { A, B }`, but we can't
// let LLVM interpret the `i1` as signed, because

View file

@ -299,7 +299,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let mut signed = false;
if let Abi::Scalar(scalar) = operand.layout.abi {
if let Int(_, s) = scalar.value {
if let Int(_, s) = scalar.primitive() {
// We use `i1` for bytes that are always `0` or `1`,
// e.g., `#[repr(i8)] enum E { A, B }`, but we can't
// let LLVM interpret the `i1` as signed, because
@ -307,15 +307,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
signed = !scalar.is_bool() && s;
if !scalar.is_always_valid(bx.cx())
&& scalar.valid_range.end >= scalar.valid_range.start
&& scalar.valid_range(bx.cx()).end
>= scalar.valid_range(bx.cx()).start
{
// We want `table[e as usize ± k]` to not
// have bound checks, and this is the most
// convenient place to put the `assume`s.
if scalar.valid_range.start > 0 {
let enum_value_lower_bound = bx
.cx()
.const_uint_big(ll_t_in, scalar.valid_range.start);
if scalar.valid_range(bx.cx()).start > 0 {
let enum_value_lower_bound = bx.cx().const_uint_big(
ll_t_in,
scalar.valid_range(bx.cx()).start,
);
let cmp_start = bx.icmp(
IntPredicate::IntUGE,
llval,
@ -324,8 +326,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.assume(cmp_start);
}
let enum_value_upper_bound =
bx.cx().const_uint_big(ll_t_in, scalar.valid_range.end);
let enum_value_upper_bound = bx
.cx()
.const_uint_big(ll_t_in, scalar.valid_range(bx.cx()).end);
let cmp_end = bx.icmp(
IntPredicate::IntULE,
llval,

View file

@ -15,7 +15,7 @@ use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, subst::Subst, TyCtxt};
use rustc_span::source_map::Span;
use rustc_target::abi::Abi;
use rustc_target::abi::{self, Abi};
use std::borrow::Cow;
use std::convert::TryInto;
@ -118,7 +118,7 @@ pub(super) fn op_to_const<'tcx>(
// the usual cases of extracting e.g. a `usize`, without there being a real use case for the
// `Undef` situation.
let try_as_immediate = match op.layout.abi {
Abi::Scalar(..) => true,
Abi::Scalar(abi::Scalar::Initialized { .. }) => true,
Abi::ScalarPair(..) => match op.layout.ty.kind() {
ty::Ref(_, inner, _) => match *inner.kind() {
ty::Slice(elem) => elem == ecx.tcx.types.u8,

View file

@ -188,7 +188,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let val = self.read_scalar(&args[0])?.check_init()?;
let bits = val.to_bits(layout_of.size)?;
let kind = match layout_of.abi {
Abi::Scalar(scalar) => scalar.value,
Abi::Scalar(scalar) => scalar.primitive(),
_ => span_bug!(
self.cur_span(),
"{} called on invalid type {:?}",

View file

@ -10,7 +10,7 @@ use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty};
use rustc_middle::{mir, ty};
use rustc_target::abi::{Abi, HasDataLayout, Size, TagEncoding};
use rustc_target::abi::{self, Abi, HasDataLayout, Size, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants};
use super::{
@ -265,16 +265,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}));
};
// It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point.
// However, `MaybeUninit<u64>` is considered a `Scalar` as far as its layout is concerned --
// and yet cannot be represented by an interpreter `Scalar`, since we have to handle the
// case where some of the bytes are initialized and others are not. So, we need an extra
// check that walks over the type of `mplace` to make sure it is truly correct to treat this
// like a `Scalar` (or `ScalarPair`).
match mplace.layout.abi {
Abi::Scalar(..) => {
Abi::Scalar(abi::Scalar::Initialized { .. }) => {
let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?;
Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout }))
}
Abi::ScalarPair(a, b) => {
Abi::ScalarPair(
abi::Scalar::Initialized { value: a, .. },
abi::Scalar::Initialized { value: b, .. },
) => {
// We checked `ptr_align` above, so all fields will have the alignment they need.
// We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
// which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
let (a, b) = (a.value, b.value);
let (a_size, b_size) = (a.size(self), b.size(self));
let b_offset = a_size.align_to(b.align(self).abi);
assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields
@ -676,7 +684,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// may be a pointer. This is `tag_val.layout`; we just use it for sanity checks.
// Get layout for tag.
let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
let tag_layout = self.layout_of(tag_scalar_layout.primitive().to_int_ty(*self.tcx))?;
// Read tag and sanity-check `tag_layout`.
let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?;

View file

@ -772,13 +772,11 @@ where
// We checked `ptr_align` above, so all fields will have the alignment they need.
// We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
// which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
let (a, b) = match dest.layout.abi {
Abi::ScalarPair(a, b) => (a.value, b.value),
_ => span_bug!(
let Abi::ScalarPair(a, b) = dest.layout.abi else { span_bug!(
self.cur_span(),
"write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",
dest.layout
),
)
};
let (a_size, b_size) = (a.size(&tcx), b.size(&tcx));
let b_offset = a_size.align_to(b.align(&tcx).abi);
@ -1046,7 +1044,7 @@ where
// raw discriminants for enums are isize or bigger during
// their computation, but the in-memory tag is the smallest possible
// representation
let size = tag_layout.value.size(self);
let size = tag_layout.size(self);
let tag_val = size.truncate(discr_val);
let tag_dest = self.place_field(dest, tag_field)?;
@ -1070,7 +1068,7 @@ where
.expect("overflow computing relative variant idx");
// We need to use machine arithmetic when taking into account `niche_start`:
// tag_val = variant_index_relative + niche_start_val
let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?;
let tag_layout = self.layout_of(tag_layout.primitive().to_int_ty(*self.tcx))?;
let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
let variant_index_relative_val =
ImmTy::from_uint(variant_index_relative, tag_layout);

View file

@ -189,12 +189,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// that will take care to make it UB to leave the range, just
// like for transmute).
(abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => {
caller.value == callee.value
caller.primitive() == callee.primitive()
}
(
abi::Abi::ScalarPair(caller1, caller2),
abi::Abi::ScalarPair(callee1, callee2),
) => caller1.value == callee1.value && caller2.value == callee2.value,
) => {
caller1.primitive() == callee1.primitive()
&& caller2.primitive() == callee2.primitive()
}
// Be conservative
_ => false,
}

View file

@ -629,12 +629,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
op: &OpTy<'tcx, M::PointerTag>,
scalar_layout: ScalarAbi,
) -> InterpResult<'tcx> {
if scalar_layout.valid_range.is_full_for(op.layout.size) {
if scalar_layout.valid_range(self.ecx).is_full_for(op.layout.size) {
// Nothing to check
return Ok(());
}
// At least one value is excluded.
let valid_range = scalar_layout.valid_range;
let valid_range = scalar_layout.valid_range(self.ecx);
let WrappingRange { start, end } = valid_range;
let max_value = op.layout.size.unsigned_int_max();
assert!(end <= max_value);

View file

@ -1047,6 +1047,12 @@ impl<'a> ExtCtxt<'a> {
self.current_expansion.id.expn_data().call_site
}
/// Returns the current expansion kind's description.
pub(crate) fn expansion_descr(&self) -> String {
let expn_data = self.current_expansion.id.expn_data();
expn_data.kind.descr()
}
/// Equivalent of `Span::def_site` from the proc macro API,
/// except that the location is taken from the span passed as an argument.
pub fn with_def_site_ctxt(&self, span: Span) -> Span {

View file

@ -24,6 +24,8 @@ impl base::ProcMacro for BangProcMacro {
span: Span,
input: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
let _timer =
ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace).map_err(|e| {
@ -48,6 +50,8 @@ impl base::AttrProcMacro for AttrProcMacro {
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
let _timer =
ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
self.client
@ -97,17 +101,21 @@ impl MultiItemModifier for ProcMacroDerive {
nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No)
};
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
let stream = match self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace) {
Ok(stream) => stream,
Err(e) => {
let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
if let Some(s) = e.as_str() {
err.help(&format!("message: {}", s));
let stream = {
let _timer =
ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
match self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace) {
Ok(stream) => stream,
Err(e) => {
let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
if let Some(s) = e.as_str() {
err.help(&format!("message: {}", s));
}
err.emit();
return ExpandResult::Ready(vec![]);
}
err.emit();
return ExpandResult::Ready(vec![]);
}
};

View file

@ -12,7 +12,7 @@ use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeFoldable};
use rustc_span::source_map;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_target::abi::Abi;
use rustc_target::abi::{Abi, WrappingRange};
use rustc_target::abi::{Integer, TagEncoding, Variants};
use rustc_target::spec::abi::Abi as SpecAbi;
@ -796,14 +796,18 @@ crate fn repr_nullable_ptr<'tcx>(
// Return the nullable type this Option-like enum can be safely represented with.
let field_ty_abi = &cx.layout_of(field_ty).unwrap().abi;
if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
match (field_ty_scalar.valid_range.start, field_ty_scalar.valid_range.end) {
(0, x) if x == field_ty_scalar.value.size(&cx.tcx).unsigned_int_max() - 1 => {
match field_ty_scalar.valid_range(cx) {
WrappingRange { start: 0, end }
if end == field_ty_scalar.size(&cx.tcx).unsigned_int_max() - 1 =>
{
return Some(get_nullable_type(cx, field_ty).unwrap());
}
(1, _) => {
WrappingRange { start: 1, .. } => {
return Some(get_nullable_type(cx, field_ty).unwrap());
}
(start, end) => unreachable!("Unhandled start and end range: ({}, {})", start, end),
WrappingRange { start, end } => {
unreachable!("Unhandled start and end range: ({}, {})", start, end)
}
};
}
}
@ -1342,7 +1346,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
return
};
let tag_size = tag.value.size(&cx.tcx).bytes();
let tag_size = tag.size(&cx.tcx).bytes();
debug!(
"enum `{}` is {} bytes large with layout:\n{:#?}",

View file

@ -305,10 +305,10 @@ fn invert_mapping(map: &[u32]) -> Vec<u32> {
impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS<'tcx> {
let dl = self.data_layout();
let b_align = b.value.align(dl);
let align = a.value.align(dl).max(b_align).max(dl.aggregate_align);
let b_offset = a.value.size(dl).align_to(b_align.abi);
let size = (b_offset + b.value.size(dl)).align_to(align.abi);
let b_align = b.align(dl);
let align = a.align(dl).max(b_align).max(dl.aggregate_align);
let b_offset = a.size(dl).align_to(b_align.abi);
let size = (b_offset + b.size(dl)).align_to(align.abi);
// HACK(nox): We iter on `b` and then `a` because `max_by_key`
// returns the last maximum.
@ -567,7 +567,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
let scalar_unit = |value: Primitive| {
let size = value.size(dl);
assert!(size.bits() <= 128);
Scalar { value, valid_range: WrappingRange { start: 0, end: size.unsigned_int_max() } }
Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
};
let scalar =
|value: Primitive| tcx.intern_layout(LayoutS::scalar(self, scalar_unit(value)));
@ -581,11 +581,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// Basic scalars.
ty::Bool => tcx.intern_layout(LayoutS::scalar(
self,
Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } },
Scalar::Initialized {
value: Int(I8, false),
valid_range: WrappingRange { start: 0, end: 1 },
},
)),
ty::Char => tcx.intern_layout(LayoutS::scalar(
self,
Scalar {
Scalar::Initialized {
value: Int(I32, false),
valid_range: WrappingRange { start: 0, end: 0x10FFFF },
},
@ -598,7 +601,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
}),
ty::FnPtr(_) => {
let mut ptr = scalar_unit(Pointer);
ptr.valid_range = ptr.valid_range.with_start(1);
ptr.valid_range_mut().start = 1;
tcx.intern_layout(LayoutS::scalar(self, ptr))
}
@ -616,7 +619,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
let mut data_ptr = scalar_unit(Pointer);
if !ty.is_unsafe_ptr() {
data_ptr.valid_range = data_ptr.valid_range.with_start(1);
data_ptr.valid_range_mut().start = 1;
}
let pointee = tcx.normalize_erasing_regions(param_env, pointee);
@ -632,7 +635,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
ty::Dynamic(..) => {
let mut vtable = scalar_unit(Pointer);
vtable.valid_range = vtable.valid_range.with_start(1);
vtable.valid_range_mut().start = 1;
vtable
}
_ => return Err(LayoutError::Unknown(unsized_part)),
@ -889,14 +892,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// If all non-ZST fields have the same ABI, forward this ABI
if optimize && !field.is_zst() {
// Normalize scalar_unit to the maximal valid range
// Discard valid range information and allow undef
let field_abi = match field.abi {
Abi::Scalar(x) => Abi::Scalar(scalar_unit(x.value)),
Abi::Scalar(x) => Abi::Scalar(x.to_union()),
Abi::ScalarPair(x, y) => {
Abi::ScalarPair(scalar_unit(x.value), scalar_unit(y.value))
Abi::ScalarPair(x.to_union(), y.to_union())
}
Abi::Vector { element: x, count } => {
Abi::Vector { element: scalar_unit(x.value), count }
Abi::Vector { element: x.to_union(), count }
}
Abi::Uninhabited | Abi::Aggregate { .. } => {
Abi::Aggregate { sized: true }
@ -1000,14 +1003,16 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
if let Bound::Included(start) = start {
// FIXME(eddyb) this might be incorrect - it doesn't
// account for wrap-around (end < start) ranges.
assert!(scalar.valid_range.start <= start);
scalar.valid_range.start = start;
let valid_range = scalar.valid_range_mut();
assert!(valid_range.start <= start);
valid_range.start = start;
}
if let Bound::Included(end) = end {
// FIXME(eddyb) this might be incorrect - it doesn't
// account for wrap-around (end < start) ranges.
assert!(scalar.valid_range.end >= end);
scalar.valid_range.end = end;
let valid_range = scalar.valid_range_mut();
assert!(valid_range.end >= end);
valid_range.end = end;
}
// Update `largest_niche` if we have introduced a larger niche.
@ -1133,9 +1138,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// guaranteed to be initialised, not the
// other primitive.
if offset.bytes() == 0 {
Abi::ScalarPair(niche_scalar, scalar_unit(second.value))
Abi::ScalarPair(
niche_scalar,
scalar_unit(second.primitive()),
)
} else {
Abi::ScalarPair(scalar_unit(first.value), niche_scalar)
Abi::ScalarPair(
scalar_unit(first.primitive()),
niche_scalar,
)
}
}
_ => Abi::Aggregate { sized: true },
@ -1314,7 +1325,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
}
let tag_mask = ity.size().unsigned_int_max();
let tag = Scalar {
let tag = Scalar::Initialized {
value: Int(ity, signed),
valid_range: WrappingRange {
start: (min as u128 & tag_mask),
@ -1325,7 +1336,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// Without latter check aligned enums with custom discriminant values
// Would result in ICE see the issue #92464 for more info
if tag.value.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
if tag.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
abi = Abi::Scalar(tag);
} else {
// Try to use a ScalarPair for all tagged enums.
@ -1345,7 +1356,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
}
};
let prim = match field.abi {
Abi::Scalar(scalar) => scalar.value,
Abi::Scalar(scalar) => scalar.primitive(),
_ => {
common_prim = None;
break;
@ -1599,7 +1610,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
let max_discr = (info.variant_fields.len() - 1) as u128;
let discr_int = Integer::fit_unsigned(max_discr);
let discr_int_ty = discr_int.to_ty(tcx, false);
let tag = Scalar {
let tag = Scalar::Initialized {
value: Primitive::Int(discr_int, false),
valid_range: WrappingRange { start: 0, end: max_discr },
};
@ -1898,7 +1909,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
adt_kind.into(),
adt_packed,
match tag_encoding {
TagEncoding::Direct => Some(tag.value.size(self)),
TagEncoding::Direct => Some(tag.size(self)),
_ => None,
},
variant_infos,
@ -2304,7 +2315,7 @@ where
let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
TyAndLayout {
layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
ty: tag.value.to_ty(tcx),
ty: tag.primitive().to_ty(tcx),
}
};
@ -3079,11 +3090,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
}
// Only pointer types handled below.
if scalar.value != Pointer {
return;
}
let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return };
if !scalar.valid_range.contains(0) {
if !valid_range.contains(0) {
attrs.set(ArgAttribute::NonNull);
}

View file

@ -3298,7 +3298,9 @@ impl<'a> Resolver<'a> {
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
Some(path_res.base_res())
}
PathResult::NonModule(..) | PathResult::Failed { .. } => None,
PathResult::Module(ModuleOrUniformRoot::ExternPrelude)
| PathResult::NonModule(..)
| PathResult::Failed { .. } => None,
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
}
}

View file

@ -6,7 +6,7 @@ use crate::abi::{self, HasDataLayout, Size, TyAbiInterface};
fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
// Always sign extend u32 values on 64-bit mips
if let abi::Abi::Scalar(scalar) = arg.layout.abi {
if let abi::Int(i, signed) = scalar.value {
if let abi::Int(i, signed) = scalar.primitive() {
if !signed && i.size().bits() == 32 {
if let PassMode::Direct(ref mut attrs) = arg.mode {
attrs.ext(ArgExtension::Sext);
@ -25,7 +25,7 @@ where
C: HasDataLayout,
{
match ret.layout.field(cx, i).abi {
abi::Abi::Scalar(scalar) => match scalar.value {
abi::Abi::Scalar(scalar) => match scalar.primitive() {
abi::F32 => Some(Reg::f32()),
abi::F64 => Some(Reg::f64()),
_ => 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.value {
if let abi::F64 = scalar.primitive() {
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

@ -348,7 +348,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
// The primitive for this algorithm.
Abi::Scalar(scalar) => {
let kind = match scalar.value {
let kind = match scalar.primitive() {
abi::Int(..) | abi::Pointer => RegKind::Integer,
abi::F32 | abi::F64 => RegKind::Float,
};
@ -482,7 +482,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
Abi::Scalar(scalar) => PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)),
Abi::ScalarPair(a, b) => PassMode::Pair(
scalar_attrs(&layout, a, Size::ZERO),
scalar_attrs(&layout, b, a.value.size(cx).align_to(b.value.align(cx).abi)),
scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)),
),
Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()),
Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()),
@ -534,7 +534,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
pub fn extend_integer_width_to(&mut self, bits: u64) {
// Only integers have signedness
if let Abi::Scalar(scalar) = self.layout.abi {
if let abi::Int(i, signed) = scalar.value {
if let abi::Int(i, signed) = scalar.primitive() {
if i.size().bits() < bits {
if let PassMode::Direct(ref mut attrs) = self.mode {
if signed {

View file

@ -44,7 +44,7 @@ where
Ty: TyAbiInterface<'a, C> + Copy,
{
match arg_layout.abi {
Abi::Scalar(scalar) => match scalar.value {
Abi::Scalar(scalar) => match scalar.primitive() {
abi::Int(..) | abi::Pointer => {
if arg_layout.size.bits() > xlen {
return Err(CannotUseFpConv);
@ -298,7 +298,7 @@ fn classify_arg<'a, Ty, C>(
fn extend_integer_width<'a, Ty>(arg: &mut ArgAbi<'a, Ty>, xlen: u64) {
if let Abi::Scalar(scalar) = arg.layout.abi {
if let abi::Int(i, _) = scalar.value {
if let abi::Int(i, _) = scalar.primitive() {
// 32-bit integers are always sign-extended
if i.size().bits() == 32 && xlen > 32 {
if let PassMode::Direct(ref mut attrs) = arg.mode {

View file

@ -20,7 +20,7 @@ where
{
let dl = cx.data_layout();
if scalar.value != abi::F32 && scalar.value != abi::F64 {
if !scalar.primitive().is_float() {
return data;
}
@ -56,7 +56,7 @@ where
return data;
}
if scalar.value == abi::F32 {
if scalar.primitive() == abi::F32 {
data.arg_attribute = ArgAttribute::InReg;
data.prefix[data.prefix_index] = Some(Reg::f32());
data.last_offset = offset + Reg::f32().size;
@ -79,17 +79,15 @@ where
C: HasDataLayout,
{
data = arg_scalar(cx, &scalar1, offset, data);
if scalar1.value == abi::F32 {
offset += Reg::f32().size;
} else if scalar2.value == abi::F64 {
offset += Reg::f64().size;
} else if let abi::Int(i, _signed) = scalar1.value {
offset += i.size();
} else if scalar1.value == abi::Pointer {
offset = offset + Reg::i64().size;
match (scalar1.primitive(), scalar2.primitive()) {
(abi::F32, _) => offset += Reg::f32().size,
(_, abi::F64) => offset += Reg::f64().size,
(abi::Int(i, _signed), _) => offset += i.size(),
(abi::Pointer, _) => offset += Reg::i64().size,
_ => {}
}
if (offset.raw % 4) != 0 && (scalar2.value == abi::F32 || scalar2.value == abi::F64) {
if (offset.raw % 4) != 0 && scalar2.primitive().is_float() {
offset.raw += 4 - (offset.raw % 4);
}
data = arg_scalar(cx, &scalar2, offset, data);

View file

@ -49,7 +49,7 @@ where
let mut c = match layout.abi {
Abi::Uninhabited => return Ok(()),
Abi::Scalar(scalar) => match scalar.value {
Abi::Scalar(scalar) => match scalar.primitive() {
abi::Int(..) | abi::Pointer => Class::Int,
abi::F32 | abi::F64 => Class::Sse,
},

View file

@ -752,6 +752,10 @@ pub struct WrappingRange {
}
impl WrappingRange {
pub fn full(size: Size) -> Self {
Self { start: 0, end: size.unsigned_int_max() }
}
/// Returns `true` if `v` is contained in the range.
#[inline(always)]
pub fn contains(&self, v: u128) -> bool {
@ -799,13 +803,23 @@ impl fmt::Debug for WrappingRange {
/// Information about one scalar component of a Rust type.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[derive(HashStable_Generic)]
pub struct Scalar {
pub value: Primitive,
pub enum Scalar {
Initialized {
value: Primitive,
// FIXME(eddyb) always use the shortest range, e.g., by finding
// the largest space between two consecutive valid values and
// taking everything else as the (shortest) valid range.
pub valid_range: WrappingRange,
// FIXME(eddyb) always use the shortest range, e.g., by finding
// the largest space between two consecutive valid values and
// taking everything else as the (shortest) valid range.
valid_range: WrappingRange,
},
Union {
/// Even for unions, we need to use the correct registers for the kind of
/// values inside the union, so we keep the `Primitive` type around. We
/// also use it to compute the size of the scalar.
/// However, unions never have niches and even allow undef,
/// so there is no `valid_range`.
value: Primitive,
},
}
impl Scalar {
@ -813,14 +827,58 @@ impl Scalar {
pub fn is_bool(&self) -> bool {
matches!(
self,
Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } }
Scalar::Initialized {
value: Int(I8, false),
valid_range: WrappingRange { start: 0, end: 1 }
}
)
}
/// Get the primitive representation of this type, ignoring the valid range and whether the
/// value is allowed to be undefined (due to being a union).
pub fn primitive(&self) -> Primitive {
match *self {
Scalar::Initialized { value, .. } | Scalar::Union { value } => value,
}
}
pub fn align(self, cx: &impl HasDataLayout) -> AbiAndPrefAlign {
self.primitive().align(cx)
}
pub fn size(self, cx: &impl HasDataLayout) -> Size {
self.primitive().size(cx)
}
#[inline]
pub fn to_union(&self) -> Self {
Self::Union { value: self.primitive() }
}
#[inline]
pub fn valid_range(&self, cx: &impl HasDataLayout) -> WrappingRange {
match *self {
Scalar::Initialized { valid_range, .. } => valid_range,
Scalar::Union { value } => WrappingRange::full(value.size(cx)),
}
}
#[inline]
/// Allows the caller to mutate the valid range. This operation will panic if attempted on a union.
pub fn valid_range_mut(&mut self) -> &mut WrappingRange {
match self {
Scalar::Initialized { valid_range, .. } => valid_range,
Scalar::Union { .. } => panic!("cannot change the valid range of a union"),
}
}
/// Returns `true` if all possible numbers are valid, i.e `valid_range` covers the whole layout
#[inline]
pub fn is_always_valid<C: HasDataLayout>(&self, cx: &C) -> bool {
self.valid_range.is_full_for(self.value.size(cx))
match *self {
Scalar::Initialized { valid_range, .. } => valid_range.is_full_for(self.size(cx)),
Scalar::Union { .. } => true,
}
}
}
@ -988,7 +1046,7 @@ impl Abi {
#[inline]
pub fn is_signed(&self) -> bool {
match self {
Abi::Scalar(scal) => match scal.value {
Abi::Scalar(scal) => match scal.primitive() {
Primitive::Int(_, signed) => signed,
_ => false,
},
@ -1060,17 +1118,19 @@ pub enum TagEncoding {
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct Niche {
pub offset: Size,
pub scalar: Scalar,
pub value: Primitive,
pub valid_range: WrappingRange,
}
impl Niche {
pub fn from_scalar<C: HasDataLayout>(cx: &C, offset: Size, scalar: Scalar) -> Option<Self> {
let niche = Niche { offset, scalar };
let Scalar::Initialized { value, valid_range } = scalar else { return None };
let niche = Niche { offset, value, valid_range };
if niche.available(cx) > 0 { Some(niche) } else { None }
}
pub fn available<C: HasDataLayout>(&self, cx: &C) -> u128 {
let Scalar { value, valid_range: v } = self.scalar;
let Self { value, valid_range: v, .. } = *self;
let size = value.size(cx);
assert!(size.bits() <= 128);
let max_value = size.unsigned_int_max();
@ -1083,7 +1143,7 @@ impl Niche {
pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> {
assert!(count > 0);
let Scalar { value, valid_range: v } = self.scalar;
let Self { value, valid_range: v, .. } = *self;
let size = value.size(cx);
assert!(size.bits() <= 128);
let max_value = size.unsigned_int_max();
@ -1107,12 +1167,12 @@ impl Niche {
// If niche zero is already reserved, the selection of bounds are of little interest.
let move_start = |v: WrappingRange| {
let start = v.start.wrapping_sub(count) & max_value;
Some((start, Scalar { value, valid_range: v.with_start(start) }))
Some((start, Scalar::Initialized { value, valid_range: v.with_start(start) }))
};
let move_end = |v: WrappingRange| {
let start = v.end.wrapping_add(1) & max_value;
let end = v.end.wrapping_add(count) & max_value;
Some((start, Scalar { value, valid_range: v.with_end(end) }))
Some((start, Scalar::Initialized { value, valid_range: v.with_end(end) }))
};
let distance_end_zero = max_value - v.end;
if v.start > v.end {
@ -1172,8 +1232,8 @@ pub struct LayoutS<'a> {
impl<'a> LayoutS<'a> {
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
let size = scalar.value.size(cx);
let align = scalar.value.align(cx);
let size = scalar.size(cx);
let align = scalar.align(cx);
LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Primitive,
@ -1325,7 +1385,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
C: HasDataLayout,
{
match self.abi {
Abi::Scalar(scalar) => scalar.value.is_float(),
Abi::Scalar(scalar) => scalar.primitive().is_float(),
Abi::Aggregate { .. } => {
if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
self.field(cx, 0).is_single_fp_element(cx)
@ -1371,7 +1431,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
let scalar_allows_raw_init = move |s: Scalar| -> bool {
if zero {
// The range must contain 0.
s.valid_range.contains(0)
s.valid_range(cx).contains(0)
} else {
// The range must include all values.
s.is_always_valid(cx)

View file

@ -540,6 +540,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
);
self.note_version_mismatch(&mut err, &trait_ref);
self.suggest_remove_await(&obligation, &mut err);
self.suggest_derive(&obligation, &mut err, trait_predicate);
if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() {
self.suggest_await_before_try(

View file

@ -208,6 +208,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
flags.push((sym::_Self, Some("&[]".to_owned())));
}
if self_ty.is_fn() {
let fn_sig = self_ty.fn_sig(self.tcx);
let shortname = match fn_sig.unsafety() {
hir::Unsafety::Normal => "fn",
hir::Unsafety::Unsafe => "unsafe fn",
};
flags.push((sym::_Self, Some(shortname.to_owned())));
}
if let ty::Array(aty, len) = self_ty.kind() {
flags.push((sym::_Self, Some("[]".to_owned())));
flags.push((sym::_Self, Some(format!("[{}]", aty))));

View file

@ -189,6 +189,13 @@ pub trait InferCtxtExt<'tcx> {
err: &mut Diagnostic,
trait_ref: &ty::PolyTraitRef<'tcx>,
);
fn suggest_derive(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut Diagnostic,
trait_pred: ty::PolyTraitPredicate<'tcx>,
);
}
fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
@ -2651,6 +2658,68 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
_ => {}
}
}
fn suggest_derive(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut Diagnostic,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else {
return;
};
let (adt, substs) = match trait_pred.skip_binder().self_ty().kind() {
ty::Adt(adt, substs) if adt.did().is_local() => (adt, substs),
_ => return,
};
let can_derive = {
let is_derivable_trait = match diagnostic_name {
sym::Default => !adt.is_enum(),
sym::PartialEq | sym::PartialOrd => {
let rhs_ty = trait_pred.skip_binder().trait_ref.substs.type_at(1);
trait_pred.skip_binder().self_ty() == rhs_ty
}
sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true,
_ => false,
};
is_derivable_trait &&
// Ensure all fields impl the trait.
adt.all_fields().all(|field| {
let field_ty = field.ty(self.tcx, substs);
let trait_substs = match diagnostic_name {
sym::PartialEq | sym::PartialOrd => {
self.tcx.mk_substs_trait(field_ty, &[field_ty.into()])
}
_ => self.tcx.mk_substs_trait(field_ty, &[]),
};
let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate {
trait_ref: ty::TraitRef {
substs: trait_substs,
..trait_pred.skip_binder().trait_ref
},
..*tr
});
let field_obl = Obligation::new(
obligation.cause.clone(),
obligation.param_env,
trait_pred.to_predicate(self.tcx),
);
self.predicate_must_hold_modulo_regions(&field_obl)
})
};
if can_derive {
err.span_suggestion_verbose(
self.tcx.def_span(adt.did()).shrink_to_lo(),
&format!(
"consider annotating `{}` with `#[derive({})]`",
trait_pred.skip_binder().self_ty(),
diagnostic_name.to_string(),
),
format!("#[derive({})]\n", diagnostic_name.to_string()),
Applicability::MaybeIncorrect,
);
}
}
}
/// Collect all the returned expressions within the input expression.

View file

@ -40,6 +40,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
self.suggest_missing_parentheses(err, expr);
self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
self.report_closure_inferred_return_type(err, expected);
@ -630,7 +631,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MachineApplicable,
true,
));
}
}
_ => {}

View file

@ -2,8 +2,6 @@ use super::FnCtxt;
use crate::astconv::AstConv;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_span::{self, Span};
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind};
@ -13,12 +11,14 @@ use rustc_hir::{
WherePredicate,
};
use rustc_infer::infer::{self, TyCtxtInferExt};
use rustc_infer::traits;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Binder, Ty};
use rustc_span::symbol::{kw, sym};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Binder, ToPredicate, Ty};
use rustc_span::symbol::{kw, sym};
use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use std::iter;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@ -846,4 +846,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let node = self.tcx.hir().get(id);
matches!(node, Node::Stmt(Stmt { kind: StmtKind::Local(..), .. }))
}
/// Suggest that `&T` was cloned instead of `T` because `T` does not implement `Clone`,
/// which is a side-effect of autoref.
pub(crate) fn note_type_is_not_clone(
&self,
diag: &mut Diagnostic,
expected_ty: Ty<'tcx>,
found_ty: Ty<'tcx>,
expr: &hir::Expr<'_>,
) {
let hir::ExprKind::MethodCall(segment, &[ref callee_expr], _) = expr.kind else { return; };
let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; };
let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return };
let results = self.typeck_results.borrow();
// First, look for a `Clone::clone` call
if segment.ident.name == sym::clone
&& results.type_dependent_def_id(expr.hir_id).map_or(
false,
|did| {
self.tcx.associated_item(did).container
== ty::AssocItemContainer::TraitContainer(clone_trait_did)
},
)
// If that clone call hasn't already dereferenced the self type (i.e. don't give this
// diagnostic in cases where we have `(&&T).clone()` and we expect `T`).
&& !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
// Check that we're in fact trying to clone into the expected type
&& self.can_coerce(*pointee_ty, expected_ty)
// And the expected type doesn't implement `Clone`
&& !self.predicate_must_hold_considering_regions(&traits::Obligation {
cause: traits::ObligationCause::dummy(),
param_env: self.param_env,
recursion_depth: 0,
predicate: ty::Binder::dummy(ty::TraitRef {
def_id: clone_trait_did,
substs: self.tcx.mk_substs([expected_ty.into()].iter()),
})
.without_const()
.to_predicate(self.tcx),
})
{
diag.span_note(
callee_expr.span,
&format!(
"`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
),
);
}
}
}

View file

@ -991,6 +991,16 @@ extern "rust-intrinsic" {
/// let ptr_num_cast = ptr as *const i32 as usize;
/// ```
///
/// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined
/// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave
/// as expected -- this is touching on many unspecified aspects of the Rust memory model.
/// Depending on what the code is doing, the following alternatives are preferrable to
/// pointer-to-integer transmutation:
/// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a
/// type for that buffer, it can use [`MaybeUninit`][mem::MaybeUninit].
/// - If the code actually wants to work on the address the pointer points to, it can use `as`
/// casts or [`ptr.addr()`][pointer::addr].
///
/// Turning a `*mut T` into an `&mut T`:
///
/// ```

View file

@ -1,8 +1,7 @@
Panics the current thread.
This allows a program to terminate immediately and provide feedback
to the caller of the program. `panic!` should be used when a program reaches
an unrecoverable state.
to the caller of the program.
This macro is the perfect way to assert conditions in example code and in
tests. `panic!` is closely tied with the `unwrap` method of both
@ -21,13 +20,25 @@ Inside the hook a panic can be accessed as a `&dyn Any + Send`,
which contains either a `&str` or `String` for regular `panic!()` invocations.
To panic with a value of another other type, [`panic_any`] can be used.
[`Result`] enum is often a better solution for recovering from errors than
using the `panic!` macro. This macro should be used to avoid proceeding using
incorrect values, such as from external sources. Detailed information about
error handling is found in the [book].
See also the macro [`compile_error!`], for raising errors during compilation.
# When to use `panic!` vs `Result`
The Rust model of error handling groups errors into two major categories:
recoverable and unrecoverable errors. For a recoverable error, such as a file
not found error, its reasonable to report the problem to the user and retry
the operation. Unrecoverable errors are always symptoms of bugs, like trying to
access a location beyond the end of an array.
The Rust language and standard library provides `Result` and `panic!` as parts
of two complementary systems for representing, reporting, propagating, reacting
to, and discarding errors for in these two categories.
The `panic!` macro is provided to represent unrecoverable errors, whereas the
`Result` enum is provided to represent recoverable errors. For more detailed
information about error handling check out the [book] or the [`std::result`]
module docs.
[ounwrap]: Option::unwrap
[runwrap]: Result::unwrap
[`std::panic::set_hook()`]: ../std/panic/fn.set_hook.html
@ -36,6 +47,7 @@ See also the macro [`compile_error!`], for raising errors during compilation.
[`Any`]: crate::any::Any
[`format!`]: ../std/macro.format.html
[book]: ../book/ch09-00-error-handling.html
[`std::result`]: ../std/result/index.html
# Current implementation

View file

@ -60,6 +60,12 @@
Args = "()",
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
),
on(
_Self = "unsafe fn",
note = "unsafe function cannot be called generically without an unsafe block",
// SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
),
message = "expected a `{Fn}<{Args}>` closure, found `{Self}`",
label = "expected an `Fn<{Args}>` closure, found `{Self}`"
)]
@ -141,6 +147,12 @@ pub trait Fn<Args>: FnMut<Args> {
Args = "()",
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
),
on(
_Self = "unsafe fn",
note = "unsafe function cannot be called generically without an unsafe block",
// SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
),
message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`",
label = "expected an `FnMut<{Args}>` closure, found `{Self}`"
)]
@ -214,6 +226,12 @@ pub trait FnMut<Args>: FnOnce<Args> {
Args = "()",
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
),
on(
_Self = "unsafe fn",
note = "unsafe function cannot be called generically without an unsafe block",
// SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
),
message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`",
label = "expected an `FnOnce<{Args}>` closure, found `{Self}`"
)]

View file

@ -10,7 +10,7 @@ use crate::slice::from_raw_parts;
use crate::sys::net::Socket;
// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android")))]
#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android"), not(target_os = "netbsd")))]
#[allow(non_camel_case_types)]
mod libc {
pub use libc::c_int;
@ -177,13 +177,24 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
}
}
#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
#[derive(Clone)]
pub struct SocketCred(());
/// Unix credential.
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[cfg(any(target_os = "android", target_os = "linux",))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
#[derive(Clone)]
pub struct SocketCred(libc::ucred);
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[cfg(target_os = "netbsd")]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
#[derive(Clone)]
pub struct SocketCred(libc::sockcred);
#[doc(cfg(any(target_os = "android", target_os = "linux")))]
#[cfg(any(target_os = "android", target_os = "linux"))]
impl SocketCred {
/// Create a Unix credential struct.
///
@ -234,6 +245,61 @@ impl SocketCred {
}
}
#[cfg(target_os = "netbsd")]
impl SocketCred {
/// Create a Unix credential struct.
///
/// PID, UID and GID is set to 0.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn new() -> SocketCred {
SocketCred(libc::sockcred {
sc_pid: 0,
sc_uid: 0,
sc_euid: 0,
sc_gid: 0,
sc_egid: 0,
sc_ngroups: 0,
sc_groups: [0u32; 1],
})
}
/// Set the PID.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn set_pid(&mut self, pid: libc::pid_t) {
self.0.sc_pid = pid;
}
/// Get the current PID.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_pid(&self) -> libc::pid_t {
self.0.sc_pid
}
/// Set the UID.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn set_uid(&mut self, uid: libc::uid_t) {
self.0.sc_uid = uid;
}
/// Get the current UID.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_uid(&self) -> libc::uid_t {
self.0.sc_uid
}
/// Set the GID.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn set_gid(&mut self, gid: libc::gid_t) {
self.0.sc_gid = gid;
}
/// Get the current GID.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_gid(&self) -> libc::gid_t {
self.0.sc_gid
}
}
/// This control message contains file descriptors.
///
/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
@ -249,14 +315,22 @@ impl<'a> Iterator for ScmRights<'a> {
}
}
#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
/// This control message contains unix credentials.
///
/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[cfg(any(target_os = "android", target_os = "linux",))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[cfg(target_os = "netbsd")]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
impl<'a> Iterator for ScmCredentials<'a> {
type Item = SocketCred;
@ -278,7 +352,7 @@ pub enum AncillaryError {
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub enum AncillaryData<'a> {
ScmRights(ScmRights<'a>),
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
ScmCredentials(ScmCredentials<'a>),
}
@ -300,8 +374,8 @@ impl<'a> AncillaryData<'a> {
/// # Safety
///
/// `data` must contain a valid control message and the control message must be type of
/// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`.
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
/// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDS`.
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
unsafe fn as_credentials(data: &'a [u8]) -> Self {
let ancillary_data_iter = AncillaryDataIter::new(data);
let scm_credentials = ScmCredentials(ancillary_data_iter);
@ -320,6 +394,8 @@ impl<'a> AncillaryData<'a> {
libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
#[cfg(any(target_os = "android", target_os = "linux",))]
libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
#[cfg(target_os = "netbsd")]
libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
cmsg_type => {
Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
}
@ -531,7 +607,7 @@ impl<'a> SocketAncillary<'a> {
/// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
/// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
///
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
self.truncated = false;
@ -540,7 +616,10 @@ impl<'a> SocketAncillary<'a> {
&mut self.length,
creds,
libc::SOL_SOCKET,
#[cfg(not(target_os = "netbsd"))]
libc::SCM_CREDENTIALS,
#[cfg(target_os = "netbsd")]
libc::SCM_CREDS,
)
}

View file

@ -865,7 +865,7 @@ impl UnixDatagram {
/// Ok(())
/// }
/// ```
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
self.0.set_passcred(passcred)
@ -877,7 +877,7 @@ impl UnixDatagram {
/// Get the socket option `SO_PASSCRED`.
///
/// [`set_passcred`]: UnixDatagram::set_passcred
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn passcred(&self) -> io::Result<bool> {
self.0.passcred()

View file

@ -415,7 +415,7 @@ impl UnixStream {
/// Ok(())
/// }
/// ```
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
self.0.set_passcred(passcred)
@ -427,7 +427,7 @@ impl UnixStream {
/// Get the socket option `SO_PASSCRED`.
///
/// [`set_passcred`]: UnixStream::set_passcred
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn passcred(&self) -> io::Result<bool> {
self.0.passcred()

View file

@ -191,7 +191,7 @@ fn wait_timeout_wake() {
#[test]
#[should_panic]
#[cfg_attr(not(unix), ignore)]
#[cfg(all(unix, not(target_os = "linux"), not(target_os = "android")))]
fn two_mutexes() {
let m = Arc::new(Mutex::new(()));
let m2 = m.clone();

View file

@ -4,31 +4,46 @@
all(target_os = "emscripten", target_feature = "atomics")
))]
#[cfg(any(target_os = "linux", target_os = "android"))]
use crate::convert::TryInto;
#[cfg(any(target_os = "linux", target_os = "android"))]
use crate::ptr::null;
use crate::sync::atomic::AtomicI32;
use crate::time::Duration;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
let timespec = timeout.and_then(|d| {
Some(libc::timespec {
// Sleep forever if the timeout is longer than fits in a timespec.
tv_sec: d.as_secs().try_into().ok()?,
// This conversion never truncates, as subsec_nanos is always <1e9.
tv_nsec: d.subsec_nanos() as _,
})
});
unsafe {
libc::syscall(
libc::SYS_futex,
futex as *const AtomicI32,
libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG,
expected,
timespec.as_ref().map_or(null(), |d| d as *const libc::timespec),
);
pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) -> bool {
use super::time::Timespec;
use crate::ptr::null;
use crate::sync::atomic::Ordering::Relaxed;
// Calculate the timeout as an absolute timespec.
//
// Overflows are rounded up to an infinite timeout (None).
let timespec =
timeout.and_then(|d| Some(Timespec::now(libc::CLOCK_MONOTONIC).checked_add_duration(&d)?));
loop {
// No need to wait if the value already changed.
if futex.load(Relaxed) != expected {
return true;
}
// Use FUTEX_WAIT_BITSET rather than FUTEX_WAIT to be able to give an
// absolute time rather than a relative time.
let r = unsafe {
libc::syscall(
libc::SYS_futex,
futex as *const AtomicI32,
libc::FUTEX_WAIT_BITSET | libc::FUTEX_PRIVATE_FLAG,
expected,
timespec.as_ref().map_or(null(), |t| &t.t as *const libc::timespec),
null::<u32>(), // This argument is unused for FUTEX_WAIT_BITSET.
!0u32, // A full bitmask, to make it behave like a regular FUTEX_WAIT.
)
};
match (r < 0).then(super::os::errno) {
Some(libc::ETIMEDOUT) => return false,
Some(libc::EINTR) => continue,
_ => return true,
}
}
}
@ -65,6 +80,18 @@ pub fn futex_wake(futex: &AtomicI32) {
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn futex_wake_all(futex: &AtomicI32) {
unsafe {
libc::syscall(
libc::SYS_futex,
futex as *const AtomicI32,
libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG,
i32::MAX,
);
}
}
#[cfg(target_os = "emscripten")]
pub fn futex_wake(futex: &AtomicI32) {
extern "C" {

View file

@ -0,0 +1,164 @@
use crate::sync::atomic::{
AtomicI32,
Ordering::{Acquire, Relaxed, Release},
};
use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
use crate::time::Duration;
pub type MovableMutex = Mutex;
pub type MovableCondvar = Condvar;
pub struct Mutex {
/// 0: unlocked
/// 1: locked, no other threads waiting
/// 2: locked, and other threads waiting (contended)
futex: AtomicI32,
}
impl Mutex {
#[inline]
pub const fn new() -> Self {
Self { futex: AtomicI32::new(0) }
}
#[inline]
pub unsafe fn init(&mut self) {}
#[inline]
pub unsafe fn destroy(&self) {}
#[inline]
pub unsafe fn try_lock(&self) -> bool {
self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok()
}
#[inline]
pub unsafe fn lock(&self) {
if self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_err() {
self.lock_contended();
}
}
#[cold]
fn lock_contended(&self) {
// Spin first to speed things up if the lock is released quickly.
let mut state = self.spin();
// If it's unlocked now, attempt to take the lock
// without marking it as contended.
if state == 0 {
match self.futex.compare_exchange(0, 1, Acquire, Relaxed) {
Ok(_) => return, // Locked!
Err(s) => state = s,
}
}
loop {
// Put the lock in contended state.
// We avoid an unnecessary write if it as already set to 2,
// to be friendlier for the caches.
if state != 2 && self.futex.swap(2, Acquire) == 0 {
// We changed it from 0 to 2, so we just succesfully locked it.
return;
}
// Wait for the futex to change state, assuming it is still 2.
futex_wait(&self.futex, 2, None);
// Spin again after waking up.
state = self.spin();
}
}
fn spin(&self) -> i32 {
let mut spin = 100;
loop {
// We only use `load` (and not `swap` or `compare_exchange`)
// while spinning, to be easier on the caches.
let state = self.futex.load(Relaxed);
// We stop spinning when the mutex is unlocked (0),
// but also when it's contended (2).
if state != 1 || spin == 0 {
return state;
}
crate::hint::spin_loop();
spin -= 1;
}
}
#[inline]
pub unsafe fn unlock(&self) {
if self.futex.swap(0, Release) == 2 {
// We only wake up one thread. When that thread locks the mutex, it
// will mark the mutex as contended (2) (see lock_contended above),
// which makes sure that any other waiting threads will also be
// woken up eventually.
self.wake();
}
}
#[cold]
fn wake(&self) {
futex_wake(&self.futex);
}
}
pub struct Condvar {
// The value of this atomic is simply incremented on every notification.
// This is used by `.wait()` to not miss any notifications after
// unlocking the mutex and before waiting for notifications.
futex: AtomicI32,
}
impl Condvar {
#[inline]
pub const fn new() -> Self {
Self { futex: AtomicI32::new(0) }
}
#[inline]
pub unsafe fn init(&mut self) {}
#[inline]
pub unsafe fn destroy(&self) {}
// All the memory orderings here are `Relaxed`,
// because synchronization is done by unlocking and locking the mutex.
pub unsafe fn notify_one(&self) {
self.futex.fetch_add(1, Relaxed);
futex_wake(&self.futex);
}
pub unsafe fn notify_all(&self) {
self.futex.fetch_add(1, Relaxed);
futex_wake_all(&self.futex);
}
pub unsafe fn wait(&self, mutex: &Mutex) {
self.wait_optional_timeout(mutex, None);
}
pub unsafe fn wait_timeout(&self, mutex: &Mutex, timeout: Duration) -> bool {
self.wait_optional_timeout(mutex, Some(timeout))
}
unsafe fn wait_optional_timeout(&self, mutex: &Mutex, timeout: Option<Duration>) -> bool {
// Examine the notification counter _before_ we unlock the mutex.
let futex_value = self.futex.load(Relaxed);
// Unlock the mutex before going to sleep.
mutex.unlock();
// Wait, but only if there hasn't been any
// notification since we unlocked the mutex.
let r = futex_wait(&self.futex, futex_value, timeout);
// Lock the mutex again.
mutex.lock();
r
}
}

View file

@ -1,8 +1,24 @@
mod pthread_condvar;
mod pthread_mutex;
mod pthread_remutex;
mod pthread_rwlock;
pub use pthread_condvar::{Condvar, MovableCondvar};
pub use pthread_mutex::{MovableMutex, Mutex};
pub use pthread_remutex::ReentrantMutex;
pub use pthread_rwlock::{MovableRWLock, RWLock};
cfg_if::cfg_if! {
if #[cfg(any(
target_os = "linux",
target_os = "android",
))] {
mod futex;
#[allow(dead_code)]
mod pthread_mutex; // Only used for PthreadMutexAttr, needed by pthread_remutex.
mod pthread_remutex; // FIXME: Implement this using a futex
mod pthread_rwlock; // FIXME: Implement this using a futex
pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
pub use pthread_remutex::ReentrantMutex;
pub use pthread_rwlock::{RWLock, MovableRWLock};
} else {
mod pthread_mutex;
mod pthread_remutex;
mod pthread_rwlock;
mod pthread_condvar;
pub use pthread_mutex::{Mutex, MovableMutex};
pub use pthread_remutex::ReentrantMutex;
pub use pthread_rwlock::{RWLock, MovableRWLock};
pub use pthread_condvar::{Condvar, MovableCondvar};
}
}

View file

@ -419,6 +419,17 @@ impl Socket {
Ok(passcred != 0)
}
#[cfg(target_os = "netbsd")]
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
setsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS, passcred as libc::c_int)
}
#[cfg(target_os = "netbsd")]
pub fn passcred(&self) -> io::Result<bool> {
let passcred: libc::c_int = getsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS)?;
Ok(passcred != 0)
}
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut nonblocking = nonblocking as libc::c_int;

View file

@ -9,8 +9,8 @@ use crate::convert::TryInto;
const NSEC_PER_SEC: u64 = 1_000_000_000;
#[derive(Copy, Clone)]
struct Timespec {
t: libc::timespec,
pub(in crate::sys::unix) struct Timespec {
pub t: libc::timespec,
}
impl Timespec {
@ -18,7 +18,7 @@ impl Timespec {
Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }
}
fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
if self >= other {
// NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
// to optimize it into a branchless form (see also #75545):
@ -51,7 +51,7 @@ impl Timespec {
}
}
fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = other
.as_secs()
.try_into() // <- target type would be `libc::time_t`
@ -68,7 +68,7 @@ impl Timespec {
Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
}
fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = other
.as_secs()
.try_into() // <- target type would be `libc::time_t`
@ -266,6 +266,7 @@ mod inner {
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
use crate::fmt;
use crate::mem::MaybeUninit;
use crate::sys::cvt;
use crate::time::Duration;
@ -285,7 +286,7 @@ mod inner {
impl Instant {
pub fn now() -> Instant {
Instant { t: now(libc::CLOCK_MONOTONIC) }
Instant { t: Timespec::now(libc::CLOCK_MONOTONIC) }
}
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
@ -312,7 +313,7 @@ mod inner {
impl SystemTime {
pub fn now() -> SystemTime {
SystemTime { t: now(libc::CLOCK_REALTIME) }
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
@ -348,9 +349,11 @@ mod inner {
#[cfg(any(target_os = "dragonfly", target_os = "espidf"))]
pub type clock_t = libc::c_ulong;
fn now(clock: clock_t) -> Timespec {
let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } };
cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap();
t
impl Timespec {
pub fn now(clock: clock_t) -> Timespec {
let mut t = MaybeUninit::uninit();
cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap();
Timespec { t: unsafe { t.assume_init() } }
}
}
}

View file

@ -1769,7 +1769,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
let tag_size = if let TagEncoding::Niche { .. } = tag_encoding {
0
} else if let Primitive::Int(i, _) = tag.value {
} else if let Primitive::Int(i, _) = tag.primitive() {
i.size().bytes()
} else {
span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int")

View file

@ -3,56 +3,70 @@
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:15:11: 15:11
let _1: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
let mut _3: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:28:25: 28:46
let mut _5: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:35:35: 35:56
let _1: char; // in scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
let mut _2: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:21:34: 21:63
let mut _4: E; // in scope 0 at $DIR/invalid_constant.rs:28:25: 28:59
let mut _5: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:28:34: 28:55
let mut _7: Empty; // in scope 0 at $DIR/invalid_constant.rs:35:35: 35:73
let mut _8: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:35:44: 35:65
scope 1 {
debug _invalid_char => _1; // in scope 1 at $DIR/invalid_constant.rs:21:9: 21:22
let _2: [main::InvalidTag; 1]; // in scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
scope 2 {
debug _invalid_tag => _2; // in scope 2 at $DIR/invalid_constant.rs:28:9: 28:21
let _4: [main::NoVariants; 1]; // in scope 2 at $DIR/invalid_constant.rs:35:9: 35:31
scope 3 {
debug _enum_without_variants => _4; // in scope 3 at $DIR/invalid_constant.rs:35:9: 35:31
let _6: main::Str<"<22><><EFBFBD>">; // in scope 3 at $DIR/invalid_constant.rs:39:9: 39:22
scope 4 {
debug _non_utf8_str => _6; // in scope 4 at $DIR/invalid_constant.rs:39:9: 39:22
let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
scope 3 {
debug _invalid_tag => _3; // in scope 3 at $DIR/invalid_constant.rs:28:9: 28:21
let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:35:9: 35:31
scope 5 {
debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:35:9: 35:31
let _9: main::Str<"<22><><EFBFBD>">; // in scope 5 at $DIR/invalid_constant.rs:39:9: 39:22
scope 7 {
debug _non_utf8_str => _9; // in scope 7 at $DIR/invalid_constant.rs:39:9: 39:22
}
}
scope 6 {
}
}
scope 4 {
}
}
scope 2 {
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
- _1 = const { InvalidChar { int: 0x110001 } }; // scope 0 at $DIR/invalid_constant.rs:21:25: 21:64
+ _1 = const InvalidChar { int: 1114113_u32, chr: {transmute(0x00110001): char} }; // scope 0 at $DIR/invalid_constant.rs:21:25: 21:64
// mir::Constant
// + span: $DIR/invalid_constant.rs:21:25: 21:64
- // + literal: Const { ty: InvalidChar, val: Unevaluated(main::{constant#0}, [main::InvalidChar], None) }
+ // + literal: Const { ty: InvalidChar, val: Value(Scalar(0x00110001)) }
StorageLive(_2); // scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:28:25: 28:46
(_3.0: u32) = const 4_u32; // scope 1 at $DIR/invalid_constant.rs:28:25: 28:46
- _2 = [move _3]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:47
+ _2 = [const InvalidTag { int: 4_u32, e: Scalar(0x00000004): E }]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:47
StorageLive(_2); // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63
(_2.0: u32) = const 1114113_u32; // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63
- _1 = (_2.1: char); // scope 2 at $DIR/invalid_constant.rs:21:34: 21:67
+ _1 = const {transmute(0x00110001): char}; // scope 2 at $DIR/invalid_constant.rs:21:34: 21:67
StorageDead(_2); // scope 0 at $DIR/invalid_constant.rs:21:69: 21:70
StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
StorageLive(_4); // scope 1 at $DIR/invalid_constant.rs:28:25: 28:59
StorageLive(_5); // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55
(_5.0: u32) = const 4_u32; // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55
- _4 = (_5.1: E); // scope 4 at $DIR/invalid_constant.rs:28:34: 28:57
- _3 = [move _4]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:60
+ _4 = const Scalar(0x00000004): E; // scope 4 at $DIR/invalid_constant.rs:28:34: 28:57
+ // mir::Constant
+ // + span: $DIR/invalid_constant.rs:28:24: 28:47
+ // + literal: Const { ty: InvalidTag, val: Value(Scalar(0x00000004)) }
StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:28:46: 28:47
StorageLive(_4); // scope 2 at $DIR/invalid_constant.rs:35:9: 35:31
StorageLive(_5); // scope 2 at $DIR/invalid_constant.rs:35:35: 35:56
(_5.0: u32) = const 0_u32; // scope 2 at $DIR/invalid_constant.rs:35:35: 35:56
- _4 = [move _5]; // scope 2 at $DIR/invalid_constant.rs:35:34: 35:57
+ _4 = [const NoVariants { int: 0_u32, empty: Scalar(<ZST>): Empty }]; // scope 2 at $DIR/invalid_constant.rs:35:34: 35:57
+ // + span: $DIR/invalid_constant.rs:28:34: 28:57
+ // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
+ _3 = [const Scalar(0x00000004): E]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:60
+ // mir::Constant
+ // + span: $DIR/invalid_constant.rs:35:34: 35:57
+ // + literal: Const { ty: NoVariants, val: Value(Scalar(0x00000000)) }
StorageDead(_5); // scope 2 at $DIR/invalid_constant.rs:35:56: 35:57
StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:39:9: 39:22
+ // + span: $DIR/invalid_constant.rs:28:24: 28:60
+ // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:28:59: 28:60
StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:28:60: 28:61
StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:35:9: 35:31
StorageLive(_7); // scope 3 at $DIR/invalid_constant.rs:35:35: 35:73
StorageLive(_8); // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65
(_8.0: u32) = const 0_u32; // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65
nop; // scope 6 at $DIR/invalid_constant.rs:35:44: 35:71
nop; // scope 3 at $DIR/invalid_constant.rs:35:34: 35:74
StorageDead(_7); // scope 3 at $DIR/invalid_constant.rs:35:73: 35:74
StorageDead(_8); // scope 3 at $DIR/invalid_constant.rs:35:74: 35:75
StorageLive(_9); // scope 5 at $DIR/invalid_constant.rs:39:9: 39:22
nop; // scope 0 at $DIR/invalid_constant.rs:15:11: 42:2
StorageDead(_9); // scope 5 at $DIR/invalid_constant.rs:42:1: 42:2
StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:42:1: 42:2
StorageDead(_4); // scope 2 at $DIR/invalid_constant.rs:42:1: 42:2
StorageDead(_2); // scope 1 at $DIR/invalid_constant.rs:42:1: 42:2
StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:42:1: 42:2
StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:42:1: 42:2
return; // scope 0 at $DIR/invalid_constant.rs:42:2: 42:2
}

View file

@ -18,21 +18,21 @@ fn main() {
int: u32,
chr: char,
}
let _invalid_char = const { InvalidChar { int: 0x110001 } };
let _invalid_char = unsafe { InvalidChar { int: 0x110001 }.chr };
// An enum with an invalid tag. Regression test for #93688.
union InvalidTag {
int: u32,
e: E,
}
let _invalid_tag = [InvalidTag { int: 4 }];
let _invalid_tag = [unsafe { InvalidTag { int: 4 }.e }];
// An enum without variants. Regression test for #94073.
union NoVariants {
int: u32,
empty: Empty,
}
let _enum_without_variants = [NoVariants { int: 0 }];
let _enum_without_variants = [unsafe { NoVariants { int: 0 }.empty }];
// A non-UTF-8 string slice. Regression test for #75763 and #78520.
struct Str<const S: &'static str>;

View file

@ -0,0 +1,8 @@
// Doc link path with empty prefix that resolves to "extern prelude" instead of a module.
// check-pass
// edition:2018
/// [::Unresolved]
//~^ WARN unresolved link to `::Unresolved`
pub struct Item;

View file

@ -0,0 +1,10 @@
warning: unresolved link to `::Unresolved`
--> $DIR/global-path.rs:6:6
|
LL | /// [::Unresolved]
| ^^^^^^^^^^^^ no item named `` in scope
|
= note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
warning: 1 warning emitted

View file

@ -5,6 +5,10 @@ LL | let headers = [Header{value: &[]}; 128];
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
|
= note: the `Copy` trait is required because the repeated element will be copied
help: consider annotating `Header<'_>` with `#[derive(Copy)]`
|
LL | #[derive(Copy)]
|
error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied
--> $DIR/repeat_empty_ok.rs:13:19
@ -13,6 +17,10 @@ LL | let headers = [Header{value: &[0]}; 128];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
|
= note: the `Copy` trait is required because the repeated element will be copied
help: consider annotating `Header<'_>` with `#[derive(Copy)]`
|
LL | #[derive(Copy)]
|
error: aborting due to 2 previous errors

View file

@ -9,6 +9,10 @@ note: required by a bound in `Tr::Ty`
|
LL | type Ty: Clone = NotClone;
| ^^^^^ required by this bound in `Tr::Ty`
help: consider annotating `NotClone` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
|
error[E0277]: the trait bound `NotClone: Clone` is not satisfied
--> $DIR/defaults-suitability.rs:22:15
@ -24,6 +28,10 @@ LL | Self::Ty: Clone,
LL | {
LL | type Ty = NotClone;
| -- required by a bound in this
help: consider annotating `NotClone` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
|
error[E0277]: the trait bound `T: Clone` is not satisfied
--> $DIR/defaults-suitability.rs:28:23

View file

@ -8,7 +8,7 @@ note: required by a bound in `Add`
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | pub trait Add<Rhs = Self> {
| ^^^ required by this bound in `Add`
| ^^^^^^^^^^ required by this bound in `Add`
help: consider further restricting `Self`
|
LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + Sized {}

View file

@ -5,10 +5,10 @@ LL | impl<const H: feature> Foo {
| ^^^^^^^ not a type
error[E0207]: the const parameter `H` is not constrained by the impl trait, self type, or predicates
--> $DIR/issue-78654.rs:9:12
--> $DIR/issue-78654.rs:9:6
|
LL | impl<const H: feature> Foo {
| ^ unconstrained const parameter
| ^^^^^^^^^^^^^^^^ unconstrained const parameter
|
= note: expressions using a const parameter must map each value to a distinct output value
= note: proving the result of expressions other than the parameter are unique is not supported

View file

@ -5,10 +5,10 @@ LL | impl<const H: feature> Foo {
| ^^^^^^^ not a type
error[E0207]: the const parameter `H` is not constrained by the impl trait, self type, or predicates
--> $DIR/issue-78654.rs:9:12
--> $DIR/issue-78654.rs:9:6
|
LL | impl<const H: feature> Foo {
| ^ unconstrained const parameter
| ^^^^^^^^^^^^^^^^ unconstrained const parameter
|
= note: expressions using a const parameter must map each value to a distinct output value
= note: proving the result of expressions other than the parameter are unique is not supported

View file

@ -2,11 +2,12 @@ error[E0277]: expected a `FnOnce<(&str,)>` closure, found `unsafe extern "rust-i
--> $DIR/coerce-unsafe-to-closure.rs:2:44
|
LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
| --- ^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(&str,)>` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
| --- ^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
| |
| required by a bound introduced by this call
|
= help: the trait `FnOnce<(&str,)>` is not implemented for `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `Option::<T>::map`
--> $SRC_DIR/core/src/option.rs:LL:COL
|

View file

@ -1,8 +1,8 @@
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
--> $DIR/default-on-impl.rs:3:12
--> $DIR/default-on-impl.rs:3:6
|
LL | impl<const N: usize = 1> Foo<N> {}
| ^
| ^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View file

@ -10,7 +10,7 @@ note: function defined here, with 2 generic parameters: `T`, `P`
--> $DIR/issue-76595.rs:10:4
|
LL | fn test<T, const P: usize>() where Bool<{core::mem::size_of::<T>() > 4}>: True {
| ^^^^ - -
| ^^^^ - --------------
help: add missing generic argument
|
LL | test::<2, P>();

View file

@ -10,7 +10,7 @@ note: function defined here, with 2 generic parameters: `X`, `Y`
--> $DIR/incorrect-number-of-const-args.rs:1:4
|
LL | fn foo<const X: usize, const Y: usize>() -> usize {
| ^^^ - -
| ^^^ -------------- --------------
help: add missing generic argument
|
LL | foo::<0, Y>();
@ -28,7 +28,7 @@ note: function defined here, with 2 generic parameters: `X`, `Y`
--> $DIR/incorrect-number-of-const-args.rs:1:4
|
LL | fn foo<const X: usize, const Y: usize>() -> usize {
| ^^^ - -
| ^^^ -------------- --------------
error: aborting due to 2 previous errors

View file

@ -1,17 +1,17 @@
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
--> $DIR/issue-68366.rs:11:13
--> $DIR/issue-68366.rs:11:7
|
LL | impl <const N: usize> Collatz<{Some(N)}> {}
| ^ unconstrained const parameter
| ^^^^^^^^^^^^^^ unconstrained const parameter
|
= note: expressions using a const parameter must map each value to a distinct output value
= note: proving the result of expressions other than the parameter are unique is not supported
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
--> $DIR/issue-68366.rs:17:12
--> $DIR/issue-68366.rs:17:6
|
LL | impl<const N: usize> Foo {}
| ^ unconstrained const parameter
| ^^^^^^^^^^^^^^ unconstrained const parameter
|
= note: expressions using a const parameter must map each value to a distinct output value
= note: proving the result of expressions other than the parameter are unique is not supported

View file

@ -8,19 +8,19 @@ LL | impl <const N: usize> Collatz<{Some(N)}> {}
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
--> $DIR/issue-68366.rs:11:13
--> $DIR/issue-68366.rs:11:7
|
LL | impl <const N: usize> Collatz<{Some(N)}> {}
| ^ unconstrained const parameter
| ^^^^^^^^^^^^^^ unconstrained const parameter
|
= note: expressions using a const parameter must map each value to a distinct output value
= note: proving the result of expressions other than the parameter are unique is not supported
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
--> $DIR/issue-68366.rs:17:12
--> $DIR/issue-68366.rs:17:6
|
LL | impl<const N: usize> Foo {}
| ^ unconstrained const parameter
| ^^^^^^^^^^^^^^ unconstrained const parameter
|
= note: expressions using a const parameter must map each value to a distinct output value
= note: proving the result of expressions other than the parameter are unique is not supported

View file

@ -1,14 +1,14 @@
error[E0053]: method `bit` has an incompatible const parameter type for trait
--> $DIR/issue-86820.rs:17:18
--> $DIR/issue-86820.rs:17:12
|
LL | fn bit<const I : usize>(self) -> bool {
| ^
| ^^^^^^^^^^^^^^^
|
note: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
--> $DIR/issue-86820.rs:12:18
--> $DIR/issue-86820.rs:12:12
|
LL | fn bit<const I : u8>(self) -> bool;
| ^
| ^^^^^^^^^^^^
error: aborting due to previous error

View file

@ -1,8 +1,8 @@
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
--> $DIR/default_function_param.rs:3:14
--> $DIR/default_function_param.rs:3:8
|
LL | fn foo<const SIZE: usize = 5usize>() {}
| ^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View file

@ -17,7 +17,7 @@ note: trait defined here, with 1 generic parameter: `N`
--> $DIR/issue-89013-no-kw.rs:1:7
|
LL | trait Foo<const N: usize> {
| ^^^ -
| ^^^ --------------
help: add missing generic argument
|
LL | impl Foo<N, N = 3> for Bar {

View file

@ -29,7 +29,7 @@ note: trait defined here, with 1 generic parameter: `N`
--> $DIR/issue-89013.rs:1:7
|
LL | trait Foo<const N: usize> {
| ^^^ -
| ^^^ --------------
help: add missing generic argument
|
LL | impl Foo<N, N = const 3> for Bar {

View file

@ -0,0 +1,34 @@
// run-pass
#![feature(const_ptr_write)]
#![feature(const_mut_refs)]
// Or, equivalently: `MaybeUninit`.
pub union BagOfBits<T: Copy> {
uninit: (),
_storage: T,
}
pub const fn make_1u8_bag<T: Copy>() -> BagOfBits<T> {
assert!(core::mem::size_of::<T>() >= 1);
let mut bag = BagOfBits { uninit: () };
unsafe { (&mut bag as *mut _ as *mut u8).write(1); };
bag
}
pub fn check_bag<T: Copy>(bag: &BagOfBits<T>) {
let val = unsafe { (bag as *const _ as *const u8).read() };
assert_eq!(val, 1);
}
fn main() {
check_bag(&make_1u8_bag::<[usize; 1]>()); // Fine
check_bag(&make_1u8_bag::<usize>()); // Fine
const CONST_ARRAY_BAG: BagOfBits<[usize; 1]> = make_1u8_bag();
check_bag(&CONST_ARRAY_BAG); // Fine.
const CONST_USIZE_BAG: BagOfBits<usize> = make_1u8_bag();
// Used to panic since CTFE would make the entire `BagOfBits<usize>` uninit
check_bag(&CONST_USIZE_BAG);
}

View file

@ -0,0 +1,16 @@
// check-pass
#![feature(const_swap)]
#![feature(const_mut_refs)]
#[repr(C)]
struct Demo(u64, bool, u64, u32, u64, u64, u64);
const C: (Demo, Demo) = {
let mut x = Demo(1, true, 3, 4, 5, 6, 7);
let mut y = Demo(10, false, 12, 13, 14, 15, 16);
std::mem::swap(&mut x, &mut y);
(x, y)
};
fn main() {}

View file

@ -8,6 +8,10 @@ LL | x: Error
| ^^^^^^^^ the trait `Clone` is not implemented for `Error`
|
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | Error
| ^^^^^ the trait `Clone` is not implemented for `Error`
|
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | x: Error
| ^^^^^^^^ the trait `Clone` is not implemented for `Error`
|
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | Error
| ^^^^^ the trait `Clone` is not implemented for `Error`
|
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
|
error: aborting due to previous error

View file

@ -10,6 +10,10 @@ LL | x: Error
= help: the trait `Debug` is not implemented for `Error`
= note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Debug)]`
|
LL | #[derive(Debug)]
|
error: aborting due to previous error

View file

@ -10,6 +10,10 @@ LL | Error
= help: the trait `Debug` is not implemented for `Error`
= note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Debug)]`
|
LL | #[derive(Debug)]
|
error: aborting due to previous error

View file

@ -10,6 +10,10 @@ LL | x: Error
= help: the trait `Debug` is not implemented for `Error`
= note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Debug)]`
|
LL | #[derive(Debug)]
|
error: aborting due to previous error

View file

@ -10,6 +10,10 @@ LL | Error
= help: the trait `Debug` is not implemented for `Error`
= note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Debug)]`
|
LL | #[derive(Debug)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | x: Error
| ^^^^^^^^ the trait `Default` is not implemented for `Error`
|
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Default)]`
|
LL | #[derive(Default)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | Error
| ^^^^^ the trait `Default` is not implemented for `Error`
|
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Default)]`
|
LL | #[derive(Default)]
|
error: aborting due to previous error

View file

@ -13,6 +13,10 @@ note: required by a bound in `AssertParamIsEq`
LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
| ^^ required by this bound in `AssertParamIsEq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Eq)]`
|
LL | #[derive(Eq)]
|
error: aborting due to previous error

View file

@ -13,6 +13,10 @@ note: required by a bound in `AssertParamIsEq`
LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
| ^^ required by this bound in `AssertParamIsEq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Eq)]`
|
LL | #[derive(Eq)]
|
error: aborting due to previous error

View file

@ -13,6 +13,10 @@ note: required by a bound in `AssertParamIsEq`
LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
| ^^ required by this bound in `AssertParamIsEq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Eq)]`
|
LL | #[derive(Eq)]
|
error: aborting due to previous error

View file

@ -13,6 +13,10 @@ note: required by a bound in `AssertParamIsEq`
LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
| ^^ required by this bound in `AssertParamIsEq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Eq)]`
|
LL | #[derive(Eq)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | x: Error
| ^^^^^^^^ the trait `Hash` is not implemented for `Error`
|
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Hash)]`
|
LL | #[derive(Hash)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | Error
| ^^^^^ the trait `Hash` is not implemented for `Error`
|
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Hash)]`
|
LL | #[derive(Hash)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | x: Error
| ^^^^^^^^ the trait `Hash` is not implemented for `Error`
|
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Hash)]`
|
LL | #[derive(Hash)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | Error
| ^^^^^ the trait `Hash` is not implemented for `Error`
|
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Hash)]`
|
LL | #[derive(Hash)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | x: Error
| ^^^^^^^^ the trait `Ord` is not implemented for `Error`
|
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Ord)]`
|
LL | #[derive(Ord)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | Error
| ^^^^^ the trait `Ord` is not implemented for `Error`
|
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Ord)]`
|
LL | #[derive(Ord)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | x: Error
| ^^^^^^^^ the trait `Ord` is not implemented for `Error`
|
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Ord)]`
|
LL | #[derive(Ord)]
|
error: aborting due to previous error

View file

@ -8,6 +8,10 @@ LL | Error
| ^^^^^ the trait `Ord` is not implemented for `Error`
|
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Ord)]`
|
LL | #[derive(Ord)]
|
error: aborting due to previous error

Some files were not shown because too many files have changed in this diff Show more