Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
c62d2106da
274 changed files with 2125 additions and 896 deletions
|
|
@ -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(¶m.attrs, sym::may_dangle),
|
||||
bounds: self.arena.alloc_from_iter(bounds),
|
||||
kind,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {:?}",
|
||||
|
|
|
|||
|
|
@ -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)?)?;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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![]);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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{:#?}",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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))));
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`:
|
||||
///
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -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, it’s 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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}`"
|
||||
)]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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" {
|
||||
|
|
|
|||
164
library/std/src/sys/unix/locks/futex.rs
Normal file
164
library/std/src/sys/unix/locks/futex.rs
Normal 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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() } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
8
src/test/rustdoc-ui/intra-doc/global-path.rs
Normal file
8
src/test/rustdoc-ui/intra-doc/global-path.rs
Normal 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;
|
||||
10
src/test/rustdoc-ui/intra-doc/global-path.stderr
Normal file
10
src/test/rustdoc-ui/intra-doc/global-path.stderr
Normal 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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
34
src/test/ui/consts/issue-69488.rs
Normal file
34
src/test/ui/consts/issue-69488.rs
Normal 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);
|
||||
}
|
||||
16
src/test/ui/consts/issue-94371.rs
Normal file
16
src/test/ui/consts/issue-94371.rs
Normal 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() {}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue