Auto merge of #91813 - matthiaskrgr:rollup-nryyeyj, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #90081 (Make `intrinsics::write_bytes` const) - #91643 (asm: Allow using r9 (ARM) and x18 (AArch64) if they are not reserved by the current target) - #91737 (Make certain panicky stdlib functions behave better under panic_immediate_abort) - #91750 (rustdoc: Add regression test for Iterator as notable trait on &T) - #91764 (Do not ICE when suggesting elided lifetimes on non-existent spans.) - #91780 (Remove hir::Node::hir_id.) - #91797 (Fix zero-sized reference to deallocated memory) - #91806 (Make `Unique`s methods `const`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e70e4d499d
@ -64,7 +64,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let mut clobber_abis = FxHashMap::default();
|
||||
if let Some(asm_arch) = asm_arch {
|
||||
for (abi_name, abi_span) in &asm.clobber_abis {
|
||||
match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
|
||||
match asm::InlineAsmClobberAbi::parse(
|
||||
asm_arch,
|
||||
|feature| self.sess.target_features.contains(&Symbol::intern(feature)),
|
||||
&self.sess.target,
|
||||
*abi_name,
|
||||
) {
|
||||
Ok(abi) => {
|
||||
// If the abi was already in the list, emit an error
|
||||
match clobber_abis.get(&abi) {
|
||||
|
@ -36,6 +36,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
// #[target_feature].
|
||||
("thumb-mode", Some(sym::arm_target_feature)),
|
||||
("thumb2", Some(sym::arm_target_feature)),
|
||||
("reserve-r9", Some(sym::arm_target_feature)),
|
||||
];
|
||||
|
||||
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
|
@ -322,6 +322,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
sym::copy => {
|
||||
self.copy_intrinsic(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?;
|
||||
}
|
||||
sym::write_bytes => {
|
||||
self.write_bytes_intrinsic(&args[0], &args[1], &args[2])?;
|
||||
}
|
||||
sym::offset => {
|
||||
let ptr = self.read_pointer(&args[0])?;
|
||||
let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?;
|
||||
@ -567,6 +570,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.memory.copy(src, align, dst, align, size, nonoverlapping)
|
||||
}
|
||||
|
||||
pub(crate) fn write_bytes_intrinsic(
|
||||
&mut self,
|
||||
dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
||||
byte: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
||||
count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?;
|
||||
|
||||
let dst = self.read_pointer(&dst)?;
|
||||
let byte = self.read_scalar(&byte)?.to_u8()?;
|
||||
let count = self.read_scalar(&count)?.to_machine_usize(self)?;
|
||||
|
||||
let len = layout
|
||||
.size
|
||||
.checked_mul(count, self)
|
||||
.ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?;
|
||||
|
||||
let bytes = std::iter::repeat(byte).take(len.bytes_usize());
|
||||
self.memory.write_bytes(dst, bytes)
|
||||
}
|
||||
|
||||
pub(crate) fn raw_eq_intrinsic(
|
||||
&mut self,
|
||||
lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
||||
|
@ -3210,34 +3210,6 @@ impl<'hir> Node<'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hir_id(&self) -> Option<HirId> {
|
||||
match self {
|
||||
Node::Item(Item { def_id, .. })
|
||||
| Node::TraitItem(TraitItem { def_id, .. })
|
||||
| Node::ImplItem(ImplItem { def_id, .. })
|
||||
| Node::ForeignItem(ForeignItem { def_id, .. }) => Some(HirId::make_owner(*def_id)),
|
||||
Node::Field(FieldDef { hir_id, .. })
|
||||
| Node::AnonConst(AnonConst { hir_id, .. })
|
||||
| Node::Expr(Expr { hir_id, .. })
|
||||
| Node::Stmt(Stmt { hir_id, .. })
|
||||
| Node::Ty(Ty { hir_id, .. })
|
||||
| Node::Binding(Pat { hir_id, .. })
|
||||
| Node::Pat(Pat { hir_id, .. })
|
||||
| Node::Arm(Arm { hir_id, .. })
|
||||
| Node::Block(Block { hir_id, .. })
|
||||
| Node::Local(Local { hir_id, .. })
|
||||
| Node::Lifetime(Lifetime { hir_id, .. })
|
||||
| Node::Param(Param { hir_id, .. })
|
||||
| Node::Infer(InferArg { hir_id, .. })
|
||||
| Node::GenericParam(GenericParam { hir_id, .. }) => Some(*hir_id),
|
||||
Node::TraitRef(TraitRef { hir_ref_id, .. }) => Some(*hir_ref_id),
|
||||
Node::PathSegment(PathSegment { hir_id, .. }) => *hir_id,
|
||||
Node::Variant(Variant { id, .. }) => Some(*id),
|
||||
Node::Ctor(variant) => variant.ctor_hir_id(),
|
||||
Node::Crate(_) | Node::Visibility(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Constness::Const` when this node is a const fn/impl/item.
|
||||
pub fn constness_for_typeck(&self) -> Constness {
|
||||
match self {
|
||||
|
@ -22,9 +22,7 @@ use ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_errors::{
|
||||
add_elided_lifetime_in_path_suggestion, struct_span_err, Applicability, SuggestionStyle,
|
||||
};
|
||||
use rustc_errors::{struct_span_err, Applicability, SuggestionStyle};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{CrateNum, DefId};
|
||||
@ -670,23 +668,6 @@ pub trait LintContext: Sized {
|
||||
) => {
|
||||
db.span_note(span_def, "the macro is defined here");
|
||||
}
|
||||
BuiltinLintDiagnostics::ElidedLifetimesInPaths(
|
||||
n,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_span,
|
||||
anon_lts,
|
||||
) => {
|
||||
add_elided_lifetime_in_path_suggestion(
|
||||
sess.source_map(),
|
||||
&mut db,
|
||||
n,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_span,
|
||||
anon_lts,
|
||||
);
|
||||
}
|
||||
BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
|
||||
db.span_suggestion(span, ¬e, sugg, Applicability::MaybeIncorrect);
|
||||
}
|
||||
|
@ -289,7 +289,6 @@ pub enum BuiltinLintDiagnostics {
|
||||
AbsPathWithModule(Span),
|
||||
ProcMacroDeriveResolutionFallback(Span),
|
||||
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
|
||||
ElidedLifetimesInPaths(usize, Span, bool, Span, String),
|
||||
UnknownCrateTypes(Span, String, String),
|
||||
UnusedImports(String, Vec<(Span, String)>),
|
||||
RedundantImport(Vec<(Span, bool)>, Ident),
|
||||
|
@ -2115,6 +2115,11 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
||||
})
|
||||
.map(|(formatter, span)| (*span, formatter(name)))
|
||||
.collect();
|
||||
if spans_suggs.is_empty() {
|
||||
// If all the spans come from macros, we cannot extract snippets and then
|
||||
// `formatters` only contains None and `spans_suggs` is empty.
|
||||
return;
|
||||
}
|
||||
err.multipart_suggestion_verbose(
|
||||
&format!(
|
||||
"consider using the `{}` lifetime",
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use crate::spec::Target;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use std::fmt;
|
||||
|
||||
@ -70,6 +71,22 @@ impl AArch64InlineAsmRegClass {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reserved_x18(
|
||||
_arch: InlineAsmArch,
|
||||
_has_feature: impl FnMut(&str) -> bool,
|
||||
target: &Target,
|
||||
) -> Result<(), &'static str> {
|
||||
if target.os == "android"
|
||||
|| target.is_like_fuchsia
|
||||
|| target.is_like_osx
|
||||
|| target.is_like_windows
|
||||
{
|
||||
Err("x18 is a reserved register on this target")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
AArch64 AArch64InlineAsmReg AArch64InlineAsmRegClass {
|
||||
x0: reg = ["x0", "w0"],
|
||||
@ -90,6 +107,7 @@ def_regs! {
|
||||
x15: reg = ["x15", "w15"],
|
||||
x16: reg = ["x16", "w16"],
|
||||
x17: reg = ["x17", "w17"],
|
||||
x18: reg = ["x18", "w18"] % reserved_x18,
|
||||
x20: reg = ["x20", "w20"],
|
||||
x21: reg = ["x21", "w21"],
|
||||
x22: reg = ["x22", "w22"],
|
||||
@ -149,8 +167,6 @@ def_regs! {
|
||||
p14: preg = ["p14"],
|
||||
p15: preg = ["p15"],
|
||||
ffr: preg = ["ffr"],
|
||||
#error = ["x18", "w18"] =>
|
||||
"x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm",
|
||||
#error = ["x19", "w19"] =>
|
||||
"x19 is used internally by LLVM and cannot be used as an operand for inline asm",
|
||||
#error = ["x29", "w29", "fp", "wfp"] =>
|
||||
|
@ -99,6 +99,22 @@ fn not_thumb1(
|
||||
}
|
||||
}
|
||||
|
||||
fn reserved_r9(
|
||||
arch: InlineAsmArch,
|
||||
mut has_feature: impl FnMut(&str) -> bool,
|
||||
target: &Target,
|
||||
) -> Result<(), &'static str> {
|
||||
not_thumb1(arch, &mut has_feature, target)?;
|
||||
|
||||
// We detect this using the reserved-r9 feature instead of using the target
|
||||
// because the relocation model can be changed with compiler options.
|
||||
if has_feature("reserved-r9") {
|
||||
Err("the RWPI static base register (r9) cannot be used as an operand for inline asm")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
Arm ArmInlineAsmReg ArmInlineAsmRegClass {
|
||||
r0: reg = ["r0", "a1"],
|
||||
@ -109,6 +125,7 @@ def_regs! {
|
||||
r5: reg = ["r5", "v2"],
|
||||
r7: reg = ["r7", "v4"] % frame_pointer_r7,
|
||||
r8: reg = ["r8", "v5"] % not_thumb1,
|
||||
r9: reg = ["r9", "v6", "rfp"] % reserved_r9,
|
||||
r10: reg = ["r10", "sl"] % not_thumb1,
|
||||
r11: reg = ["r11", "fp"] % frame_pointer_r11,
|
||||
r12: reg = ["r12", "ip"] % not_thumb1,
|
||||
@ -195,8 +212,6 @@ def_regs! {
|
||||
q15: qreg = ["q15"],
|
||||
#error = ["r6", "v3"] =>
|
||||
"r6 is used internally by LLVM and cannot be used as an operand for inline asm",
|
||||
#error = ["r9", "v6", "rfp"] =>
|
||||
"r9 is used internally by LLVM and cannot be used as an operand for inline asm",
|
||||
#error = ["r13", "sp"] =>
|
||||
"the stack pointer cannot be used as an operand for inline asm",
|
||||
#error = ["r15", "pc"] =>
|
||||
|
@ -785,6 +785,7 @@ pub enum InlineAsmClobberAbi {
|
||||
X86_64SysV,
|
||||
Arm,
|
||||
AArch64,
|
||||
AArch64NoX18,
|
||||
RiscV,
|
||||
}
|
||||
|
||||
@ -793,6 +794,7 @@ impl InlineAsmClobberAbi {
|
||||
/// clobber ABIs for the target.
|
||||
pub fn parse(
|
||||
arch: InlineAsmArch,
|
||||
has_feature: impl FnMut(&str) -> bool,
|
||||
target: &Target,
|
||||
name: Symbol,
|
||||
) -> Result<Self, &'static [&'static str]> {
|
||||
@ -816,7 +818,13 @@ impl InlineAsmClobberAbi {
|
||||
_ => Err(&["C", "system", "efiapi", "aapcs"]),
|
||||
},
|
||||
InlineAsmArch::AArch64 => match name {
|
||||
"C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::AArch64),
|
||||
"C" | "system" | "efiapi" => {
|
||||
Ok(if aarch64::reserved_x18(arch, has_feature, target).is_err() {
|
||||
InlineAsmClobberAbi::AArch64NoX18
|
||||
} else {
|
||||
InlineAsmClobberAbi::AArch64
|
||||
})
|
||||
}
|
||||
_ => Err(&["C", "system", "efiapi"]),
|
||||
},
|
||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
|
||||
@ -891,8 +899,25 @@ impl InlineAsmClobberAbi {
|
||||
AArch64 AArch64InlineAsmReg {
|
||||
x0, x1, x2, x3, x4, x5, x6, x7,
|
||||
x8, x9, x10, x11, x12, x13, x14, x15,
|
||||
// x18 is platform-reserved or temporary, but we exclude it
|
||||
// here since it is a reserved register.
|
||||
x16, x17, x18, 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, v17, v18, v19, v20, v21, v22, v23,
|
||||
v24, v25, v26, v27, v28, v29, v30, v31,
|
||||
|
||||
p0, p1, p2, p3, p4, p5, p6, p7,
|
||||
p8, p9, p10, p11, p12, p13, p14, p15,
|
||||
ffr,
|
||||
|
||||
}
|
||||
},
|
||||
InlineAsmClobberAbi::AArch64NoX18 => clobbered_regs! {
|
||||
AArch64 AArch64InlineAsmReg {
|
||||
x0, x1, x2, x3, x4, x5, x6, x7,
|
||||
x8, x9, x10, x11, x12, x13, x14, x15,
|
||||
x16, x17, x30,
|
||||
|
||||
// Technically the low 64 bits of v8-v15 are preserved, but
|
||||
@ -910,7 +935,8 @@ impl InlineAsmClobberAbi {
|
||||
},
|
||||
InlineAsmClobberAbi::Arm => clobbered_regs! {
|
||||
Arm ArmInlineAsmReg {
|
||||
// r9 is platform-reserved and is treated as callee-saved.
|
||||
// r9 is either platform-reserved or callee-saved. Either
|
||||
// way we don't need to clobber it.
|
||||
r0, r1, r2, r3, r12, r14,
|
||||
|
||||
// The finest-grained register variant is used here so that
|
||||
|
@ -128,10 +128,6 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
|
||||
|
||||
let iter = mem::replace(&mut self.iter, (&mut []).iter());
|
||||
let drop_len = iter.len();
|
||||
let drop_ptr = iter.as_slice().as_ptr();
|
||||
|
||||
// forget iter so there's no aliasing reference
|
||||
drop(iter);
|
||||
|
||||
let mut vec = self.vec;
|
||||
|
||||
@ -155,6 +151,12 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
|
||||
return;
|
||||
}
|
||||
|
||||
// as_slice() must only be called when iter.len() is > 0 because
|
||||
// vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate
|
||||
// the iterator's internal pointers. Creating a reference to deallocated memory
|
||||
// is invalid even when it is zero-length
|
||||
let drop_ptr = iter.as_slice().as_ptr();
|
||||
|
||||
unsafe {
|
||||
// drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place
|
||||
// a pointer with mutable provenance is necessary. Therefore we must reconstruct
|
||||
|
@ -2244,13 +2244,29 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
||||
/// assert_eq!(*v, 42);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
|
||||
#[inline]
|
||||
pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
|
||||
pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
|
||||
extern "rust-intrinsic" {
|
||||
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
|
||||
fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
|
||||
}
|
||||
|
||||
debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
|
||||
#[cfg(debug_assertions)]
|
||||
fn runtime_check<T>(ptr: *mut T) {
|
||||
debug_assert!(
|
||||
is_aligned_and_not_null(ptr),
|
||||
"attempt to write to unaligned or null pointer"
|
||||
);
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
const fn compiletime_check<T>(_ptr: *mut T) {}
|
||||
#[cfg(debug_assertions)]
|
||||
// SAFETY: runtime debug-assertions are a best-effort basis; it's fine to
|
||||
// not do them during compile time
|
||||
unsafe {
|
||||
const_eval_select((dst,), compiletime_check, runtime_check);
|
||||
}
|
||||
|
||||
// SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
|
||||
unsafe { write_bytes(dst, val, count) }
|
||||
|
@ -124,6 +124,7 @@
|
||||
#![feature(const_option)]
|
||||
#![feature(const_pin)]
|
||||
#![feature(const_replace)]
|
||||
#![feature(const_ptr_is_null)]
|
||||
#![feature(const_ptr_offset)]
|
||||
#![feature(const_ptr_offset_from)]
|
||||
#![feature(const_ptr_read)]
|
||||
|
@ -1671,7 +1671,8 @@ impl<T, E> Option<Result<T, E>> {
|
||||
}
|
||||
|
||||
// This is a separate function to reduce the code size of .expect() itself.
|
||||
#[inline(never)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[cold]
|
||||
#[track_caller]
|
||||
const fn expect_failed(msg: &str) -> ! {
|
||||
|
@ -92,7 +92,7 @@ impl<T: ?Sized> Unique<T> {
|
||||
|
||||
/// Creates a new `Unique` if `ptr` is non-null.
|
||||
#[inline]
|
||||
pub fn new(ptr: *mut T) -> Option<Self> {
|
||||
pub const fn new(ptr: *mut T) -> Option<Self> {
|
||||
if !ptr.is_null() {
|
||||
// SAFETY: The pointer has already been checked and is not null.
|
||||
Some(unsafe { Unique { pointer: ptr as _, _marker: PhantomData } })
|
||||
@ -115,7 +115,7 @@ impl<T: ?Sized> Unique<T> {
|
||||
/// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub unsafe fn as_ref(&self) -> &T {
|
||||
pub const unsafe fn as_ref(&self) -> &T {
|
||||
// SAFETY: the caller must guarantee that `self` meets all the
|
||||
// requirements for a reference.
|
||||
unsafe { &*self.as_ptr() }
|
||||
@ -128,7 +128,7 @@ impl<T: ?Sized> Unique<T> {
|
||||
/// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub unsafe fn as_mut(&mut self) -> &mut T {
|
||||
pub const unsafe fn as_mut(&mut self) -> &mut T {
|
||||
// SAFETY: the caller must guarantee that `self` meets all the
|
||||
// requirements for a mutable reference.
|
||||
unsafe { &mut *self.as_ptr() }
|
||||
|
@ -1653,6 +1653,7 @@ impl<T> Result<T, T> {
|
||||
}
|
||||
|
||||
// This is a separate function to reduce the code size of the methods
|
||||
#[cfg(not(feature = "panic_immediate_abort"))]
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
#[track_caller]
|
||||
@ -1660,6 +1661,18 @@ fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
|
||||
panic!("{}: {:?}", msg, error)
|
||||
}
|
||||
|
||||
// This is a separate function to avoid constructing a `dyn Debug`
|
||||
// that gets immediately thrown away, since vtables don't get cleaned up
|
||||
// by dead code elimination if a trait object is constructed even if it goes
|
||||
// unused
|
||||
#[cfg(feature = "panic_immediate_abort")]
|
||||
#[inline]
|
||||
#[cold]
|
||||
#[track_caller]
|
||||
fn unwrap_failed<T>(_msg: &str, _error: &T) -> ! {
|
||||
panic!()
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Trait implementations
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -27,35 +27,40 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[cold]
|
||||
#[track_caller]
|
||||
fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
|
||||
panic!("range start index {} out of range for slice of length {}", index, len);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[cold]
|
||||
#[track_caller]
|
||||
fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
|
||||
panic!("range end index {} out of range for slice of length {}", index, len);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[cold]
|
||||
#[track_caller]
|
||||
fn slice_index_order_fail(index: usize, end: usize) -> ! {
|
||||
panic!("slice index starts at {} but ends at {}", index, end);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[cold]
|
||||
#[track_caller]
|
||||
fn slice_start_index_overflow_fail() -> ! {
|
||||
panic!("attempted to index slice from after maximum usize");
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[cold]
|
||||
#[track_caller]
|
||||
fn slice_end_index_overflow_fail() -> ! {
|
||||
|
@ -35,3 +35,33 @@ fn test_assume_can_be_in_const_contexts() {
|
||||
let rs = unsafe { foo(42, 97) };
|
||||
assert_eq!(rs, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(bootstrap))]
|
||||
const fn test_write_bytes_in_const_contexts() {
|
||||
use core::intrinsics::write_bytes;
|
||||
|
||||
const TEST: [u32; 3] = {
|
||||
let mut arr = [1u32, 2, 3];
|
||||
unsafe {
|
||||
write_bytes(arr.as_mut_ptr(), 0, 2);
|
||||
}
|
||||
arr
|
||||
};
|
||||
|
||||
assert!(TEST[0] == 0);
|
||||
assert!(TEST[1] == 0);
|
||||
assert!(TEST[2] == 3);
|
||||
|
||||
const TEST2: [u32; 3] = {
|
||||
let mut arr = [1u32, 2, 3];
|
||||
unsafe {
|
||||
write_bytes(arr.as_mut_ptr(), 1, 2);
|
||||
}
|
||||
arr
|
||||
};
|
||||
|
||||
assert!(TEST2[0] == 16843009);
|
||||
assert!(TEST2[1] == 16843009);
|
||||
assert!(TEST2[2] == 3);
|
||||
}
|
||||
|
21
src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs
Normal file
21
src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs
Normal file
@ -0,0 +1,21 @@
|
||||
//! Test case for [#78160].
|
||||
//!
|
||||
//! A SomeTrait that is implemented for `&mut T` should not be marked as
|
||||
//! "notable" for return values that are `&T`.
|
||||
//!
|
||||
//! [#78160]: https://github.com/rust-lang/rust/issues/78160
|
||||
|
||||
#![feature(rustdoc_internals)]
|
||||
|
||||
#[doc(primitive = "reference")]
|
||||
/// Some useless docs, wouhou!
|
||||
///
|
||||
/// We need to put this in here, because notable traits
|
||||
/// that are implemented on foreign types don't show up.
|
||||
mod reference {}
|
||||
|
||||
// @has doc_notable_trait_mut_t_is_not_ref_t/fn.fn_no_matches.html
|
||||
// @!has - '//code[@class="content"]' "impl<'_, I> Iterator for &'_ mut I"
|
||||
pub fn fn_no_matches<'a, T: Iterator + 'a>() -> &'a T {
|
||||
loop {}
|
||||
}
|
@ -29,8 +29,6 @@ fn main() {
|
||||
//~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand
|
||||
asm!("", in("xzr") foo);
|
||||
//~^ ERROR invalid register `xzr`: the zero register cannot be used as an operand
|
||||
asm!("", in("x18") foo);
|
||||
//~^ ERROR invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm
|
||||
asm!("", in("x19") foo);
|
||||
//~^ ERROR invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm
|
||||
|
||||
|
@ -74,38 +74,32 @@ error: invalid register `xzr`: the zero register cannot be used as an operand fo
|
||||
LL | asm!("", in("xzr") foo);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm
|
||||
--> $DIR/bad-reg.rs:32:18
|
||||
|
|
||||
LL | asm!("", in("x18") foo);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm
|
||||
--> $DIR/bad-reg.rs:34:18
|
||||
--> $DIR/bad-reg.rs:32:18
|
||||
|
|
||||
LL | asm!("", in("x19") foo);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: register class `preg` can only be used as a clobber, not as an input or output
|
||||
--> $DIR/bad-reg.rs:37:18
|
||||
--> $DIR/bad-reg.rs:35:18
|
||||
|
|
||||
LL | asm!("", in("p0") foo);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: register class `preg` can only be used as a clobber, not as an input or output
|
||||
--> $DIR/bad-reg.rs:40:20
|
||||
--> $DIR/bad-reg.rs:38:20
|
||||
|
|
||||
LL | asm!("{}", in(preg) foo);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: register class `preg` can only be used as a clobber, not as an input or output
|
||||
--> $DIR/bad-reg.rs:42:20
|
||||
--> $DIR/bad-reg.rs:40:20
|
||||
|
|
||||
LL | asm!("{}", out(preg) _);
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: register `x0` conflicts with register `x0`
|
||||
--> $DIR/bad-reg.rs:48:32
|
||||
--> $DIR/bad-reg.rs:46:32
|
||||
|
|
||||
LL | asm!("", in("x0") foo, in("w0") bar);
|
||||
| ------------ ^^^^^^^^^^^^ register `x0`
|
||||
@ -113,7 +107,7 @@ LL | asm!("", in("x0") foo, in("w0") bar);
|
||||
| register `x0`
|
||||
|
||||
error: register `x0` conflicts with register `x0`
|
||||
--> $DIR/bad-reg.rs:50:32
|
||||
--> $DIR/bad-reg.rs:48:32
|
||||
|
|
||||
LL | asm!("", in("x0") foo, out("x0") bar);
|
||||
| ------------ ^^^^^^^^^^^^^ register `x0`
|
||||
@ -121,13 +115,13 @@ LL | asm!("", in("x0") foo, out("x0") bar);
|
||||
| register `x0`
|
||||
|
|
||||
help: use `lateout` instead of `out` to avoid conflict
|
||||
--> $DIR/bad-reg.rs:50:18
|
||||
--> $DIR/bad-reg.rs:48:18
|
||||
|
|
||||
LL | asm!("", in("x0") foo, out("x0") bar);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: register `v0` conflicts with register `v0`
|
||||
--> $DIR/bad-reg.rs:53:32
|
||||
--> $DIR/bad-reg.rs:51:32
|
||||
|
|
||||
LL | asm!("", in("v0") foo, in("q0") bar);
|
||||
| ------------ ^^^^^^^^^^^^ register `v0`
|
||||
@ -135,7 +129,7 @@ LL | asm!("", in("v0") foo, in("q0") bar);
|
||||
| register `v0`
|
||||
|
||||
error: register `v0` conflicts with register `v0`
|
||||
--> $DIR/bad-reg.rs:55:32
|
||||
--> $DIR/bad-reg.rs:53:32
|
||||
|
|
||||
LL | asm!("", in("v0") foo, out("q0") bar);
|
||||
| ------------ ^^^^^^^^^^^^^ register `v0`
|
||||
@ -143,10 +137,10 @@ LL | asm!("", in("v0") foo, out("q0") bar);
|
||||
| register `v0`
|
||||
|
|
||||
help: use `lateout` instead of `out` to avoid conflict
|
||||
--> $DIR/bad-reg.rs:55:18
|
||||
--> $DIR/bad-reg.rs:53:18
|
||||
|
|
||||
LL | asm!("", in("v0") foo, out("q0") bar);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 19 previous errors
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
|
47
src/test/ui/lifetimes/auxiliary/issue-91763-aux.rs
Normal file
47
src/test/ui/lifetimes/auxiliary/issue-91763-aux.rs
Normal file
@ -0,0 +1,47 @@
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
//#![feature(proc_macro_diagnostic, proc_macro_span, proc_macro_def_site)]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn repro(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let call_site = Span::call_site();
|
||||
let span = input.into_iter().nth(8).unwrap().span();
|
||||
|
||||
//fn f(_: &::std::fmt::Formatter) {}
|
||||
TokenStream::from_iter([
|
||||
TokenTree::Ident(Ident::new("fn", call_site)),
|
||||
TokenTree::Ident(Ident::new("f", call_site)),
|
||||
TokenTree::Group(Group::new(
|
||||
Delimiter::Parenthesis,
|
||||
TokenStream::from_iter([
|
||||
TokenTree::Ident(Ident::new("_", call_site)),
|
||||
TokenTree::Punct(punct(':', Spacing::Alone, call_site)),
|
||||
TokenTree::Punct(punct('&', Spacing::Alone, call_site)),
|
||||
TokenTree::Punct(punct(':', Spacing::Joint, span)),
|
||||
TokenTree::Punct(punct(':', Spacing::Alone, span)),
|
||||
TokenTree::Ident(Ident::new("std", span)),
|
||||
TokenTree::Punct(punct(':', Spacing::Joint, span)),
|
||||
TokenTree::Punct(punct(':', Spacing::Alone, span)),
|
||||
TokenTree::Ident(Ident::new("fmt", span)),
|
||||
TokenTree::Punct(punct(':', Spacing::Joint, span)),
|
||||
TokenTree::Punct(punct(':', Spacing::Alone, span)),
|
||||
TokenTree::Ident(Ident::new("Formatter", span)),
|
||||
]),
|
||||
)),
|
||||
TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
|
||||
])
|
||||
}
|
||||
|
||||
fn punct(ch: char, spacing: Spacing, span: Span) -> Punct {
|
||||
let mut punct = Punct::new(ch, spacing);
|
||||
punct.set_span(span);
|
||||
punct
|
||||
}
|
11
src/test/ui/lifetimes/issue-91763.rs
Normal file
11
src/test/ui/lifetimes/issue-91763.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// aux-build:issue-91763-aux.rs
|
||||
|
||||
#![deny(elided_lifetimes_in_paths)]
|
||||
|
||||
extern crate issue_91763_aux;
|
||||
|
||||
#[issue_91763_aux::repro]
|
||||
fn f() -> Ptr<Thing>;
|
||||
//~^ ERROR hidden lifetime parameters in types are deprecated
|
||||
|
||||
fn main() {}
|
14
src/test/ui/lifetimes/issue-91763.stderr
Normal file
14
src/test/ui/lifetimes/issue-91763.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error: hidden lifetime parameters in types are deprecated
|
||||
--> $DIR/issue-91763.rs:8:20
|
||||
|
|
||||
LL | fn f() -> Ptr<Thing>;
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-91763.rs:3:9
|
||||
|
|
||||
LL | #![deny(elided_lifetimes_in_paths)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
x
Reference in New Issue
Block a user