mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 14:23:45 +00:00
Auto merge of #131690 - matthiaskrgr:rollup-mcau4ol, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #129424 (Stabilize `Pin::as_deref_mut()`) - #131332 (Fix clobber_abi and disallow SVE-related registers in Arm64EC inline assembly) - #131384 (Update precondition tests (especially for zero-size access to null)) - #131430 (Special treatment empty tuple when suggest adding a string literal in format macro.) - #131550 (Make some tweaks to extern block diagnostics) - #131667 (Fix AArch64InlineAsmReg::emit) - #131679 (compiletest: Document various parts of compiletest's `lib.rs`) - #131682 (Tag PRs affecting compiletest with `A-compiletest`) Failed merges: - #131496 (Stabilise `const_make_ascii`.) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
9322d183f4
@ -62,12 +62,12 @@ ast_passes_equality_in_where = equality constraints are not yet supported in `wh
|
||||
|
||||
ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
|
||||
|
||||
ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers
|
||||
ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have `{$kw}` qualifier
|
||||
.label = in this `extern` block
|
||||
.suggestion = remove this qualifier
|
||||
.suggestion = remove the `{$kw}` qualifier
|
||||
|
||||
ast_passes_extern_invalid_safety = items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
.suggestion = add unsafe to this `extern` block
|
||||
ast_passes_extern_invalid_safety = items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
.suggestion = add `unsafe` to this `extern` block
|
||||
|
||||
ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
|
||||
.label = in this `extern` block
|
||||
|
@ -524,21 +524,24 @@ impl<'a> AstValidator<'a> {
|
||||
// Deconstruct to ensure exhaustiveness
|
||||
FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader,
|
||||
) {
|
||||
let report_err = |span| {
|
||||
self.dcx()
|
||||
.emit_err(errors::FnQualifierInExtern { span, block: self.current_extern_span() });
|
||||
let report_err = |span, kw| {
|
||||
self.dcx().emit_err(errors::FnQualifierInExtern {
|
||||
span,
|
||||
kw,
|
||||
block: self.current_extern_span(),
|
||||
});
|
||||
};
|
||||
match coroutine_kind {
|
||||
Some(knd) => report_err(knd.span()),
|
||||
Some(kind) => report_err(kind.span(), kind.as_str()),
|
||||
None => (),
|
||||
}
|
||||
match constness {
|
||||
Const::Yes(span) => report_err(span),
|
||||
Const::Yes(span) => report_err(span, "const"),
|
||||
Const::No => (),
|
||||
}
|
||||
match ext {
|
||||
Extern::None => (),
|
||||
Extern::Implicit(span) | Extern::Explicit(_, span) => report_err(span),
|
||||
Extern::Implicit(span) | Extern::Explicit(_, span) => report_err(span, "extern"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,6 +295,7 @@ pub(crate) struct FnQualifierInExtern {
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub block: Span,
|
||||
pub kw: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -195,12 +195,26 @@ fn make_format_args(
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
let sugg_fmt = match args.explicit_args().len() {
|
||||
0 => "{}".to_string(),
|
||||
count => {
|
||||
format!("{}{{}}", "{} ".repeat(count))
|
||||
// `{}` or `()`
|
||||
let should_suggest = |kind: &ExprKind| -> bool {
|
||||
match kind {
|
||||
ExprKind::Block(b, None) if b.stmts.is_empty() => true,
|
||||
ExprKind::Tup(v) if v.is_empty() => true,
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
|
||||
let mut sugg_fmt = String::new();
|
||||
for kind in std::iter::once(&efmt.kind)
|
||||
.chain(args.explicit_args().into_iter().map(|a| &a.expr.kind))
|
||||
{
|
||||
sugg_fmt.push_str(if should_suggest(kind) {
|
||||
"{:?} "
|
||||
} else {
|
||||
"{} "
|
||||
});
|
||||
}
|
||||
sugg_fmt = sugg_fmt.trim_end().to_string();
|
||||
err.span_suggestion(
|
||||
unexpanded_fmt_span.shrink_to_lo(),
|
||||
"you might be missing a string literal to format with",
|
||||
|
@ -542,57 +542,16 @@ fn xmm_reg_index(reg: InlineAsmReg) -> Option<u32> {
|
||||
|
||||
/// If the register is an AArch64 integer register then return its index.
|
||||
fn a64_reg_index(reg: InlineAsmReg) -> Option<u32> {
|
||||
use AArch64InlineAsmReg::*;
|
||||
// Unlike `a64_vreg_index`, we can't subtract `x0` to get the u32 because
|
||||
// `x19` and `x29` are missing and the integer constants for the
|
||||
// `x0`..`x30` enum variants don't all match the register number. E.g. the
|
||||
// integer constant for `x18` is 18, but the constant for `x20` is 19.
|
||||
Some(match reg {
|
||||
InlineAsmReg::AArch64(r) => match r {
|
||||
x0 => 0,
|
||||
x1 => 1,
|
||||
x2 => 2,
|
||||
x3 => 3,
|
||||
x4 => 4,
|
||||
x5 => 5,
|
||||
x6 => 6,
|
||||
x7 => 7,
|
||||
x8 => 8,
|
||||
x9 => 9,
|
||||
x10 => 10,
|
||||
x11 => 11,
|
||||
x12 => 12,
|
||||
x13 => 13,
|
||||
x14 => 14,
|
||||
x15 => 15,
|
||||
x16 => 16,
|
||||
x17 => 17,
|
||||
x18 => 18,
|
||||
// x19 is reserved
|
||||
x20 => 20,
|
||||
x21 => 21,
|
||||
x22 => 22,
|
||||
x23 => 23,
|
||||
x24 => 24,
|
||||
x25 => 25,
|
||||
x26 => 26,
|
||||
x27 => 27,
|
||||
x28 => 28,
|
||||
// x29 is reserved
|
||||
x30 => 30,
|
||||
_ => return None,
|
||||
},
|
||||
_ => return None,
|
||||
})
|
||||
match reg {
|
||||
InlineAsmReg::AArch64(r) => r.reg_index(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// If the register is an AArch64 vector register then return its index.
|
||||
fn a64_vreg_index(reg: InlineAsmReg) -> Option<u32> {
|
||||
use AArch64InlineAsmReg::*;
|
||||
match reg {
|
||||
InlineAsmReg::AArch64(reg) if reg as u32 >= v0 as u32 && reg as u32 <= v31 as u32 => {
|
||||
Some(reg as u32 - v0 as u32)
|
||||
}
|
||||
InlineAsmReg::AArch64(reg) => reg.vreg_index(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ impl AArch64InlineAsmRegClass {
|
||||
neon: I8, I16, I32, I64, F16, F32, F64, F128,
|
||||
VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF16(4), VecF32(2), VecF64(1),
|
||||
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2);
|
||||
// Note: When adding support for SVE vector types, they must be rejected for Arm64EC.
|
||||
},
|
||||
Self::preg => &[],
|
||||
}
|
||||
@ -96,7 +97,7 @@ fn restricted_for_arm64ec(
|
||||
_is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
if arch == InlineAsmArch::Arm64EC {
|
||||
Err("x13, x14, x23, x24, x28, v16-v31 cannot be used for Arm64EC")
|
||||
Err("x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@ -165,23 +166,23 @@ def_regs! {
|
||||
v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"] % restricted_for_arm64ec,
|
||||
v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"] % restricted_for_arm64ec,
|
||||
v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"] % restricted_for_arm64ec,
|
||||
p0: preg = ["p0"],
|
||||
p1: preg = ["p1"],
|
||||
p2: preg = ["p2"],
|
||||
p3: preg = ["p3"],
|
||||
p4: preg = ["p4"],
|
||||
p5: preg = ["p5"],
|
||||
p6: preg = ["p6"],
|
||||
p7: preg = ["p7"],
|
||||
p8: preg = ["p8"],
|
||||
p9: preg = ["p9"],
|
||||
p10: preg = ["p10"],
|
||||
p11: preg = ["p11"],
|
||||
p12: preg = ["p12"],
|
||||
p13: preg = ["p13"],
|
||||
p14: preg = ["p14"],
|
||||
p15: preg = ["p15"],
|
||||
ffr: preg = ["ffr"],
|
||||
p0: preg = ["p0"] % restricted_for_arm64ec,
|
||||
p1: preg = ["p1"] % restricted_for_arm64ec,
|
||||
p2: preg = ["p2"] % restricted_for_arm64ec,
|
||||
p3: preg = ["p3"] % restricted_for_arm64ec,
|
||||
p4: preg = ["p4"] % restricted_for_arm64ec,
|
||||
p5: preg = ["p5"] % restricted_for_arm64ec,
|
||||
p6: preg = ["p6"] % restricted_for_arm64ec,
|
||||
p7: preg = ["p7"] % restricted_for_arm64ec,
|
||||
p8: preg = ["p8"] % restricted_for_arm64ec,
|
||||
p9: preg = ["p9"] % restricted_for_arm64ec,
|
||||
p10: preg = ["p10"] % restricted_for_arm64ec,
|
||||
p11: preg = ["p11"] % restricted_for_arm64ec,
|
||||
p12: preg = ["p12"] % restricted_for_arm64ec,
|
||||
p13: preg = ["p13"] % restricted_for_arm64ec,
|
||||
p14: preg = ["p14"] % restricted_for_arm64ec,
|
||||
p15: preg = ["p15"] % restricted_for_arm64ec,
|
||||
ffr: preg = ["ffr"] % restricted_for_arm64ec,
|
||||
#error = ["x19", "w19"] =>
|
||||
"x19 is used internally by LLVM and cannot be used as an operand for inline asm",
|
||||
#error = ["x29", "w29", "fp", "wfp"] =>
|
||||
@ -200,12 +201,66 @@ impl AArch64InlineAsmReg {
|
||||
_arch: InlineAsmArch,
|
||||
modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
let (prefix, index) = if (self as u32) < Self::v0 as u32 {
|
||||
(modifier.unwrap_or('x'), self as u32 - Self::x0 as u32)
|
||||
let (prefix, index) = if let Some(index) = self.reg_index() {
|
||||
(modifier.unwrap_or('x'), index)
|
||||
} else if let Some(index) = self.vreg_index() {
|
||||
(modifier.unwrap_or('v'), index)
|
||||
} else {
|
||||
(modifier.unwrap_or('v'), self as u32 - Self::v0 as u32)
|
||||
return out.write_str(self.name());
|
||||
};
|
||||
assert!(index < 32);
|
||||
write!(out, "{prefix}{index}")
|
||||
}
|
||||
|
||||
/// If the register is an integer register then return its index.
|
||||
pub fn reg_index(self) -> Option<u32> {
|
||||
// Unlike `vreg_index`, we can't subtract `x0` to get the u32 because
|
||||
// `x19` and `x29` are missing and the integer constants for the
|
||||
// `x0`..`x30` enum variants don't all match the register number. E.g. the
|
||||
// integer constant for `x18` is 18, but the constant for `x20` is 19.
|
||||
use AArch64InlineAsmReg::*;
|
||||
Some(match self {
|
||||
x0 => 0,
|
||||
x1 => 1,
|
||||
x2 => 2,
|
||||
x3 => 3,
|
||||
x4 => 4,
|
||||
x5 => 5,
|
||||
x6 => 6,
|
||||
x7 => 7,
|
||||
x8 => 8,
|
||||
x9 => 9,
|
||||
x10 => 10,
|
||||
x11 => 11,
|
||||
x12 => 12,
|
||||
x13 => 13,
|
||||
x14 => 14,
|
||||
x15 => 15,
|
||||
x16 => 16,
|
||||
x17 => 17,
|
||||
x18 => 18,
|
||||
// x19 is reserved
|
||||
x20 => 20,
|
||||
x21 => 21,
|
||||
x22 => 22,
|
||||
x23 => 23,
|
||||
x24 => 24,
|
||||
x25 => 25,
|
||||
x26 => 26,
|
||||
x27 => 27,
|
||||
x28 => 28,
|
||||
// x29 is reserved
|
||||
x30 => 30,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// If the register is a vector register then return its index.
|
||||
pub fn vreg_index(self) -> Option<u32> {
|
||||
use AArch64InlineAsmReg::*;
|
||||
if self as u32 >= v0 as u32 && self as u32 <= v31 as u32 {
|
||||
return Some(self as u32 - v0 as u32);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -890,6 +890,7 @@ pub enum InlineAsmClobberAbi {
|
||||
Arm,
|
||||
AArch64,
|
||||
AArch64NoX18,
|
||||
Arm64EC,
|
||||
RiscV,
|
||||
LoongArch,
|
||||
S390x,
|
||||
@ -932,7 +933,7 @@ impl InlineAsmClobberAbi {
|
||||
_ => Err(&["C", "system", "efiapi"]),
|
||||
},
|
||||
InlineAsmArch::Arm64EC => match name {
|
||||
"C" | "system" => Ok(InlineAsmClobberAbi::AArch64NoX18),
|
||||
"C" | "system" => Ok(InlineAsmClobberAbi::Arm64EC),
|
||||
_ => Err(&["C", "system"]),
|
||||
},
|
||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
|
||||
@ -1033,7 +1034,6 @@ impl InlineAsmClobberAbi {
|
||||
p0, p1, p2, p3, p4, p5, p6, p7,
|
||||
p8, p9, p10, p11, p12, p13, p14, p15,
|
||||
ffr,
|
||||
|
||||
}
|
||||
},
|
||||
InlineAsmClobberAbi::AArch64NoX18 => clobbered_regs! {
|
||||
@ -1052,7 +1052,20 @@ impl InlineAsmClobberAbi {
|
||||
p0, p1, p2, p3, p4, p5, p6, p7,
|
||||
p8, p9, p10, p11, p12, p13, p14, p15,
|
||||
ffr,
|
||||
}
|
||||
},
|
||||
InlineAsmClobberAbi::Arm64EC => clobbered_regs! {
|
||||
AArch64 AArch64InlineAsmReg {
|
||||
// x13 and x14 cannot be used in Arm64EC.
|
||||
x0, x1, x2, x3, x4, x5, x6, x7,
|
||||
x8, x9, x10, x11, x12, x15,
|
||||
x16, x17, x30,
|
||||
|
||||
// Technically the low 64 bits of v8-v15 are preserved, but
|
||||
// we have no way of expressing this using clobbers.
|
||||
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||
v8, v9, v10, v11, v12, v13, v14, v15,
|
||||
// v16-v31, p*, and ffr cannot be used in Arm64EC.
|
||||
}
|
||||
},
|
||||
InlineAsmClobberAbi::Arm => clobbered_regs! {
|
||||
|
@ -506,7 +506,7 @@ impl AsciiChar {
|
||||
pub const unsafe fn digit_unchecked(d: u8) -> Self {
|
||||
assert_unsafe_precondition!(
|
||||
check_language_ub,
|
||||
"`AsciiChar::digit_unchecked` input cannot exceed 9.",
|
||||
"`ascii::Char::digit_unchecked` input cannot exceed 9.",
|
||||
(d: u8 = d) => d < 10
|
||||
);
|
||||
|
||||
|
@ -64,6 +64,7 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use crate::marker::{DiscriminantKind, Tuple};
|
||||
use crate::mem::SizedTypeProperties;
|
||||
use crate::{ptr, ub_checks};
|
||||
|
||||
pub mod mir;
|
||||
@ -3364,10 +3365,12 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
|
||||
size: usize = size_of::<T>(),
|
||||
align: usize = align_of::<T>(),
|
||||
count: usize = count,
|
||||
) =>
|
||||
ub_checks::is_aligned_and_not_null(src, align)
|
||||
&& ub_checks::is_aligned_and_not_null(dst, align)
|
||||
&& ub_checks::is_nonoverlapping(src, dst, size, count)
|
||||
) => {
|
||||
let zero_size = count == 0 || size == 0;
|
||||
ub_checks::is_aligned_and_not_null(src, align, zero_size)
|
||||
&& ub_checks::is_aligned_and_not_null(dst, align, zero_size)
|
||||
&& ub_checks::is_nonoverlapping(src, dst, size, count)
|
||||
}
|
||||
);
|
||||
|
||||
// SAFETY: the safety contract for `copy_nonoverlapping` must be
|
||||
@ -3465,9 +3468,10 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
||||
src: *const () = src as *const (),
|
||||
dst: *mut () = dst as *mut (),
|
||||
align: usize = align_of::<T>(),
|
||||
zero_size: bool = T::IS_ZST || count == 0,
|
||||
) =>
|
||||
ub_checks::is_aligned_and_not_null(src, align)
|
||||
&& ub_checks::is_aligned_and_not_null(dst, align)
|
||||
ub_checks::is_aligned_and_not_null(src, align, zero_size)
|
||||
&& ub_checks::is_aligned_and_not_null(dst, align, zero_size)
|
||||
);
|
||||
copy(src, dst, count)
|
||||
}
|
||||
@ -3544,7 +3548,8 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
|
||||
(
|
||||
addr: *const () = dst as *const (),
|
||||
align: usize = align_of::<T>(),
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align)
|
||||
zero_size: bool = T::IS_ZST || count == 0,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, zero_size)
|
||||
);
|
||||
write_bytes(dst, val, count)
|
||||
}
|
||||
|
@ -1422,7 +1422,7 @@ impl<Ptr: DerefMut> Pin<Ptr> {
|
||||
/// move in the future, and this method does not enable the pointee to move. "Malicious"
|
||||
/// implementations of `Ptr::DerefMut` are likewise ruled out by the contract of
|
||||
/// `Pin::new_unchecked`.
|
||||
#[unstable(feature = "pin_deref_mut", issue = "86918")]
|
||||
#[stable(feature = "pin_deref_mut", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[must_use = "`self` will be dropped if the result is not used"]
|
||||
#[inline(always)]
|
||||
pub fn as_deref_mut(self: Pin<&mut Pin<Ptr>>) -> Pin<&mut Ptr::Target> {
|
||||
|
@ -448,7 +448,7 @@
|
||||
|
||||
use crate::cmp::Ordering;
|
||||
use crate::marker::FnPtr;
|
||||
use crate::mem::{self, MaybeUninit};
|
||||
use crate::mem::{self, MaybeUninit, SizedTypeProperties};
|
||||
use crate::{fmt, hash, intrinsics, ub_checks};
|
||||
|
||||
mod alignment;
|
||||
@ -1165,10 +1165,12 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
|
||||
size: usize = size_of::<T>(),
|
||||
align: usize = align_of::<T>(),
|
||||
count: usize = count,
|
||||
) =>
|
||||
ub_checks::is_aligned_and_not_null(x, align)
|
||||
&& ub_checks::is_aligned_and_not_null(y, align)
|
||||
&& ub_checks::is_nonoverlapping(x, y, size, count)
|
||||
) => {
|
||||
let zero_size = size == 0 || count == 0;
|
||||
ub_checks::is_aligned_and_not_null(x, align, zero_size)
|
||||
&& ub_checks::is_aligned_and_not_null(y, align, zero_size)
|
||||
&& ub_checks::is_nonoverlapping(x, y, size, count)
|
||||
}
|
||||
);
|
||||
|
||||
// Split up the slice into small power-of-two-sized chunks that LLVM is able
|
||||
@ -1278,7 +1280,8 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
|
||||
(
|
||||
addr: *const () = dst as *const (),
|
||||
align: usize = align_of::<T>(),
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align)
|
||||
is_zst: bool = T::IS_ZST,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
||||
);
|
||||
mem::replace(&mut *dst, src)
|
||||
}
|
||||
@ -1430,7 +1433,8 @@ pub const unsafe fn read<T>(src: *const T) -> T {
|
||||
(
|
||||
addr: *const () = src as *const (),
|
||||
align: usize = align_of::<T>(),
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align)
|
||||
is_zst: bool = T::IS_ZST,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
||||
);
|
||||
crate::intrinsics::read_via_copy(src)
|
||||
}
|
||||
@ -1635,7 +1639,8 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
|
||||
(
|
||||
addr: *mut () = dst as *mut (),
|
||||
align: usize = align_of::<T>(),
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align)
|
||||
is_zst: bool = T::IS_ZST,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
||||
);
|
||||
intrinsics::write_via_move(dst, src)
|
||||
}
|
||||
@ -1808,7 +1813,8 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
||||
(
|
||||
addr: *const () = src as *const (),
|
||||
align: usize = align_of::<T>(),
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align)
|
||||
is_zst: bool = T::IS_ZST,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
||||
);
|
||||
intrinsics::volatile_load(src)
|
||||
}
|
||||
@ -1887,7 +1893,8 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
|
||||
(
|
||||
addr: *mut () = dst as *mut (),
|
||||
align: usize = align_of::<T>(),
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align)
|
||||
is_zst: bool = T::IS_ZST,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
||||
);
|
||||
intrinsics::volatile_store(dst, src);
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
|
||||
align: usize = align_of::<T>(),
|
||||
len: usize = len,
|
||||
) =>
|
||||
ub_checks::is_aligned_and_not_null(data, align)
|
||||
ub_checks::is_aligned_and_not_null(data, align, false)
|
||||
&& ub_checks::is_valid_allocation_size(size, len)
|
||||
);
|
||||
&*ptr::slice_from_raw_parts(data, len)
|
||||
@ -187,7 +187,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
|
||||
align: usize = align_of::<T>(),
|
||||
len: usize = len,
|
||||
) =>
|
||||
ub_checks::is_aligned_and_not_null(data, align)
|
||||
ub_checks::is_aligned_and_not_null(data, align, false)
|
||||
&& ub_checks::is_valid_allocation_size(size, len)
|
||||
);
|
||||
&mut *ptr::slice_from_raw_parts_mut(data, len)
|
||||
|
@ -109,15 +109,15 @@ pub(crate) const fn check_language_ub() -> bool {
|
||||
intrinsics::ub_checks() && const_eval_select((), comptime, runtime)
|
||||
}
|
||||
|
||||
/// Checks whether `ptr` is properly aligned with respect to
|
||||
/// `align_of::<T>()`.
|
||||
/// Checks whether `ptr` is properly aligned with respect to the given alignment, and
|
||||
/// if `is_zst == false`, that `ptr` is not null.
|
||||
///
|
||||
/// In `const` this is approximate and can fail spuriously. It is primarily intended
|
||||
/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
|
||||
/// check is anyway not executed in `const`.
|
||||
#[inline]
|
||||
pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize) -> bool {
|
||||
!ptr.is_null() && ptr.is_aligned_to(align)
|
||||
pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool {
|
||||
ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -43,6 +43,11 @@ use crate::common::{
|
||||
use crate::header::HeadersCache;
|
||||
use crate::util::logv;
|
||||
|
||||
/// Creates the `Config` instance for this invocation of compiletest.
|
||||
///
|
||||
/// The config mostly reflects command-line arguments, but there might also be
|
||||
/// some code here that inspects environment variables or even runs executables
|
||||
/// (e.g. when discovering debugger versions).
|
||||
pub fn parse_config(args: Vec<String>) -> Config {
|
||||
let mut opts = Options::new();
|
||||
opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH")
|
||||
@ -413,6 +418,7 @@ pub fn opt_str2(maybestr: Option<String>) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// Called by `main` after the config has been parsed.
|
||||
pub fn run_tests(config: Arc<Config>) {
|
||||
// If we want to collect rustfix coverage information,
|
||||
// we first make sure that the coverage file does not exist.
|
||||
@ -454,6 +460,8 @@ pub fn run_tests(config: Arc<Config>) {
|
||||
configs.push(config.clone());
|
||||
};
|
||||
|
||||
// Discover all of the tests in the test suite directory, and build a libtest
|
||||
// structure for each test (or each revision of a multi-revision test).
|
||||
let mut tests = Vec::new();
|
||||
for c in configs {
|
||||
let mut found_paths = HashSet::new();
|
||||
@ -463,7 +471,12 @@ pub fn run_tests(config: Arc<Config>) {
|
||||
|
||||
tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice()));
|
||||
|
||||
// Delegate to libtest to filter and run the big list of structures created
|
||||
// during test discovery. When libtest decides to run a test, it will invoke
|
||||
// the corresponding closure created by `make_test_closure`.
|
||||
let res = test::run_tests_console(&opts, tests);
|
||||
|
||||
// Check the outcome reported by libtest.
|
||||
match res {
|
||||
Ok(true) => {}
|
||||
Ok(false) => {
|
||||
@ -532,6 +545,11 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates libtest structures for every test/revision in the test suite directory.
|
||||
///
|
||||
/// This always inspects _all_ test files in the suite (e.g. all 17k+ ui tests),
|
||||
/// regardless of whether any filters/tests were specified on the command-line,
|
||||
/// because filtering is handled later by libtest.
|
||||
pub fn make_tests(
|
||||
config: Arc<Config>,
|
||||
tests: &mut Vec<test::TestDescAndFn>,
|
||||
@ -610,10 +628,17 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
|
||||
stamp
|
||||
}
|
||||
|
||||
/// Returns a list of modified/untracked test files that should be run when
|
||||
/// the `--only-modified` flag is in use.
|
||||
///
|
||||
/// (Might be inaccurate in some cases.)
|
||||
fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
|
||||
// If `--only-modified` wasn't passed, the list of modified tests won't be
|
||||
// used for anything, so avoid some work and just return an empty list.
|
||||
if !config.only_modified {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let files =
|
||||
get_git_modified_files(&config.git_config(), Some(dir), &vec!["rs", "stderr", "fixed"])?
|
||||
.unwrap_or(vec![]);
|
||||
@ -634,6 +659,8 @@ fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
|
||||
Ok(full_paths)
|
||||
}
|
||||
|
||||
/// Recursively scans a directory to find test files and create test structures
|
||||
/// that will be handed over to libtest.
|
||||
fn collect_tests_from_dir(
|
||||
config: Arc<Config>,
|
||||
cache: &HeadersCache,
|
||||
@ -650,6 +677,8 @@ fn collect_tests_from_dir(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// For run-make tests, a "test file" is actually a directory that contains
|
||||
// an `rmake.rs` or `Makefile`"
|
||||
if config.mode == Mode::RunMake {
|
||||
if dir.join("Makefile").exists() && dir.join("rmake.rs").exists() {
|
||||
return Err(io::Error::other(
|
||||
@ -663,6 +692,7 @@ fn collect_tests_from_dir(
|
||||
relative_dir: relative_dir_path.parent().unwrap().to_path_buf(),
|
||||
};
|
||||
tests.extend(make_test(config, cache, &paths, inputs, poisoned));
|
||||
// This directory is a test, so don't try to find other tests inside it.
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@ -677,22 +707,27 @@ fn collect_tests_from_dir(
|
||||
fs::create_dir_all(&build_dir).unwrap();
|
||||
|
||||
// Add each `.rs` file as a test, and recurse further on any
|
||||
// subdirectories we find, except for `aux` directories.
|
||||
// subdirectories we find, except for `auxiliary` directories.
|
||||
// FIXME: this walks full tests tree, even if we have something to ignore
|
||||
// use walkdir/ignore like in tidy?
|
||||
for file in fs::read_dir(dir)? {
|
||||
let file = file?;
|
||||
let file_path = file.path();
|
||||
let file_name = file.file_name();
|
||||
|
||||
if is_test(&file_name) && (!config.only_modified || modified_tests.contains(&file_path)) {
|
||||
// We found a test file, so create the corresponding libtest structures.
|
||||
debug!("found test file: {:?}", file_path.display());
|
||||
|
||||
// Record the stem of the test file, to check for overlaps later.
|
||||
let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap());
|
||||
found_paths.insert(rel_test_path);
|
||||
|
||||
let paths =
|
||||
TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() };
|
||||
|
||||
tests.extend(make_test(config.clone(), cache, &paths, inputs, poisoned))
|
||||
} else if file_path.is_dir() {
|
||||
// Recurse to find more tests in a subdirectory.
|
||||
let relative_file_path = relative_dir_path.join(file.file_name());
|
||||
if &file_name != "auxiliary" {
|
||||
debug!("found directory: {:?}", file_path.display());
|
||||
@ -728,6 +763,8 @@ pub fn is_test(file_name: &OsString) -> bool {
|
||||
!invalid_prefixes.iter().any(|p| file_name.starts_with(p))
|
||||
}
|
||||
|
||||
/// For a single test file, creates one or more test structures (one per revision)
|
||||
/// that can be handed over to libtest to run, possibly in parallel.
|
||||
fn make_test(
|
||||
config: Arc<Config>,
|
||||
cache: &HeadersCache,
|
||||
@ -735,6 +772,9 @@ fn make_test(
|
||||
inputs: &Stamp,
|
||||
poisoned: &mut bool,
|
||||
) -> Vec<test::TestDescAndFn> {
|
||||
// For run-make tests, each "test file" is actually a _directory_ containing
|
||||
// an `rmake.rs` or `Makefile`. But for the purposes of directive parsing,
|
||||
// we want to look at that recipe file, not the directory itself.
|
||||
let test_path = if config.mode == Mode::RunMake {
|
||||
if testpaths.file.join("rmake.rs").exists() && testpaths.file.join("Makefile").exists() {
|
||||
panic!("run-make tests cannot have both `rmake.rs` and `Makefile`");
|
||||
@ -750,26 +790,40 @@ fn make_test(
|
||||
} else {
|
||||
PathBuf::from(&testpaths.file)
|
||||
};
|
||||
|
||||
// Scan the test file to discover its revisions, if any.
|
||||
let early_props = EarlyProps::from_file(&config, &test_path);
|
||||
|
||||
// Incremental tests are special, they inherently cannot be run in parallel.
|
||||
// `runtest::run` will be responsible for iterating over revisions.
|
||||
// Normally we create one libtest structure per revision, with two exceptions:
|
||||
// - If a test doesn't use revisions, create a dummy revision (None) so that
|
||||
// the test can still run.
|
||||
// - Incremental tests inherently can't run their revisions in parallel, so
|
||||
// we treat them like non-revisioned tests here. Incremental revisions are
|
||||
// handled internally by `runtest::run` instead.
|
||||
let revisions = if early_props.revisions.is_empty() || config.mode == Mode::Incremental {
|
||||
vec![None]
|
||||
} else {
|
||||
early_props.revisions.iter().map(|r| Some(r.as_str())).collect()
|
||||
};
|
||||
|
||||
// For each revision (or the sole dummy revision), create and return a
|
||||
// `test::TestDescAndFn` that can be handed over to libtest.
|
||||
revisions
|
||||
.into_iter()
|
||||
.map(|revision| {
|
||||
// Create a test name and description to hand over to libtest.
|
||||
let src_file =
|
||||
std::fs::File::open(&test_path).expect("open test file to parse ignores");
|
||||
let test_name = crate::make_test_name(&config, testpaths, revision);
|
||||
// Create a libtest description for the test/revision.
|
||||
// This is where `ignore-*`/`only-*`/`needs-*` directives are handled,
|
||||
// because they need to set the libtest ignored flag.
|
||||
let mut desc = make_test_description(
|
||||
&config, cache, test_name, &test_path, src_file, revision, poisoned,
|
||||
);
|
||||
// Ignore tests that already run and are up to date with respect to inputs.
|
||||
|
||||
// If a test's inputs haven't changed since the last time it ran,
|
||||
// mark it as ignored so that libtest will skip it.
|
||||
if !config.force_rerun
|
||||
&& is_up_to_date(&config, testpaths, &early_props, revision, inputs)
|
||||
{
|
||||
@ -777,18 +831,25 @@ fn make_test(
|
||||
// Keep this in sync with the "up-to-date" message detected by bootstrap.
|
||||
desc.ignore_message = Some("up-to-date");
|
||||
}
|
||||
test::TestDescAndFn {
|
||||
desc,
|
||||
testfn: make_test_closure(config.clone(), testpaths, revision),
|
||||
}
|
||||
|
||||
// Create the callback that will run this test/revision when libtest calls it.
|
||||
let testfn = make_test_closure(config.clone(), testpaths, revision);
|
||||
|
||||
test::TestDescAndFn { desc, testfn }
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// The path of the `stamp` file that gets created or updated whenever a
|
||||
/// particular test completes successfully.
|
||||
fn stamp(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
|
||||
output_base_dir(config, testpaths, revision).join("stamp")
|
||||
}
|
||||
|
||||
/// Returns a list of files that, if modified, would cause this test to no
|
||||
/// longer be up-to-date.
|
||||
///
|
||||
/// (Might be inaccurate in some cases.)
|
||||
fn files_related_to_test(
|
||||
config: &Config,
|
||||
testpaths: &TestPaths,
|
||||
@ -824,46 +885,61 @@ fn files_related_to_test(
|
||||
related
|
||||
}
|
||||
|
||||
/// Checks whether a particular test/revision is "up-to-date", meaning that no
|
||||
/// relevant files/settings have changed since the last time the test succeeded.
|
||||
///
|
||||
/// (This is not very reliable in some circumstances, so the `--force-rerun`
|
||||
/// flag can be used to ignore up-to-date checking and always re-run tests.)
|
||||
fn is_up_to_date(
|
||||
config: &Config,
|
||||
testpaths: &TestPaths,
|
||||
props: &EarlyProps,
|
||||
revision: Option<&str>,
|
||||
inputs: &Stamp,
|
||||
inputs: &Stamp, // Last-modified timestamp of the compiler, compiletest etc
|
||||
) -> bool {
|
||||
let stamp_name = stamp(config, testpaths, revision);
|
||||
// Check hash.
|
||||
// Check the config hash inside the stamp file.
|
||||
let contents = match fs::read_to_string(&stamp_name) {
|
||||
Ok(f) => f,
|
||||
Err(ref e) if e.kind() == ErrorKind::InvalidData => panic!("Can't read stamp contents"),
|
||||
// The test hasn't succeeded yet, so it is not up-to-date.
|
||||
Err(_) => return false,
|
||||
};
|
||||
let expected_hash = runtest::compute_stamp_hash(config);
|
||||
if contents != expected_hash {
|
||||
// Some part of compiletest configuration has changed since the test
|
||||
// last succeeded, so it is not up-to-date.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check timestamps.
|
||||
// Check the timestamp of the stamp file against the last modified time
|
||||
// of all files known to be relevant to the test.
|
||||
let mut inputs = inputs.clone();
|
||||
for path in files_related_to_test(config, testpaths, props, revision) {
|
||||
inputs.add_path(&path);
|
||||
}
|
||||
|
||||
// If no relevant files have been modified since the stamp file was last
|
||||
// written, the test is up-to-date.
|
||||
inputs < Stamp::from_path(&stamp_name)
|
||||
}
|
||||
|
||||
/// The maximum of a set of file-modified timestamps.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct Stamp {
|
||||
time: SystemTime,
|
||||
}
|
||||
|
||||
impl Stamp {
|
||||
/// Creates a timestamp holding the last-modified time of the specified file.
|
||||
fn from_path(path: &Path) -> Self {
|
||||
let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH };
|
||||
stamp.add_path(path);
|
||||
stamp
|
||||
}
|
||||
|
||||
/// Updates this timestamp to the last-modified time of the specified file,
|
||||
/// if it is later than the currently-stored timestamp.
|
||||
fn add_path(&mut self, path: &Path) {
|
||||
let modified = fs::metadata(path)
|
||||
.and_then(|metadata| metadata.modified())
|
||||
@ -871,6 +947,9 @@ impl Stamp {
|
||||
self.time = self.time.max(modified);
|
||||
}
|
||||
|
||||
/// Updates this timestamp to the most recent last-modified time of all files
|
||||
/// recursively contained in the given directory, if it is later than the
|
||||
/// currently-stored timestamp.
|
||||
fn add_dir(&mut self, path: &Path) {
|
||||
for entry in WalkDir::new(path) {
|
||||
let entry = entry.unwrap();
|
||||
@ -886,6 +965,7 @@ impl Stamp {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a name for this test/revision that can be handed over to libtest.
|
||||
fn make_test_name(
|
||||
config: &Config,
|
||||
testpaths: &TestPaths,
|
||||
@ -914,20 +994,41 @@ fn make_test_name(
|
||||
))
|
||||
}
|
||||
|
||||
/// Creates a callback for this test/revision that libtest will call when it
|
||||
/// decides to actually run the underlying test.
|
||||
fn make_test_closure(
|
||||
config: Arc<Config>,
|
||||
testpaths: &TestPaths,
|
||||
revision: Option<&str>,
|
||||
) -> test::TestFn {
|
||||
let config = config.clone();
|
||||
let testpaths = testpaths.clone();
|
||||
let revision = revision.map(str::to_owned);
|
||||
|
||||
// This callback is the link between compiletest's test discovery code,
|
||||
// and the parts of compiletest that know how to run an individual test.
|
||||
test::DynTestFn(Box::new(move || {
|
||||
runtest::run(config, &testpaths, revision.as_deref());
|
||||
Ok(())
|
||||
}))
|
||||
}
|
||||
|
||||
/// Checks that test discovery didn't find any tests whose name stem is a prefix
|
||||
/// of some other tests's name.
|
||||
///
|
||||
/// For example, suppose the test suite contains these two test files:
|
||||
/// - `tests/rustdoc/primitive.rs`
|
||||
/// - `tests/rustdoc/primitive/no_std.rs`
|
||||
///
|
||||
/// The test runner might put the output from those tests in these directories:
|
||||
/// - `$build/test/rustdoc/primitive/`
|
||||
/// - `$build/test/rustdoc/primitive/no_std/`
|
||||
///
|
||||
/// Because one output path is a subdirectory of the other, the two tests might
|
||||
/// interfere with each other in unwanted ways, especially if the test runner
|
||||
/// decides to delete test output directories to clean them between runs.
|
||||
/// To avoid problems, we forbid test names from overlapping in this way.
|
||||
///
|
||||
/// See <https://github.com/rust-lang/rust/pull/109509> for more context.
|
||||
fn check_overlapping_tests(found_paths: &HashSet<PathBuf>) {
|
||||
let mut collisions = Vec::new();
|
||||
for path in found_paths {
|
||||
|
36
tests/codegen/asm-arm64ec-clobbers.rs
Normal file
36
tests/codegen/asm-arm64ec-clobbers.rs
Normal file
@ -0,0 +1,36 @@
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target arm64ec-pc-windows-msvc
|
||||
//@ needs-llvm-components: aarch64
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @cc_clobber
|
||||
// CHECK: call void asm sideeffect "", "~{cc}"()
|
||||
#[no_mangle]
|
||||
pub unsafe fn cc_clobber() {
|
||||
asm!("", options(nostack, nomem));
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @no_clobber
|
||||
// CHECK: call void asm sideeffect "", ""()
|
||||
#[no_mangle]
|
||||
pub unsafe fn no_clobber() {
|
||||
asm!("", options(nostack, nomem, preserves_flags));
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @clobber_abi
|
||||
// CHECK: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15}"()
|
||||
#[no_mangle]
|
||||
pub unsafe fn clobber_abi() {
|
||||
asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
|
||||
}
|
@ -2,7 +2,7 @@ extern "C" {
|
||||
//@ is "$.index[*][?(@.name=='f1')].inner.function.header.is_unsafe" true
|
||||
pub fn f1();
|
||||
|
||||
// items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
// items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
|
28
tests/ui/asm/aarch64/aarch64-sve.rs
Normal file
28
tests/ui/asm/aarch64/aarch64-sve.rs
Normal file
@ -0,0 +1,28 @@
|
||||
//@ only-aarch64
|
||||
//@ build-pass
|
||||
//@ needs-asm-support
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items)]
|
||||
#![no_core]
|
||||
|
||||
// AArch64 test corresponding to arm64ec-sve.rs.
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
impl Copy for f64 {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
|
||||
fn f(x: f64) {
|
||||
unsafe {
|
||||
asm!("", out("p0") _);
|
||||
asm!("", out("ffr") _);
|
||||
}
|
||||
}
|
31
tests/ui/asm/aarch64/arm64ec-sve.rs
Normal file
31
tests/ui/asm/aarch64/arm64ec-sve.rs
Normal file
@ -0,0 +1,31 @@
|
||||
//@ compile-flags: --target arm64ec-pc-windows-msvc
|
||||
//@ needs-asm-support
|
||||
//@ needs-llvm-components: aarch64
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
|
||||
#![no_core]
|
||||
|
||||
// SVE cannot be used for Arm64EC
|
||||
// https://github.com/rust-lang/rust/pull/131332#issuecomment-2401189142
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
impl Copy for f64 {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
|
||||
fn f(x: f64) {
|
||||
unsafe {
|
||||
asm!("", out("p0") _);
|
||||
//~^ ERROR cannot use register `p0`
|
||||
asm!("", out("ffr") _);
|
||||
//~^ ERROR cannot use register `ffr`
|
||||
}
|
||||
}
|
14
tests/ui/asm/aarch64/arm64ec-sve.stderr
Normal file
14
tests/ui/asm/aarch64/arm64ec-sve.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error: cannot use register `p0`: x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC
|
||||
--> $DIR/arm64ec-sve.rs:26:18
|
||||
|
|
||||
LL | asm!("", out("p0") _);
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: cannot use register `ffr`: x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC
|
||||
--> $DIR/arm64ec-sve.rs:28:18
|
||||
|
|
||||
LL | asm!("", out("ffr") _);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
2
tests/ui/extern/issue-95829.rs
vendored
2
tests/ui/extern/issue-95829.rs
vendored
@ -2,7 +2,7 @@
|
||||
|
||||
extern {
|
||||
async fn L() { //~ ERROR: incorrect function inside `extern` block
|
||||
//~^ ERROR: functions in `extern` blocks cannot have qualifiers
|
||||
//~^ ERROR: functions in `extern` blocks cannot have `async` qualifier
|
||||
async fn M() {}
|
||||
}
|
||||
}
|
||||
|
4
tests/ui/extern/issue-95829.stderr
vendored
4
tests/ui/extern/issue-95829.stderr
vendored
@ -15,13 +15,13 @@ LL | | }
|
||||
= help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
|
||||
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
error: functions in `extern` blocks cannot have `async` qualifier
|
||||
--> $DIR/issue-95829.rs:4:5
|
||||
|
|
||||
LL | extern {
|
||||
| ------ in this `extern` block
|
||||
LL | async fn L() {
|
||||
| ^^^^^ help: remove this qualifier
|
||||
| ^^^^^ help: remove the `async` qualifier
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
//@ run-rustfix
|
||||
|
||||
fn main() {
|
||||
let s = "123";
|
||||
println!("{:?} {} {}", {}, "sss", s);
|
||||
//~^ ERROR format argument must be a string literal
|
||||
println!("{:?}", {});
|
||||
//~^ ERROR format argument must be a string literal
|
||||
println!("{} {} {} {:?}", s, "sss", s, {});
|
||||
//~^ ERROR format argument must be a string literal
|
||||
println!("{:?} {} {:?}", (), s, {});
|
||||
//~^ ERROR format argument must be a string literal
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
//@ run-rustfix
|
||||
|
||||
fn main() {
|
||||
let s = "123";
|
||||
println!({}, "sss", s);
|
||||
//~^ ERROR format argument must be a string literal
|
||||
println!({});
|
||||
//~^ ERROR format argument must be a string literal
|
||||
println!(s, "sss", s, {});
|
||||
//~^ ERROR format argument must be a string literal
|
||||
println!((), s, {});
|
||||
//~^ ERROR format argument must be a string literal
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
error: format argument must be a string literal
|
||||
--> $DIR/format-empty-block-unit-tuple-suggestion-130170.rs:5:14
|
||||
|
|
||||
LL | println!({}, "sss", s);
|
||||
| ^^
|
||||
|
|
||||
help: you might be missing a string literal to format with
|
||||
|
|
||||
LL | println!("{:?} {} {}", {}, "sss", s);
|
||||
| +++++++++++++
|
||||
|
||||
error: format argument must be a string literal
|
||||
--> $DIR/format-empty-block-unit-tuple-suggestion-130170.rs:7:14
|
||||
|
|
||||
LL | println!({});
|
||||
| ^^
|
||||
|
|
||||
help: you might be missing a string literal to format with
|
||||
|
|
||||
LL | println!("{:?}", {});
|
||||
| +++++++
|
||||
|
||||
error: format argument must be a string literal
|
||||
--> $DIR/format-empty-block-unit-tuple-suggestion-130170.rs:9:14
|
||||
|
|
||||
LL | println!(s, "sss", s, {});
|
||||
| ^
|
||||
|
|
||||
help: you might be missing a string literal to format with
|
||||
|
|
||||
LL | println!("{} {} {} {:?}", s, "sss", s, {});
|
||||
| ++++++++++++++++
|
||||
|
||||
error: format argument must be a string literal
|
||||
--> $DIR/format-empty-block-unit-tuple-suggestion-130170.rs:11:14
|
||||
|
|
||||
LL | println!((), s, {});
|
||||
| ^^
|
||||
|
|
||||
help: you might be missing a string literal to format with
|
||||
|
|
||||
LL | println!("{:?} {} {:?}", (), s, {});
|
||||
| +++++++++++++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
@ -41,15 +41,15 @@ fn main() {
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
async fn fe1(); //~ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
unsafe fn fe2(); //~ ERROR items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
async fn fe1(); //~ ERROR functions in `extern` blocks cannot
|
||||
unsafe fn fe2(); //~ ERROR items in `extern` blocks without an `unsafe` qualifier cannot
|
||||
const fn fe3(); //~ ERROR functions in `extern` blocks cannot
|
||||
extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot
|
||||
const async unsafe extern "C" fn fe5();
|
||||
//~^ ERROR functions in `extern` blocks
|
||||
//~| ERROR functions in `extern` blocks
|
||||
//~| ERROR functions in `extern` blocks
|
||||
//~| ERROR functions cannot be both `const` and `async`
|
||||
//~| ERROR items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
//~| ERROR items in `extern` blocks without an `unsafe` qualifier cannot have
|
||||
}
|
||||
}
|
||||
|
@ -70,77 +70,77 @@ LL | const async unsafe extern "C" fn fi5() {}
|
||||
| | `async` because of this
|
||||
| `const` because of this
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
error: functions in `extern` blocks cannot have `async` qualifier
|
||||
--> $DIR/fn-header-semantic-fail.rs:44:9
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
LL | async fn fe1();
|
||||
| ^^^^^ help: remove this qualifier
|
||||
| ^^^^^ help: remove the `async` qualifier
|
||||
|
||||
error: items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
error: items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:45:9
|
||||
|
|
||||
LL | unsafe fn fe2();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add unsafe to this `extern` block
|
||||
help: add `unsafe` to this `extern` block
|
||||
|
|
||||
LL | unsafe extern "C" {
|
||||
| ++++++
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
error: functions in `extern` blocks cannot have `const` qualifier
|
||||
--> $DIR/fn-header-semantic-fail.rs:46:9
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const fn fe3();
|
||||
| ^^^^^ help: remove this qualifier
|
||||
| ^^^^^ help: remove the `const` qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
error: functions in `extern` blocks cannot have `extern` qualifier
|
||||
--> $DIR/fn-header-semantic-fail.rs:47:9
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | extern "C" fn fe4();
|
||||
| ^^^^^^^^^^ help: remove this qualifier
|
||||
| ^^^^^^^^^^ help: remove the `extern` qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
error: functions in `extern` blocks cannot have `async` qualifier
|
||||
--> $DIR/fn-header-semantic-fail.rs:48:15
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const async unsafe extern "C" fn fe5();
|
||||
| ^^^^^ help: remove this qualifier
|
||||
| ^^^^^ help: remove the `async` qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
error: functions in `extern` blocks cannot have `const` qualifier
|
||||
--> $DIR/fn-header-semantic-fail.rs:48:9
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const async unsafe extern "C" fn fe5();
|
||||
| ^^^^^ help: remove this qualifier
|
||||
| ^^^^^ help: remove the `const` qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
error: functions in `extern` blocks cannot have `extern` qualifier
|
||||
--> $DIR/fn-header-semantic-fail.rs:48:28
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const async unsafe extern "C" fn fe5();
|
||||
| ^^^^^^^^^^ help: remove this qualifier
|
||||
| ^^^^^^^^^^ help: remove the `extern` qualifier
|
||||
|
||||
error: items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
error: items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:48:9
|
||||
|
|
||||
LL | const async unsafe extern "C" fn fe5();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add unsafe to this `extern` block
|
||||
help: add `unsafe` to this `extern` block
|
||||
|
|
||||
LL | unsafe extern "C" {
|
||||
| ++++++
|
||||
|
@ -1,9 +1,9 @@
|
||||
extern "C" {
|
||||
const fn foo();
|
||||
//~^ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
//~^ ERROR functions in `extern` blocks cannot
|
||||
const unsafe fn bar();
|
||||
//~^ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
//~| ERROR items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
//~^ ERROR functions in `extern` blocks cannot
|
||||
//~| ERROR items in `extern` blocks without an `unsafe` qualifier cannot
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,27 +1,27 @@
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
error: functions in `extern` blocks cannot have `const` qualifier
|
||||
--> $DIR/no-const-fn-in-extern-block.rs:2:5
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
LL | const fn foo();
|
||||
| ^^^^^ help: remove this qualifier
|
||||
| ^^^^^ help: remove the `const` qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
error: functions in `extern` blocks cannot have `const` qualifier
|
||||
--> $DIR/no-const-fn-in-extern-block.rs:4:5
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const unsafe fn bar();
|
||||
| ^^^^^ help: remove this qualifier
|
||||
| ^^^^^ help: remove the `const` qualifier
|
||||
|
||||
error: items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
error: items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
--> $DIR/no-const-fn-in-extern-block.rs:4:5
|
||||
|
|
||||
LL | const unsafe fn bar();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add unsafe to this `extern` block
|
||||
help: add `unsafe` to this `extern` block
|
||||
|
|
||||
LL | unsafe extern "C" {
|
||||
| ++++++
|
||||
|
11
tests/ui/precondition-checks/alignment.rs
Normal file
11
tests/ui/precondition-checks/alignment.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: Alignment::new_unchecked requires
|
||||
|
||||
#![feature(ptr_alignment_type)]
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
std::ptr::Alignment::new_unchecked(0);
|
||||
}
|
||||
}
|
11
tests/ui/precondition-checks/ascii-char-digit_unchecked.rs
Normal file
11
tests/ui/precondition-checks/ascii-char-digit_unchecked.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: `ascii::Char::digit_unchecked` input cannot exceed 9
|
||||
|
||||
#![feature(ascii_char)]
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
std::ascii::Char::digit_unchecked(b'a');
|
||||
}
|
||||
}
|
9
tests/ui/precondition-checks/assert_unchecked.rs
Normal file
9
tests/ui/precondition-checks/assert_unchecked.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: hint::assert_unchecked must never be called when the condition is false
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
std::hint::assert_unchecked(false);
|
||||
}
|
||||
}
|
9
tests/ui/precondition-checks/char-from_u32_unchecked.rs
Normal file
9
tests/ui/precondition-checks/char-from_u32_unchecked.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: invalid value for `char`
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
char::from_u32_unchecked(0xD801);
|
||||
}
|
||||
}
|
25
tests/ui/precondition-checks/copy-nonoverlapping.rs
Normal file
25
tests/ui/precondition-checks/copy-nonoverlapping.rs
Normal file
@ -0,0 +1,25 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: ptr::copy_nonoverlapping requires
|
||||
//@ revisions: null_src null_dst misaligned_src misaligned_dst overlapping
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
let src = [0u16; 3];
|
||||
let mut dst = [0u16; 3];
|
||||
let src = src.as_ptr();
|
||||
let dst = dst.as_mut_ptr();
|
||||
unsafe {
|
||||
#[cfg(null_src)]
|
||||
ptr::copy_nonoverlapping(ptr::null(), dst, 1);
|
||||
#[cfg(null_dst)]
|
||||
ptr::copy_nonoverlapping(src, ptr::null_mut(), 1);
|
||||
#[cfg(misaligned_src)]
|
||||
ptr::copy_nonoverlapping(src.byte_add(1), dst, 1);
|
||||
#[cfg(misaligned_dst)]
|
||||
ptr::copy_nonoverlapping(src, dst.byte_add(1), 1);
|
||||
#[cfg(overlapping)]
|
||||
ptr::copy_nonoverlapping(dst, dst.add(1), 2);
|
||||
}
|
||||
}
|
23
tests/ui/precondition-checks/copy.rs
Normal file
23
tests/ui/precondition-checks/copy.rs
Normal file
@ -0,0 +1,23 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: ptr::copy requires
|
||||
//@ revisions: null_src null_dst misaligned_src misaligned_dst
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
let src = [0u16; 3];
|
||||
let mut dst = [0u16; 3];
|
||||
let src = src.as_ptr();
|
||||
let dst = dst.as_mut_ptr();
|
||||
unsafe {
|
||||
#[cfg(null_src)]
|
||||
ptr::copy(ptr::null(), dst, 1);
|
||||
#[cfg(null_dst)]
|
||||
ptr::copy(src, ptr::null_mut(), 1);
|
||||
#[cfg(misaligned_src)]
|
||||
ptr::copy(src.byte_add(1), dst, 1);
|
||||
#[cfg(misaligned_dst)]
|
||||
ptr::copy(src, dst.byte_add(1), 1);
|
||||
}
|
||||
}
|
15
tests/ui/precondition-checks/layout.rs
Normal file
15
tests/ui/precondition-checks/layout.rs
Normal file
@ -0,0 +1,15 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: Layout::from_size_align_unchecked requires
|
||||
//@ revisions: toolarge badalign
|
||||
//@[toolarge] compile-flags: --cfg toolarge
|
||||
//@[badalign] compile-flags: --cfg badalign
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
#[cfg(toolarge)]
|
||||
std::alloc::Layout::from_size_align_unchecked(isize::MAX as usize, 2);
|
||||
#[cfg(badalign)]
|
||||
std::alloc::Layout::from_size_align_unchecked(1, 3);
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts
|
||||
//@ ignore-debug
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let _s: &[u64] = std::slice::from_raw_parts(1usize as *const u64, 0);
|
||||
}
|
||||
}
|
9
tests/ui/precondition-checks/nonnull.rs
Normal file
9
tests/ui/precondition-checks/nonnull.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: NonNull::new_unchecked requires
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
std::ptr::NonNull::new_unchecked(std::ptr::null_mut::<u8>());
|
||||
}
|
||||
}
|
12
tests/ui/precondition-checks/nonzero-from_mut_unchecked.rs
Normal file
12
tests/ui/precondition-checks/nonzero-from_mut_unchecked.rs
Normal file
@ -0,0 +1,12 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: NonZero::from_mut_unchecked requires
|
||||
|
||||
#![feature(nonzero_from_mut)]
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut num = 0u8;
|
||||
std::num::NonZeroU8::from_mut_unchecked(&mut num);
|
||||
}
|
||||
}
|
9
tests/ui/precondition-checks/nonzero-new_unchecked.rs
Normal file
9
tests/ui/precondition-checks/nonzero-new_unchecked.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: NonZero::new_unchecked requires
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
std::num::NonZeroU8::new_unchecked(0);
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts
|
||||
//@ ignore-debug
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let _s: &[u8] = std::slice::from_raw_parts(std::ptr::null(), 0);
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: slice::get_unchecked requires
|
||||
//@ ignore-debug
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let sli: &[u8] = &[0];
|
||||
sli.get_unchecked(1);
|
||||
}
|
||||
}
|
18
tests/ui/precondition-checks/read.rs
Normal file
18
tests/ui/precondition-checks/read.rs
Normal file
@ -0,0 +1,18 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: ptr::read requires
|
||||
//@ revisions: null misaligned
|
||||
//@ ignore-test
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
let src = [0u16; 2];
|
||||
let src = src.as_ptr();
|
||||
unsafe {
|
||||
#[cfg(null)]
|
||||
ptr::read(ptr::null::<u8>());
|
||||
#[cfg(misaligned)]
|
||||
ptr::read(src.byte_add(1));
|
||||
}
|
||||
}
|
17
tests/ui/precondition-checks/read_volatile.rs
Normal file
17
tests/ui/precondition-checks/read_volatile.rs
Normal file
@ -0,0 +1,17 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: ptr::read_volatile requires
|
||||
//@ revisions: null misaligned
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
let src = [0u16; 2];
|
||||
let src = src.as_ptr();
|
||||
unsafe {
|
||||
#[cfg(null)]
|
||||
ptr::read_volatile(ptr::null::<u8>());
|
||||
#[cfg(misaligned)]
|
||||
ptr::read_volatile(src.byte_add(1));
|
||||
}
|
||||
}
|
17
tests/ui/precondition-checks/replace.rs
Normal file
17
tests/ui/precondition-checks/replace.rs
Normal file
@ -0,0 +1,17 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: ptr::replace requires
|
||||
//@ revisions: null misaligned
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
let mut dst = [0u16; 2];
|
||||
let dst = dst.as_mut_ptr();
|
||||
unsafe {
|
||||
#[cfg(null)]
|
||||
ptr::replace(ptr::null_mut::<u8>(), 1);
|
||||
#[cfg(misaligned)]
|
||||
ptr::replace(dst.byte_add(1), 1u16);
|
||||
}
|
||||
}
|
16
tests/ui/precondition-checks/slice-from-raw-parts-mut.rs
Normal file
16
tests/ui/precondition-checks/slice-from-raw-parts-mut.rs
Normal file
@ -0,0 +1,16 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts_mut requires
|
||||
//@ revisions: null misaligned toolarge
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
#[cfg(null)]
|
||||
let _s: &mut [u8] = std::slice::from_raw_parts_mut(std::ptr::null_mut(), 0);
|
||||
#[cfg(misaligned)]
|
||||
let _s: &mut [u16] = std::slice::from_raw_parts_mut(1usize as *mut u16, 0);
|
||||
#[cfg(toolarge)]
|
||||
let _s: &mut [u16] =
|
||||
std::slice::from_raw_parts_mut(2usize as *mut u16, isize::MAX as usize);
|
||||
}
|
||||
}
|
15
tests/ui/precondition-checks/slice-from-raw-parts.rs
Normal file
15
tests/ui/precondition-checks/slice-from-raw-parts.rs
Normal file
@ -0,0 +1,15 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts requires
|
||||
//@ revisions: null misaligned toolarge
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
#[cfg(null)]
|
||||
let _s: &[u8] = std::slice::from_raw_parts(std::ptr::null(), 0);
|
||||
#[cfg(misaligned)]
|
||||
let _s: &[u16] = std::slice::from_raw_parts(1usize as *const u16, 0);
|
||||
#[cfg(toolarge)]
|
||||
let _s: &[u16] = std::slice::from_raw_parts(2usize as *const u16, isize::MAX as usize);
|
||||
}
|
||||
}
|
20
tests/ui/precondition-checks/slice-get_unchecked.rs
Normal file
20
tests/ui/precondition-checks/slice-get_unchecked.rs
Normal file
@ -0,0 +1,20 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: slice::get_unchecked requires
|
||||
//@ revisions: usize range range_to range_from backwards_range
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let s = &[0];
|
||||
#[cfg(usize)]
|
||||
s.get_unchecked(1);
|
||||
#[cfg(range)]
|
||||
s.get_unchecked(1..2);
|
||||
#[cfg(range_to)]
|
||||
s.get_unchecked(..2);
|
||||
#[cfg(range_from)]
|
||||
s.get_unchecked(2..);
|
||||
#[cfg(backwards_range)]
|
||||
s.get_unchecked(1..0);
|
||||
}
|
||||
}
|
20
tests/ui/precondition-checks/slice-get_unchecked_mut.rs
Normal file
20
tests/ui/precondition-checks/slice-get_unchecked_mut.rs
Normal file
@ -0,0 +1,20 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: slice::get_unchecked_mut requires
|
||||
//@ revisions: usize range range_to range_from backwards_range
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut s = &mut [0];
|
||||
#[cfg(usize)]
|
||||
s.get_unchecked_mut(1);
|
||||
#[cfg(range)]
|
||||
s.get_unchecked_mut(1..2);
|
||||
#[cfg(range_to)]
|
||||
s.get_unchecked_mut(..2);
|
||||
#[cfg(range_from)]
|
||||
s.get_unchecked_mut(2..);
|
||||
#[cfg(backwards_range)]
|
||||
s.get_unchecked_mut(1..0);
|
||||
}
|
||||
}
|
14
tests/ui/precondition-checks/slice-swap_unchecked.rs
Normal file
14
tests/ui/precondition-checks/slice-swap_unchecked.rs
Normal file
@ -0,0 +1,14 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: index out of bounds: the len is 2 but the index is 2
|
||||
//@ revisions: oob_a oob_b
|
||||
|
||||
fn main() {
|
||||
let mut pair = [0u8; 2];
|
||||
unsafe {
|
||||
#[cfg(oob_a)]
|
||||
pair.swap(0, 2);
|
||||
#[cfg(oob_b)]
|
||||
pair.swap(2, 0);
|
||||
}
|
||||
}
|
18
tests/ui/precondition-checks/str-get_unchecked.rs
Normal file
18
tests/ui/precondition-checks/str-get_unchecked.rs
Normal file
@ -0,0 +1,18 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: str::get_unchecked requires
|
||||
//@ revisions: range range_to range_from backwards_range
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let s = "💅";
|
||||
#[cfg(range)]
|
||||
s.get_unchecked(4..5);
|
||||
#[cfg(range_to)]
|
||||
s.get_unchecked(..5);
|
||||
#[cfg(range_from)]
|
||||
s.get_unchecked(5..);
|
||||
#[cfg(backwards_range)]
|
||||
s.get_unchecked(1..0);
|
||||
}
|
||||
}
|
19
tests/ui/precondition-checks/str-get_unchecked_mut.rs
Normal file
19
tests/ui/precondition-checks/str-get_unchecked_mut.rs
Normal file
@ -0,0 +1,19 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: str::get_unchecked_mut requires
|
||||
//@ revisions: range range_to range_from backwards_range
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut s: String = "💅".chars().collect();
|
||||
let mut s: &mut str = &mut s;
|
||||
#[cfg(range)]
|
||||
s.get_unchecked_mut(4..5);
|
||||
#[cfg(range_to)]
|
||||
s.get_unchecked_mut(..5);
|
||||
#[cfg(range_from)]
|
||||
s.get_unchecked_mut(5..);
|
||||
#[cfg(backwards_range)]
|
||||
s.get_unchecked_mut(1..0);
|
||||
}
|
||||
}
|
25
tests/ui/precondition-checks/swap-nonoverlapping.rs
Normal file
25
tests/ui/precondition-checks/swap-nonoverlapping.rs
Normal file
@ -0,0 +1,25 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: ptr::swap_nonoverlapping requires
|
||||
//@ revisions: null_src null_dst misaligned_src misaligned_dst overlapping
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
let mut src = [0u16; 3];
|
||||
let mut dst = [0u16; 3];
|
||||
let src = src.as_mut_ptr();
|
||||
let dst = dst.as_mut_ptr();
|
||||
unsafe {
|
||||
#[cfg(null_src)]
|
||||
ptr::swap_nonoverlapping(ptr::null_mut(), dst, 1);
|
||||
#[cfg(null_dst)]
|
||||
ptr::swap_nonoverlapping(src, ptr::null_mut(), 1);
|
||||
#[cfg(misaligned_src)]
|
||||
ptr::swap_nonoverlapping(src.byte_add(1), dst, 1);
|
||||
#[cfg(misaligned_dst)]
|
||||
ptr::swap_nonoverlapping(src, dst.byte_add(1), 1);
|
||||
#[cfg(overlapping)]
|
||||
ptr::swap_nonoverlapping(dst, dst.add(1), 2);
|
||||
}
|
||||
}
|
9
tests/ui/precondition-checks/unchecked_add.rs
Normal file
9
tests/ui/precondition-checks/unchecked_add.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: u8::unchecked_add cannot overflow
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
1u8.unchecked_add(u8::MAX);
|
||||
}
|
||||
}
|
9
tests/ui/precondition-checks/unchecked_mul.rs
Normal file
9
tests/ui/precondition-checks/unchecked_mul.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: u8::unchecked_add cannot overflow
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
2u8.unchecked_add(u8::MAX);
|
||||
}
|
||||
}
|
11
tests/ui/precondition-checks/unchecked_shl.rs
Normal file
11
tests/ui/precondition-checks/unchecked_shl.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: u8::unchecked_shl cannot overflow
|
||||
|
||||
#![feature(unchecked_shifts)]
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
0u8.unchecked_shl(u8::BITS);
|
||||
}
|
||||
}
|
11
tests/ui/precondition-checks/unchecked_shr.rs
Normal file
11
tests/ui/precondition-checks/unchecked_shr.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: u8::unchecked_shr cannot overflow
|
||||
|
||||
#![feature(unchecked_shifts)]
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
0u8.unchecked_shr(u8::BITS);
|
||||
}
|
||||
}
|
9
tests/ui/precondition-checks/unchecked_sub.rs
Normal file
9
tests/ui/precondition-checks/unchecked_sub.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: u8::unchecked_sub cannot overflow
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
0u8.unchecked_sub(1u8);
|
||||
}
|
||||
}
|
9
tests/ui/precondition-checks/unreachable_unchecked.rs
Normal file
9
tests/ui/precondition-checks/unreachable_unchecked.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: hint::unreachable_unchecked must never be reached
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
std::hint::unreachable_unchecked();
|
||||
}
|
||||
}
|
18
tests/ui/precondition-checks/write.rs
Normal file
18
tests/ui/precondition-checks/write.rs
Normal file
@ -0,0 +1,18 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: ptr::write requires
|
||||
//@ revisions: null misaligned
|
||||
//@ ignore-test
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
let mut dst = [0u16; 2];
|
||||
let mut dst = dst.as_mut_ptr();
|
||||
unsafe {
|
||||
#[cfg(null)]
|
||||
ptr::write(ptr::null_mut::<u8>(), 1u8);
|
||||
#[cfg(misaligned)]
|
||||
ptr::write(dst.byte_add(1), 1u16);
|
||||
}
|
||||
}
|
18
tests/ui/precondition-checks/write_bytes.rs
Normal file
18
tests/ui/precondition-checks/write_bytes.rs
Normal file
@ -0,0 +1,18 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: ptr::write requires
|
||||
//@ revisions: null misaligned
|
||||
//@ ignore-test
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
let mut dst = [0u16; 2];
|
||||
let mut dst = dst.as_mut_ptr();
|
||||
unsafe {
|
||||
#[cfg(null)]
|
||||
ptr::write_bytes(ptr::null_mut::<u8>(), 1u8, 2);
|
||||
#[cfg(misaligned)]
|
||||
ptr::write_bytes(dst.byte_add(1), 1u8, 2);
|
||||
}
|
||||
}
|
17
tests/ui/precondition-checks/write_volatile.rs
Normal file
17
tests/ui/precondition-checks/write_volatile.rs
Normal file
@ -0,0 +1,17 @@
|
||||
//@ run-fail
|
||||
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: ptr::write_volatile requires
|
||||
//@ revisions: null misaligned
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
let mut dst = [0u16; 2];
|
||||
let mut dst = dst.as_mut_ptr();
|
||||
unsafe {
|
||||
#[cfg(null)]
|
||||
ptr::write_volatile(ptr::null_mut::<u8>(), 1u8);
|
||||
#[cfg(misaligned)]
|
||||
ptr::write_volatile(dst.byte_add(1), 1u16);
|
||||
}
|
||||
}
|
21
tests/ui/precondition-checks/zero-size-null.rs
Normal file
21
tests/ui/precondition-checks/zero-size-null.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Test that none of the precondition checks panic on zero-sized reads or writes through null.
|
||||
|
||||
//@ run-pass
|
||||
//@ compile-flags: -Zmir-opt-level=0 -Copt-level=0 -Cdebug-assertions=yes
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping::<u8>(ptr::null(), ptr::null_mut(), 0);
|
||||
ptr::copy_nonoverlapping::<()>(ptr::null(), ptr::null_mut(), 123);
|
||||
ptr::copy::<u8>(ptr::null(), ptr::null_mut(), 0);
|
||||
ptr::copy::<()>(ptr::null(), ptr::null_mut(), 123);
|
||||
ptr::swap::<()>(ptr::null_mut(), ptr::null_mut());
|
||||
ptr::replace::<()>(ptr::null_mut(), ());
|
||||
ptr::read::<()>(ptr::null());
|
||||
ptr::write::<()>(ptr::null_mut(), ());
|
||||
ptr::read_volatile::<()>(ptr::null());
|
||||
ptr::write_volatile::<()>(ptr::null_mut(), ());
|
||||
}
|
||||
}
|
@ -1,21 +1,21 @@
|
||||
error: items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
error: items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:5
|
||||
|
|
||||
LL | safe static TEST1: i32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add unsafe to this `extern` block
|
||||
help: add `unsafe` to this `extern` block
|
||||
|
|
||||
LL | unsafe extern "C" {
|
||||
| ++++++
|
||||
|
||||
error: items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
error: items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5
|
||||
|
|
||||
LL | safe fn test1(i: i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add unsafe to this `extern` block
|
||||
help: add `unsafe` to this `extern` block
|
||||
|
|
||||
LL | unsafe extern "C" {
|
||||
| ++++++
|
||||
|
@ -10,24 +10,24 @@ LL | |
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
error: items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:5
|
||||
|
|
||||
LL | safe static TEST1: i32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add unsafe to this `extern` block
|
||||
help: add `unsafe` to this `extern` block
|
||||
|
|
||||
LL | unsafe extern "C" {
|
||||
| ++++++
|
||||
|
||||
error: items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
error: items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5
|
||||
|
|
||||
LL | safe fn test1(i: i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add unsafe to this `extern` block
|
||||
help: add `unsafe` to this `extern` block
|
||||
|
|
||||
LL | unsafe extern "C" {
|
||||
| ++++++
|
||||
|
@ -6,9 +6,9 @@
|
||||
extern "C" {
|
||||
//[edition2024]~^ ERROR extern blocks must be unsafe
|
||||
safe static TEST1: i32;
|
||||
//~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
//~^ ERROR items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
safe fn test1(i: i32);
|
||||
//~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
//~^ ERROR items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
}
|
||||
|
||||
fn test2() {
|
||||
|
@ -3,7 +3,7 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
unsafe extern "C" {
|
||||
unsafe fn foo(); //~ ERROR items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
unsafe fn foo(); //~ ERROR items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -3,7 +3,7 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
extern "C" {
|
||||
unsafe fn foo(); //~ ERROR items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
unsafe fn foo(); //~ ERROR items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,10 +1,10 @@
|
||||
error: items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
error: items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||
--> $DIR/unsafe-on-extern-block-issue-126756.rs:6:5
|
||||
|
|
||||
LL | unsafe fn foo();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add unsafe to this `extern` block
|
||||
help: add `unsafe` to this `extern` block
|
||||
|
|
||||
LL | unsafe extern "C" {
|
||||
| ++++++
|
||||
|
@ -431,6 +431,11 @@ trigger_files = [
|
||||
"src/tools/run-make-support"
|
||||
]
|
||||
|
||||
[autolabel."A-compiletest"]
|
||||
trigger_files = [
|
||||
"src/tools/compiletest"
|
||||
]
|
||||
|
||||
[notify-zulip."I-prioritize"]
|
||||
zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
|
||||
topic = "#{number} {title}"
|
||||
|
Loading…
Reference in New Issue
Block a user