diff options
142 files changed, 2623 insertions, 1033 deletions
diff --git a/Cargo.lock b/Cargo.lock index 93d3d118778..9cca91c25df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3273,7 +3273,6 @@ name = "rustc_ast_lowering" version = "0.0.0" dependencies = [ "rustc_ast", - "rustc_ast_pretty", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -3468,7 +3467,6 @@ dependencies = [ "rustc_macros", "rustc_metadata", "rustc_middle", - "rustc_monomorphize", "rustc_query_system", "rustc_serialize", "rustc_session", @@ -3744,7 +3742,6 @@ dependencies = [ "rustc_feature", "rustc_fluent_macro", "rustc_hir", - "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_lint_defs", @@ -3792,7 +3789,6 @@ dependencies = [ "rustc_middle", "rustc_session", "rustc_span", - "rustc_target", "rustc_trait_selection", "rustc_type_ir", "smallvec", @@ -3852,9 +3848,7 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_middle", - "rustc_next_trait_solver", "rustc_span", - "rustc_target", "rustc_type_ir", "smallvec", "thin-vec", @@ -3933,7 +3927,6 @@ dependencies = [ "rustc_feature", "rustc_fluent_macro", "rustc_hir", - "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_macros", @@ -4161,7 +4154,6 @@ dependencies = [ name = "rustc_next_trait_solver" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", "derive-where", "rustc_ast_ir", "rustc_data_structures", @@ -4457,9 +4449,7 @@ dependencies = [ "object 0.36.4", "rustc_abi", "rustc_data_structures", - "rustc_feature", "rustc_fs_util", - "rustc_index", "rustc_macros", "rustc_serialize", "rustc_span", @@ -4491,8 +4481,6 @@ dependencies = [ "rustc_middle", "rustc_next_trait_solver", "rustc_parse_format", - "rustc_query_system", - "rustc_serialize", "rustc_session", "rustc_span", "rustc_transmute", diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index e9a7397557e..ccf88d8ff4b 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -1,5 +1,7 @@ // We need this feature as it changes `dylib` linking behavior and allows us to link to `rustc_driver`. #![feature(rustc_private)] +// Several crates are depended upon but unused so that they are present in the sysroot +#![expect(unused_crate_dependencies)] // A note about jemalloc: rustc uses jemalloc when built for CI and // distribution. The obvious way to do this is with the `#[global_allocator]` diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 8cc4521e0a7..c47c12b4fd1 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -9,7 +9,6 @@ doctest = false [dependencies] # tidy-alphabetical-start rustc_ast = { path = "../rustc_ast" } -rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 42c7f5f0dc6..3da215fe6c0 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -616,25 +616,70 @@ pub union MaybeUninit<T> { } pub mod intrinsics { - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; - #[rustc_safe_intrinsic] - pub fn size_of<T>() -> usize; - pub fn size_of_val<T: ?::Sized>(val: *const T) -> usize; - #[rustc_safe_intrinsic] - pub fn min_align_of<T>() -> usize; - pub fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize; - pub fn copy<T>(src: *const T, dst: *mut T, count: usize); - pub fn transmute<T, U>(e: T) -> U; - pub fn ctlz_nonzero<T>(x: T) -> u32; - #[rustc_safe_intrinsic] - pub fn needs_drop<T: ?::Sized>() -> bool; - #[rustc_safe_intrinsic] - pub fn bitreverse<T>(x: T) -> T; - #[rustc_safe_intrinsic] - pub fn bswap<T>(x: T) -> T; - pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize); + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn size_of<T>() -> usize { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn size_of_val<T: ?::Sized>(_val: *const T) -> usize { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn min_align_of<T>() -> usize { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn min_align_of_val<T: ?::Sized>(_val: *const T) -> usize { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn copy<T>(_src: *const T, _dst: *mut T, _count: usize) { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn transmute<T, U>(_e: T) -> U { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn ctlz_nonzero<T>(_x: T) -> u32 { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn needs_drop<T: ?::Sized>() -> bool { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn bitreverse<T>(_x: T) -> T { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn bswap<T>(_x: T) -> T { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn write_bytes<T>(_dst: *mut T, _val: u8, _count: usize) { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn unreachable() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index e5a12162687..1e2e41b3122 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1,4 +1,4 @@ -//! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, `extern "platform-intrinsic"` +//! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, //! and LLVM intrinsics that have symbol names starting with `llvm.`. macro_rules! intrinsic_args { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 16fb68a7bdf..36a35d42c3e 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -1,4 +1,4 @@ -//! Codegen `extern "platform-intrinsic"` intrinsics. +//! Codegen SIMD intrinsics. use cranelift_codegen::ir::immediates::Offset32; use rustc_target::abi::Endian; diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 0576b64ef6f..c887598f6e9 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -579,28 +579,70 @@ pub union MaybeUninit<T> { } pub mod intrinsics { - use crate::Sized; - - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; - #[rustc_safe_intrinsic] - pub fn size_of<T>() -> usize; - pub fn size_of_val<T: ?Sized>(val: *const T) -> usize; - #[rustc_safe_intrinsic] - pub fn min_align_of<T>() -> usize; - pub fn min_align_of_val<T: ?Sized>(val: *const T) -> usize; - pub fn copy<T>(src: *const T, dst: *mut T, count: usize); - pub fn transmute<T, U>(e: T) -> U; - pub fn ctlz_nonzero<T>(x: T) -> u32; - #[rustc_safe_intrinsic] - pub fn needs_drop<T: ?Sized>() -> bool; - #[rustc_safe_intrinsic] - pub fn bitreverse<T>(x: T) -> T; - #[rustc_safe_intrinsic] - pub fn bswap<T>(x: T) -> T; - pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize); - pub fn unreachable() -> !; + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn size_of<T>() -> usize { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn size_of_val<T: ?::Sized>(_val: *const T) -> usize { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn min_align_of<T>() -> usize { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn min_align_of_val<T: ?::Sized>(_val: *const T) -> usize { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn copy<T>(_src: *const T, _dst: *mut T, _count: usize) { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn transmute<T, U>(_e: T) -> U { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn ctlz_nonzero<T>(_x: T) -> u32 { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn needs_drop<T: ?::Sized>() -> bool { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn bitreverse<T>(_x: T) -> T { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn bswap<T>(_x: T) -> T { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn write_bytes<T>(_dst: *mut T, _val: u8, _count: usize) { + loop {} + } + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub unsafe fn unreachable() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index 0cee05f1cea..82e98370b37 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -2,6 +2,7 @@ use std::path::Path; use rustc_codegen_ssa::back::archive::{ ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, + ImportLibraryItem, }; use rustc_session::Session; @@ -16,7 +17,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { &self, _sess: &Session, _lib_name: &str, - _import_name_and_ordinal_vector: Vec<(String, Option<u16>)>, + _items: Vec<ImportLibraryItem>, _output_path: &Path, ) { unimplemented!("creating dll imports is not yet supported"); diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index b44d4aa8cc8..6b067b35e71 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -688,6 +688,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { ) => { unreachable!("clobber-only") } + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"), InlineAsmRegClass::Err => unreachable!(), }, }; @@ -767,6 +769,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => { unreachable!("clobber-only") } + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"), InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), @@ -946,6 +950,7 @@ fn modifier_to_gcc( }, InlineAsmRegClass::Avr(_) => None, InlineAsmRegClass::S390x(_) => None, + InlineAsmRegClass::Sparc(_) => None, InlineAsmRegClass::Msp430(_) => None, InlineAsmRegClass::M68k(_) => None, InlineAsmRegClass::CSKY(_) => None, diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs index 44297e12779..696197d7377 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs @@ -33,9 +33,11 @@ pub(crate) unsafe auto trait Freeze {} mod intrinsics { use super::Sized; - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs index ce816927123..714cd6c0f38 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs @@ -33,9 +33,11 @@ pub(crate) unsafe auto trait Freeze {} mod intrinsics { use super::Sized; - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs index 432f11ad8d4..d8de9f28d4c 100644 --- a/compiler/rustc_codegen_gcc/tests/run/array.rs +++ b/compiler/rustc_codegen_gcc/tests/run/array.rs @@ -106,9 +106,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { } mod intrinsics { - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs index e105d64a8ad..2a47f0c2966 100644 --- a/compiler/rustc_codegen_gcc/tests/run/assign.rs +++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs @@ -56,9 +56,11 @@ mod libc { } mod intrinsics { - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs index 00e61cc001f..b0d0ca4ee8d 100644 --- a/compiler/rustc_codegen_gcc/tests/run/closure.rs +++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs @@ -98,9 +98,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { } mod intrinsics { - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs index 7b05b7decd3..770b18a89e3 100644 --- a/compiler/rustc_codegen_gcc/tests/run/condition.rs +++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs @@ -109,9 +109,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { } mod intrinsics { - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs index 4e96f376555..523544ee6bb 100644 --- a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs +++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs @@ -103,9 +103,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { } mod intrinsics { - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs index 5a3f72b6904..3ae79338216 100644 --- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs +++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs @@ -58,9 +58,11 @@ mod libc { } mod intrinsics { - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs index d697bd921cd..2e3c021d5f7 100644 --- a/compiler/rustc_codegen_gcc/tests/run/operations.rs +++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs @@ -64,9 +64,11 @@ mod libc { } mod intrinsics { - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs index a94279182d6..c7510d16449 100644 --- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs +++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs @@ -103,9 +103,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { } mod intrinsics { - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs index e86fc823a1a..35ad594ecde 100644 --- a/compiler/rustc_codegen_gcc/tests/run/slice.rs +++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs @@ -103,9 +103,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { mod intrinsics { use super::Sized; - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs index 6247e08f5e3..a17ea2a4893 100644 --- a/compiler/rustc_codegen_gcc/tests/run/static.rs +++ b/compiler/rustc_codegen_gcc/tests/run/static.rs @@ -46,9 +46,11 @@ pub(crate) unsafe auto trait Freeze {} mod intrinsics { use super::Sized; - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn abort() -> !; + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + pub fn abort() -> ! { + loop {} } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index a1ccf0d1719..bb74dfe1487 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -268,6 +268,15 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { InlineAsmArch::S390x => { constraints.push("~{cc}".to_string()); } + InlineAsmArch::Sparc | InlineAsmArch::Sparc64 => { + // In LLVM, ~{icc} represents icc and xcc in 64-bit code. + // https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/SparcRegisterInfo.td#L64 + constraints.push("~{icc}".to_string()); + constraints.push("~{fcc0}".to_string()); + constraints.push("~{fcc1}".to_string()); + constraints.push("~{fcc2}".to_string()); + constraints.push("~{fcc3}".to_string()); + } InlineAsmArch::SpirV => {} InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {} InlineAsmArch::Bpf => {} @@ -672,6 +681,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => { unreachable!("clobber-only") } + Sparc(SparcInlineAsmRegClass::reg) => "r", + Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"), Msp430(Msp430InlineAsmRegClass::reg) => "r", M68k(M68kInlineAsmRegClass::reg) => "r", M68k(M68kInlineAsmRegClass::reg_addr) => "a", @@ -765,6 +776,7 @@ fn modifier_to_llvm( }, Avr(_) => None, S390x(_) => None, + Sparc(_) => None, Msp430(_) => None, SpirV(SpirVInlineAsmRegClass::reg) => bug!("LLVM backend does not support SPIR-V"), M68k(_) => None, @@ -835,6 +847,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => { unreachable!("clobber-only") } + Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(), + Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"), Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 25037b97375..dcea9d3b391 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -44,6 +44,22 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t let llfn = if tcx.sess.target.arch == "x86" && let Some(dllimport) = crate::common::get_dllimport(tcx, instance_def_id, sym) { + // When calling functions in generated import libraries, MSVC needs + // the fully decorated name (as would have been in the declaring + // object file), but MinGW wants the name as exported (as would be + // in the def file) which may be missing decorations. + let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&tcx.sess.target); + let llfn = cx.declare_fn( + &common::i686_decorated_name( + dllimport, + mingw_gnu_toolchain, + true, + !mingw_gnu_toolchain, + ), + fn_abi, + Some(instance), + ); + // Fix for https://github.com/rust-lang/rust/issues/104453 // On x86 Windows, LLVM uses 'L' as the prefix for any private // global symbols, so when we create an undecorated function symbol @@ -55,15 +71,6 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t // LLVM will prefix the name with `__imp_`. Ideally, we'd like the // existing logic below to set the Storage Class, but it has an // exemption for MinGW for backwards compatibility. - let llfn = cx.declare_fn( - &common::i686_decorated_name( - dllimport, - common::is_mingw_gnu_toolchain(&tcx.sess.target), - true, - ), - fn_abi, - Some(instance), - ); unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index bed64686a23..7ab4f45cd73 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -194,16 +194,10 @@ fn check_and_apply_linkage<'ll, 'tcx>( unsafe { llvm::LLVMSetInitializer(g2, g1) }; g2 } else if cx.tcx.sess.target.arch == "x86" + && common::is_mingw_gnu_toolchain(&cx.tcx.sess.target) && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym) { - cx.declare_global( - &common::i686_decorated_name( - dllimport, - common::is_mingw_gnu_toolchain(&cx.tcx.sess.target), - true, - ), - llty, - ) + cx.declare_global(&common::i686_decorated_name(dllimport, true, true, false), llty) } else { // Generate an external declaration. // FIXME(nagisa): investigate whether it can be changed into define_global diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index b7ab5d6d5f0..ba863d9d74b 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -154,6 +154,11 @@ pub(crate) unsafe fn create_module<'ll>( // See https://github.com/llvm/llvm-project/pull/106951 target_data_layout = target_data_layout.replace("-i128:128", ""); } + if sess.target.arch.starts_with("mips64") { + // LLVM 20 updates the mips64 layout to correctly align 128 bit integers to 128 bit. + // See https://github.com/llvm/llvm-project/pull/112084 + target_data_layout = target_data_layout.replace("-i128:128", ""); + } } // Ensure the data-layout values hardcoded remain the defaults. diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs new file mode 100644 index 00000000000..99c2d12b261 --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs @@ -0,0 +1,100 @@ +//! Safe wrappers for coverage-specific FFI functions. + +use std::ffi::CString; + +use crate::common::AsCCharPtr; +use crate::coverageinfo::ffi; +use crate::llvm; + +pub(crate) fn covmap_var_name() -> CString { + CString::new(llvm::build_byte_buffer(|s| unsafe { + llvm::LLVMRustCoverageWriteCovmapVarNameToString(s); + })) + .expect("covmap variable name should not contain NUL") +} + +pub(crate) fn covmap_section_name(llmod: &llvm::Module) -> CString { + CString::new(llvm::build_byte_buffer(|s| unsafe { + llvm::LLVMRustCoverageWriteCovmapSectionNameToString(llmod, s); + })) + .expect("covmap section name should not contain NUL") +} + +pub(crate) fn covfun_section_name(llmod: &llvm::Module) -> CString { + CString::new(llvm::build_byte_buffer(|s| unsafe { + llvm::LLVMRustCoverageWriteCovfunSectionNameToString(llmod, s); + })) + .expect("covfun section name should not contain NUL") +} + +pub(crate) fn create_pgo_func_name_var<'ll>( + llfn: &'ll llvm::Value, + mangled_fn_name: &str, +) -> &'ll llvm::Value { + unsafe { + llvm::LLVMRustCoverageCreatePGOFuncNameVar( + llfn, + mangled_fn_name.as_c_char_ptr(), + mangled_fn_name.len(), + ) + } +} + +pub(crate) fn write_filenames_to_buffer<'a>( + filenames: impl IntoIterator<Item = &'a str>, +) -> Vec<u8> { + let (pointers, lengths) = filenames + .into_iter() + .map(|s: &str| (s.as_c_char_ptr(), s.len())) + .unzip::<_, _, Vec<_>, Vec<_>>(); + + llvm::build_byte_buffer(|buffer| unsafe { + llvm::LLVMRustCoverageWriteFilenamesToBuffer( + pointers.as_ptr(), + pointers.len(), + lengths.as_ptr(), + lengths.len(), + buffer, + ); + }) +} + +pub(crate) fn write_function_mappings_to_buffer( + virtual_file_mapping: &[u32], + expressions: &[ffi::CounterExpression], + code_regions: &[ffi::CodeRegion], + branch_regions: &[ffi::BranchRegion], + mcdc_branch_regions: &[ffi::MCDCBranchRegion], + mcdc_decision_regions: &[ffi::MCDCDecisionRegion], +) -> Vec<u8> { + llvm::build_byte_buffer(|buffer| unsafe { + llvm::LLVMRustCoverageWriteFunctionMappingsToBuffer( + virtual_file_mapping.as_ptr(), + virtual_file_mapping.len(), + expressions.as_ptr(), + expressions.len(), + code_regions.as_ptr(), + code_regions.len(), + branch_regions.as_ptr(), + branch_regions.len(), + mcdc_branch_regions.as_ptr(), + mcdc_branch_regions.len(), + mcdc_decision_regions.as_ptr(), + mcdc_decision_regions.len(), + buffer, + ) + }) +} + +/// Hashes some bytes into a 64-bit hash, via LLVM's `IndexedInstrProf::ComputeHash`, +/// as required for parts of the LLVM coverage mapping format. +pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 { + unsafe { llvm::LLVMRustCoverageHashBytes(bytes.as_c_char_ptr(), bytes.len()) } +} + +/// Returns LLVM's `coverage::CovMapVersion::CurrentVersion` (CoverageMapping.h) +/// as a raw numeric value. For historical reasons, the numeric value is 1 less +/// than the number in the version's name, so `Version7` is actually `6u32`. +pub(crate) fn mapping_version() -> u32 { + unsafe { llvm::LLVMRustCoverageMappingVersion() } +} diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index f6378199fe2..bb2f634cb25 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -1,4 +1,5 @@ use std::ffi::CString; +use std::iter; use itertools::Itertools as _; use rustc_abi::Align; @@ -17,9 +18,9 @@ use rustc_target::spec::HasTargetSpec; use tracing::debug; use crate::common::CodegenCx; -use crate::coverageinfo::ffi; use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector}; -use crate::{coverageinfo, llvm}; +use crate::coverageinfo::{ffi, llvm_cov}; +use crate::llvm; /// Generates and exports the coverage map, which is embedded in special /// linker sections in the final binary. @@ -33,7 +34,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { // agrees with our Rust-side code. Expected versions (encoded as n-1) are: // - `CovMapVersion::Version7` (6) used by LLVM 18-19 let covmap_version = { - let llvm_covmap_version = coverageinfo::mapping_version(); + let llvm_covmap_version = llvm_cov::mapping_version(); let expected_versions = 6..=6; assert!( expected_versions.contains(&llvm_covmap_version), @@ -78,7 +79,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { let filenames_size = filenames_buffer.len(); let filenames_val = cx.const_bytes(&filenames_buffer); - let filenames_ref = coverageinfo::hash_bytes(&filenames_buffer); + let filenames_ref = llvm_cov::hash_bytes(&filenames_buffer); // Generate the coverage map header, which contains the filenames used by // this CGU's coverage mappings, and store it in a well-known global. @@ -187,13 +188,10 @@ impl GlobalFileTable { .for_scope(tcx.sess, RemapPathScopeComponents::MACRO) .to_string_lossy(); - llvm::build_byte_buffer(|buffer| { - coverageinfo::write_filenames_section_to_buffer( - // Insert the working dir at index 0, before the other filenames. - std::iter::once(working_dir).chain(self.raw_file_table.iter().map(Symbol::as_str)), - buffer, - ); - }) + // Insert the working dir at index 0, before the other filenames. + let filenames = + iter::once(working_dir).chain(self.raw_file_table.iter().map(Symbol::as_str)); + llvm_cov::write_filenames_to_buffer(filenames) } } @@ -296,17 +294,14 @@ fn encode_mappings_for_function( } // Encode the function's coverage mappings into a buffer. - llvm::build_byte_buffer(|buffer| { - coverageinfo::write_mapping_to_buffer( - virtual_file_mapping.into_vec(), - expressions, - &code_regions, - &branch_regions, - &mcdc_branch_regions, - &mcdc_decision_regions, - buffer, - ); - }) + llvm_cov::write_function_mappings_to_buffer( + &virtual_file_mapping.into_vec(), + &expressions, + &code_regions, + &branch_regions, + &mcdc_branch_regions, + &mcdc_decision_regions, + ) } /// Generates the contents of the covmap record for this CGU, which mostly @@ -335,23 +330,11 @@ fn generate_covmap_record<'ll>( let covmap_data = cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false); - let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe { - llvm::LLVMRustCoverageWriteMappingVarNameToString(s); - })) - .unwrap(); - debug!("covmap var name: {:?}", covmap_var_name); - - let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe { - llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s); - })) - .expect("covmap section name should not contain NUL"); - debug!("covmap section name: {:?}", covmap_section_name); - - let llglobal = llvm::add_global(cx.llmod, cx.val_ty(covmap_data), &covmap_var_name); + let llglobal = llvm::add_global(cx.llmod, cx.val_ty(covmap_data), &llvm_cov::covmap_var_name()); llvm::set_initializer(llglobal, covmap_data); llvm::set_global_constant(llglobal, true); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::set_section(llglobal, &covmap_section_name); + llvm::set_section(llglobal, &llvm_cov::covmap_section_name(cx.llmod)); // LLVM's coverage mapping format specifies 8-byte alignment for items in this section. // <https://llvm.org/docs/CoverageMappingFormat.html> llvm::set_alignment(llglobal, Align::EIGHT); @@ -373,7 +356,7 @@ fn generate_covfun_record( let coverage_mapping_size = coverage_mapping_buffer.len(); let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer); - let func_name_hash = coverageinfo::hash_bytes(mangled_function_name.as_bytes()); + let func_name_hash = llvm_cov::hash_bytes(mangled_function_name.as_bytes()); let func_name_hash_val = cx.const_u64(func_name_hash); let coverage_mapping_size_val = cx.const_u32(coverage_mapping_size as u32); let source_hash_val = cx.const_u64(source_hash); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index aaba0684c12..bf773cd2667 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -1,24 +1,23 @@ use std::cell::{OnceCell, RefCell}; use std::ffi::{CStr, CString}; -use libc::c_uint; use rustc_abi::Size; use rustc_codegen_ssa::traits::{ BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods, }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_llvm::RustString; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::ty::Instance; use rustc_middle::ty::layout::HasTyCtxt; use tracing::{debug, instrument}; use crate::builder::Builder; -use crate::common::{AsCCharPtr, CodegenCx}; +use crate::common::CodegenCx; use crate::coverageinfo::map_data::FunctionCoverageCollector; use crate::llvm; pub(crate) mod ffi; +mod llvm_cov; pub(crate) mod map_data; mod mapgen; @@ -80,12 +79,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix) /// - `.lcovfun$M` on Windows (includes `$M` sorting suffix) fn covfun_section_name(&self) -> &CStr { - self.coverage_cx().covfun_section_name.get_or_init(|| { - CString::new(llvm::build_byte_buffer(|s| unsafe { - llvm::LLVMRustCoverageWriteFuncSectionNameToString(self.llmod, s); - })) - .expect("covfun section name should not contain NUL") - }) + self.coverage_cx() + .covfun_section_name + .get_or_init(|| llvm_cov::covfun_section_name(self.llmod)) } /// For LLVM codegen, returns a function-specific `Value` for a global @@ -95,9 +91,11 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value { debug!("getting pgo_func_name_var for instance={:?}", instance); let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut(); - pgo_func_name_var_map - .entry(instance) - .or_insert_with(|| create_pgo_func_name_var(self, instance)) + pgo_func_name_var_map.entry(instance).or_insert_with(|| { + let llfn = self.get_fn(instance); + let mangled_fn_name: &str = self.tcx.symbol_name(instance).name; + llvm_cov::create_pgo_func_name_var(llfn, mangled_fn_name) + }) } } @@ -225,80 +223,3 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { } } } - -/// Calls llvm::createPGOFuncNameVar() with the given function instance's -/// mangled function name. The LLVM API returns an llvm::GlobalVariable -/// containing the function name, with the specific variable name and linkage -/// required by LLVM InstrProf source-based coverage instrumentation. Use -/// `bx.get_pgo_func_name_var()` to ensure the variable is only created once per -/// `Instance`. -fn create_pgo_func_name_var<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, - instance: Instance<'tcx>, -) -> &'ll llvm::Value { - let mangled_fn_name: &str = cx.tcx.symbol_name(instance).name; - let llfn = cx.get_fn(instance); - unsafe { - llvm::LLVMRustCoverageCreatePGOFuncNameVar( - llfn, - mangled_fn_name.as_c_char_ptr(), - mangled_fn_name.len(), - ) - } -} - -pub(crate) fn write_filenames_section_to_buffer<'a>( - filenames: impl IntoIterator<Item = &'a str>, - buffer: &RustString, -) { - let (pointers, lengths) = filenames - .into_iter() - .map(|s: &str| (s.as_c_char_ptr(), s.len())) - .unzip::<_, _, Vec<_>, Vec<_>>(); - - unsafe { - llvm::LLVMRustCoverageWriteFilenamesSectionToBuffer( - pointers.as_ptr(), - pointers.len(), - lengths.as_ptr(), - lengths.len(), - buffer, - ); - } -} - -pub(crate) fn write_mapping_to_buffer( - virtual_file_mapping: Vec<u32>, - expressions: Vec<ffi::CounterExpression>, - code_regions: &[ffi::CodeRegion], - branch_regions: &[ffi::BranchRegion], - mcdc_branch_regions: &[ffi::MCDCBranchRegion], - mcdc_decision_regions: &[ffi::MCDCDecisionRegion], - buffer: &RustString, -) { - unsafe { - llvm::LLVMRustCoverageWriteMappingToBuffer( - virtual_file_mapping.as_ptr(), - virtual_file_mapping.len() as c_uint, - expressions.as_ptr(), - expressions.len() as c_uint, - code_regions.as_ptr(), - code_regions.len() as c_uint, - branch_regions.as_ptr(), - branch_regions.len() as c_uint, - mcdc_branch_regions.as_ptr(), - mcdc_branch_regions.len() as c_uint, - mcdc_decision_regions.as_ptr(), - mcdc_decision_regions.len() as c_uint, - buffer, - ); - } -} - -pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 { - unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_c_char_ptr(), bytes.len()) } -} - -pub(crate) fn mapping_version() -> u32 { - unsafe { llvm::LLVMRustCoverageMappingVersion() } -} diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index b85d28a2f1f..49e616b5371 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -22,7 +22,6 @@ use std::any::Any; use std::ffi::CStr; -use std::io::Write; use std::mem::ManuallyDrop; use back::owned_target_machine::OwnedTargetMachine; @@ -165,30 +164,12 @@ impl WriteBackendMethods for LlvmCodegenBackend { type ThinData = back::lto::ThinData; type ThinBuffer = back::lto::ThinBuffer; fn print_pass_timings(&self) { - unsafe { - let mut size = 0; - let cstr = llvm::LLVMRustPrintPassTimings(&raw mut size); - if cstr.is_null() { - println!("failed to get pass timings"); - } else { - let timings = std::slice::from_raw_parts(cstr as *const u8, size); - std::io::stdout().write_all(timings).unwrap(); - libc::free(cstr as *mut _); - } - } + let timings = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap(); + print!("{timings}"); } fn print_statistics(&self) { - unsafe { - let mut size = 0; - let cstr = llvm::LLVMRustPrintStatistics(&raw mut size); - if cstr.is_null() { - println!("failed to get pass stats"); - } else { - let stats = std::slice::from_raw_parts(cstr as *const u8, size); - std::io::stdout().write_all(stats).unwrap(); - libc::free(cstr as *mut _); - } - } + let stats = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap(); + print!("{stats}"); } fn run_link( cgcx: &CodegenContext<Self>, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index d84ae8d8836..8508f87c8d3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1765,11 +1765,13 @@ unsafe extern "C" { /// Returns a string describing the last error caused by an LLVMRust* call. pub fn LLVMRustGetLastError() -> *const c_char; - /// Print the pass timings since static dtors aren't picking them up. - pub fn LLVMRustPrintPassTimings(size: *const size_t) -> *const c_char; + /// Prints the timing information collected by `-Ztime-llvm-passes`. + #[expect(improper_ctypes)] + pub(crate) fn LLVMRustPrintPassTimings(OutStr: &RustString); - /// Print the statistics since static dtors aren't picking them up. - pub fn LLVMRustPrintStatistics(size: *const size_t) -> *const c_char; + /// Prints the statistics collected by `-Zprint-codegen-stats`. + #[expect(improper_ctypes)] + pub(crate) fn LLVMRustPrintStatistics(OutStr: &RustString); /// Prepares inline assembly. pub fn LLVMRustInlineAsm( @@ -1790,7 +1792,7 @@ unsafe extern "C" { ) -> bool; #[allow(improper_ctypes)] - pub(crate) fn LLVMRustCoverageWriteFilenamesSectionToBuffer( + pub(crate) fn LLVMRustCoverageWriteFilenamesToBuffer( Filenames: *const *const c_char, FilenamesLen: size_t, Lengths: *const size_t, @@ -1799,19 +1801,19 @@ unsafe extern "C" { ); #[allow(improper_ctypes)] - pub(crate) fn LLVMRustCoverageWriteMappingToBuffer( + pub(crate) fn LLVMRustCoverageWriteFunctionMappingsToBuffer( VirtualFileMappingIDs: *const c_uint, - NumVirtualFileMappingIDs: c_uint, + NumVirtualFileMappingIDs: size_t, Expressions: *const crate::coverageinfo::ffi::CounterExpression, - NumExpressions: c_uint, + NumExpressions: size_t, CodeRegions: *const crate::coverageinfo::ffi::CodeRegion, - NumCodeRegions: c_uint, + NumCodeRegions: size_t, BranchRegions: *const crate::coverageinfo::ffi::BranchRegion, - NumBranchRegions: c_uint, + NumBranchRegions: size_t, MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion, - NumMCDCBranchRegions: c_uint, + NumMCDCBranchRegions: size_t, MCDCDecisionRegions: *const crate::coverageinfo::ffi::MCDCDecisionRegion, - NumMCDCDecisionRegions: c_uint, + NumMCDCDecisionRegions: size_t, BufferOut: &RustString, ); @@ -1820,16 +1822,16 @@ unsafe extern "C" { FuncName: *const c_char, FuncNameLen: size_t, ) -> &Value; - pub(crate) fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64; + pub(crate) fn LLVMRustCoverageHashBytes(Bytes: *const c_char, NumBytes: size_t) -> u64; #[allow(improper_ctypes)] - pub(crate) fn LLVMRustCoverageWriteMapSectionNameToString(M: &Module, Str: &RustString); + pub(crate) fn LLVMRustCoverageWriteCovmapSectionNameToString(M: &Module, OutStr: &RustString); #[allow(improper_ctypes)] - pub(crate) fn LLVMRustCoverageWriteFuncSectionNameToString(M: &Module, Str: &RustString); + pub(crate) fn LLVMRustCoverageWriteCovfunSectionNameToString(M: &Module, OutStr: &RustString); #[allow(improper_ctypes)] - pub(crate) fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString); + pub(crate) fn LLVMRustCoverageWriteCovmapVarNameToString(OutStr: &RustString); pub(crate) fn LLVMRustCoverageMappingVersion() -> u32; pub fn LLVMRustDebugMetadataVersion() -> u32; diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index dffb7a7271e..b898cfec796 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -28,7 +28,6 @@ rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_metadata = { path = "../rustc_metadata" } rustc_middle = { path = "../rustc_middle" } -rustc_monomorphize = { path = "../rustc_monomorphize" } rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 2f48c1fbf0d..e83bfa7b70d 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -26,6 +26,35 @@ use crate::errors::{ DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile, }; +/// An item to be included in an import library. +/// This is a slimmed down version of `COFFShortExport` from `ar-archive-writer`. +pub struct ImportLibraryItem { + /// The name to be exported. + pub name: String, + /// The ordinal to be exported, if any. + pub ordinal: Option<u16>, + /// The original, decorated name if `name` is not decorated. + pub symbol_name: Option<String>, + /// True if this is a data export, false if it is a function export. + pub is_data: bool, +} + +impl From<ImportLibraryItem> for COFFShortExport { + fn from(item: ImportLibraryItem) -> Self { + COFFShortExport { + name: item.name, + ext_name: None, + symbol_name: item.symbol_name, + alias_target: None, + ordinal: item.ordinal.unwrap_or(0), + noname: item.ordinal.is_some(), + data: item.is_data, + private: false, + constant: false, + } + } +} + pub trait ArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>; @@ -38,7 +67,7 @@ pub trait ArchiveBuilderBuilder { &self, sess: &Session, lib_name: &str, - import_name_and_ordinal_vector: Vec<(String, Option<u16>)>, + items: Vec<ImportLibraryItem>, output_path: &Path, ) { if common::is_mingw_gnu_toolchain(&sess.target) { @@ -47,21 +76,16 @@ pub trait ArchiveBuilderBuilder { // that loaded but crashed with an AV upon calling one of the imported // functions. Therefore, use binutils to create the import library instead, // by writing a .DEF file to the temp dir and calling binutils's dlltool. - create_mingw_dll_import_lib( - sess, - lib_name, - import_name_and_ordinal_vector, - output_path, - ); + create_mingw_dll_import_lib(sess, lib_name, items, output_path); } else { trace!("creating import library"); trace!(" dll_name {:#?}", lib_name); trace!(" output_path {}", output_path.display()); trace!( " import names: {}", - import_name_and_ordinal_vector + items .iter() - .map(|(name, _ordinal)| name.clone()) + .map(|ImportLibraryItem { name, .. }| name.clone()) .collect::<Vec<_>>() .join(", "), ); @@ -79,20 +103,7 @@ pub trait ArchiveBuilderBuilder { .emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }), }; - let exports = import_name_and_ordinal_vector - .iter() - .map(|(name, ordinal)| COFFShortExport { - name: name.to_string(), - ext_name: None, - symbol_name: None, - alias_target: None, - ordinal: ordinal.unwrap_or(0), - noname: ordinal.is_some(), - data: false, - private: false, - constant: false, - }) - .collect::<Vec<_>>(); + let exports = items.into_iter().map(Into::into).collect::<Vec<_>>(); let machine = match &*sess.target.arch { "x86_64" => MachineTypes::AMD64, "x86" => MachineTypes::I386, @@ -160,16 +171,16 @@ pub trait ArchiveBuilderBuilder { fn create_mingw_dll_import_lib( sess: &Session, lib_name: &str, - import_name_and_ordinal_vector: Vec<(String, Option<u16>)>, + items: Vec<ImportLibraryItem>, output_path: &Path, ) { let def_file_path = output_path.with_extension("def"); let def_file_content = format!( "EXPORTS\n{}", - import_name_and_ordinal_vector + items .into_iter() - .map(|(name, ordinal)| { + .map(|ImportLibraryItem { name, ordinal, .. }| { match ordinal { Some(n) => format!("{name} @{n} NONAME"), None => name, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 44581cfa64b..8f754debaf0 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -45,7 +45,7 @@ use rustc_target::spec::{ use tempfile::Builder as TempFileBuilder; use tracing::{debug, info, warn}; -use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; +use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder, ImportLibraryItem}; use super::command::Command; use super::linker::{self, Linker}; use super::metadata::{MetadataPosition, create_wrapper_file}; @@ -495,16 +495,35 @@ fn create_dll_import_libs<'a>( let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target); - let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = raw_dylib_imports + let items: Vec<ImportLibraryItem> = raw_dylib_imports .iter() .map(|import: &DllImport| { if sess.target.arch == "x86" { - ( - common::i686_decorated_name(import, mingw_gnu_toolchain, false), - import.ordinal(), - ) + ImportLibraryItem { + name: common::i686_decorated_name( + import, + mingw_gnu_toolchain, + false, + false, + ), + ordinal: import.ordinal(), + symbol_name: import.is_missing_decorations().then(|| { + common::i686_decorated_name( + import, + mingw_gnu_toolchain, + false, + true, + ) + }), + is_data: !import.is_fn, + } } else { - (import.name.to_string(), import.ordinal()) + ImportLibraryItem { + name: import.name.to_string(), + ordinal: import.ordinal(), + symbol_name: None, + is_data: !import.is_fn, + } } }) .collect(); @@ -512,7 +531,7 @@ fn create_dll_import_libs<'a>( archive_builder_builder.create_dll_import_lib( sess, &raw_dylib_name, - import_name_and_ordinal_vector, + items, &output_path, ); diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 582a2a87e48..965bd34ac14 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -187,12 +187,15 @@ pub fn i686_decorated_name( dll_import: &DllImport, mingw: bool, disable_name_mangling: bool, + force_fully_decorated: bool, ) -> String { let name = dll_import.name.as_str(); - let (add_prefix, add_suffix) = match dll_import.import_name_type { - Some(PeImportNameType::NoPrefix) => (false, true), - Some(PeImportNameType::Undecorated) => (false, false), + let (add_prefix, add_suffix) = match (force_fully_decorated, dll_import.import_name_type) { + // No prefix is a bit weird, in that LLVM/ar_archive_writer won't emit it, so we will + // ignore `force_fully_decorated` and always partially decorate it. + (_, Some(PeImportNameType::NoPrefix)) => (false, true), + (false, Some(PeImportNameType::Undecorated)) => (false, false), _ => (true, true), }; diff --git a/compiler/rustc_error_codes/src/error_codes/E0094.md b/compiler/rustc_error_codes/src/error_codes/E0094.md index d8c1a3cb55c..efbfa0851a8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0094.md +++ b/compiler/rustc_error_codes/src/error_codes/E0094.md @@ -3,13 +3,15 @@ An invalid number of generic parameters was passed to an intrinsic function. Erroneous code example: ```compile_fail,E0094 -#![feature(intrinsics, rustc_attrs)] +#![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - fn size_of<T, U>() -> usize; // error: intrinsic has wrong number - // of type parameters +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +fn size_of<T, U>() -> usize // error: intrinsic has wrong number + // of type parameters +{ + loop {} } ``` @@ -18,11 +20,13 @@ and verify with the function declaration in the Rust source code. Example: ``` -#![feature(intrinsics, rustc_attrs)] +#![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - fn size_of<T>() -> usize; // ok! +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +fn size_of<T>() -> usize // ok! +{ + loop {} } ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0211.md b/compiler/rustc_error_codes/src/error_codes/E0211.md index 19a482f6c93..7aa42628549 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0211.md +++ b/compiler/rustc_error_codes/src/error_codes/E0211.md @@ -4,12 +4,11 @@ You used a function or type which doesn't fit the requirements for where it was used. Erroneous code examples: ```compile_fail -#![feature(intrinsics, rustc_attrs)] +#![feature(intrinsics)] #![allow(internal_features)] extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - fn size_of<T>(); // error: intrinsic has wrong type + fn unreachable(); // error: intrinsic has wrong type } // or: @@ -41,12 +40,11 @@ impl Foo { For the first code example, please check the function definition. Example: ``` -#![feature(intrinsics, rustc_attrs)] +#![feature(intrinsics)] #![allow(internal_features)] extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - fn size_of<T>() -> usize; // ok! + fn unreachable() -> !; // ok! } ``` diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index cc0bdec7019..a4820ba8b72 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -997,23 +997,18 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing, EncodeCrossCrate::Yes, r#"`rustc_doc_primitive` is a rustc internal attribute"#, ), - rustc_attr!( - rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, - "the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe" - ), - rustc_attr!( - rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, + gated!( + rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics, "the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies", ), + gated!( + rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics, + "the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies", + ), rustc_attr!( rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen" ), - rustc_attr!( - rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies", - ), // ========================================================================== // Internal attributes, Testing: diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 3c8887f08bc..581ef2272d1 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -19,7 +19,6 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } -rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 1513ea7c9e8..cb954b0adcb 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -1,10 +1,9 @@ -//! Type-checking for the rust-intrinsic and platform-intrinsic -//! intrinsics that the compiler exposes. +//! Type-checking for the rust-intrinsic intrinsics that the compiler exposes. use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{DiagMessage, struct_span_code_err}; -use rustc_hir as hir; +use rustc_hir::{self as hir, Safety}; use rustc_middle::bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -76,10 +75,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - let has_safe_attr = if tcx.has_attr(intrinsic_id, sym::rustc_intrinsic) { tcx.fn_sig(intrinsic_id).skip_binder().safety() } else { - match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) { - true => hir::Safety::Safe, - false => hir::Safety::Unsafe, - } + // Old-style intrinsics are never safe + Safety::Unsafe }; let is_in_list = match tcx.item_name(intrinsic_id.into()) { // When adding a new intrinsic to this list, diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index 894402a8c2e..8ddbb4b3397 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -23,7 +23,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index ef5a1468c87..6d1a2d3de9e 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -16,9 +16,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } -rustc_next_trait_solver = { path = "../rustc_next_trait_solver" } rustc_span = { path = "../rustc_span" } -rustc_target = { path = "../rustc_target" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index dd7b40d0a32..ec5f0f06c59 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -14,7 +14,6 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } -rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_lint/src/static_mut_refs.rs b/compiler/rustc_lint/src/static_mut_refs.rs index 5d78b41944f..fed5c29284b 100644 --- a/compiler/rustc_lint/src/static_mut_refs.rs +++ b/compiler/rustc_lint/src/static_mut_refs.rs @@ -3,8 +3,8 @@ use rustc_hir::{Expr, Stmt}; use rustc_middle::ty::{Mutability, TyKind}; use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::Span; use rustc_span::edition::Edition; +use rustc_span::{BytePos, Span}; use crate::lints::{MutRefSugg, RefOfMutStatic}; use crate::{LateContext, LateLintPass, LintContext}; @@ -71,13 +71,24 @@ impl<'tcx> LateLintPass<'tcx> for StaticMutRefs { if matches!(borrow_kind, hir::BorrowKind::Ref) && let Some(err_span) = path_is_static_mut(ex, err_span) => { - emit_static_mut_refs( - cx, - err_span, - err_span.with_hi(ex.span.lo()), - m, - !expr.span.from_expansion(), - ); + let source_map = cx.sess().source_map(); + let snippet = source_map.span_to_snippet(err_span); + + let sugg_span = if let Ok(snippet) = snippet { + // ( ( &IDENT ) ) + // ~~~~ exclude these from the suggestion span to avoid unmatching parens + let exclude_n_bytes: u32 = snippet + .chars() + .take_while(|ch| ch.is_whitespace() || *ch == '(') + .map(|ch| ch.len_utf8() as u32) + .sum(); + + err_span.with_lo(err_span.lo() + BytePos(exclude_n_bytes)).with_hi(ex.span.lo()) + } else { + err_span.with_hi(ex.span.lo()) + }; + + emit_static_mut_refs(cx, err_span, sugg_span, m, !expr.span.from_expansion()); } hir::ExprKind::MethodCall(_, e, _, _) if let Some(err_span) = path_is_static_mut(e, expr.span) diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index b32af5e5e75..2ee7454b652 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -123,13 +123,13 @@ fromRust(LLVMRustCounterExprKind Kind) { report_fatal_error("Bad LLVMRustCounterExprKind!"); } -extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer( +extern "C" void LLVMRustCoverageWriteFilenamesToBuffer( const char *const Filenames[], size_t FilenamesLen, // String start pointers const size_t *const Lengths, size_t LengthsLen, // Corresponding lengths RustStringRef BufferOut) { if (FilenamesLen != LengthsLen) { report_fatal_error( - "Mismatched lengths in LLVMRustCoverageWriteFilenamesSectionToBuffer"); + "Mismatched lengths in LLVMRustCoverageWriteFilenamesToBuffer"); } SmallVector<std::string, 32> FilenameRefs; @@ -143,16 +143,15 @@ extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer( FilenamesWriter.write(OS); } -extern "C" void LLVMRustCoverageWriteMappingToBuffer( - const unsigned *VirtualFileMappingIDs, unsigned NumVirtualFileMappingIDs, - const LLVMRustCounterExpression *RustExpressions, unsigned NumExpressions, - const LLVMRustCoverageCodeRegion *CodeRegions, unsigned NumCodeRegions, - const LLVMRustCoverageBranchRegion *BranchRegions, - unsigned NumBranchRegions, +extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer( + const unsigned *VirtualFileMappingIDs, size_t NumVirtualFileMappingIDs, + const LLVMRustCounterExpression *RustExpressions, size_t NumExpressions, + const LLVMRustCoverageCodeRegion *CodeRegions, size_t NumCodeRegions, + const LLVMRustCoverageBranchRegion *BranchRegions, size_t NumBranchRegions, const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions, - unsigned NumMCDCBranchRegions, + size_t NumMCDCBranchRegions, const LLVMRustCoverageMCDCDecisionRegion *MCDCDecisionRegions, - unsigned NumMCDCDecisionRegions, RustStringRef BufferOut) { + size_t NumMCDCDecisionRegions, RustStringRef BufferOut) { // Convert from FFI representation to LLVM representation. // Expressions: @@ -219,34 +218,37 @@ LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, const char *FuncName, return wrap(createPGOFuncNameVar(*cast<Function>(unwrap(F)), FuncNameRef)); } -extern "C" uint64_t LLVMRustCoverageHashByteArray(const char *Bytes, - size_t NumBytes) { - auto StrRef = StringRef(Bytes, NumBytes); - return IndexedInstrProf::ComputeHash(StrRef); +extern "C" uint64_t LLVMRustCoverageHashBytes(const char *Bytes, + size_t NumBytes) { + return IndexedInstrProf::ComputeHash(StringRef(Bytes, NumBytes)); } -static void WriteSectionNameToString(LLVMModuleRef M, InstrProfSectKind SK, - RustStringRef Str) { +// Private helper function for getting the covmap and covfun section names. +static void writeInstrProfSectionNameToString(LLVMModuleRef M, + InstrProfSectKind SectKind, + RustStringRef OutStr) { auto TargetTriple = Triple(unwrap(M)->getTargetTriple()); - auto name = getInstrProfSectionName(SK, TargetTriple.getObjectFormat()); - auto OS = RawRustStringOstream(Str); + auto name = getInstrProfSectionName(SectKind, TargetTriple.getObjectFormat()); + auto OS = RawRustStringOstream(OutStr); OS << name; } -extern "C" void LLVMRustCoverageWriteMapSectionNameToString(LLVMModuleRef M, - RustStringRef Str) { - WriteSectionNameToString(M, IPSK_covmap, Str); +extern "C" void +LLVMRustCoverageWriteCovmapSectionNameToString(LLVMModuleRef M, + RustStringRef OutStr) { + writeInstrProfSectionNameToString(M, IPSK_covmap, OutStr); } extern "C" void -LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M, - RustStringRef Str) { - WriteSectionNameToString(M, IPSK_covfun, Str); +LLVMRustCoverageWriteCovfunSectionNameToString(LLVMModuleRef M, + RustStringRef OutStr) { + writeInstrProfSectionNameToString(M, IPSK_covfun, OutStr); } -extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { +extern "C" void +LLVMRustCoverageWriteCovmapVarNameToString(RustStringRef OutStr) { auto name = getCoverageMappingVarName(); - auto OS = RawRustStringOstream(Str); + auto OS = RawRustStringOstream(OutStr); OS << name; } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 645b4082be5..a68eed03e61 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -140,26 +140,14 @@ extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M, unwrap(M)->setTargetTriple(Triple::normalize(Triple)); } -extern "C" const char *LLVMRustPrintPassTimings(size_t *Len) { - std::string buf; - auto SS = raw_string_ostream(buf); - TimerGroup::printAll(SS); - SS.flush(); - *Len = buf.length(); - char *CStr = (char *)malloc(*Len); - memcpy(CStr, buf.c_str(), *Len); - return CStr; -} - -extern "C" const char *LLVMRustPrintStatistics(size_t *Len) { - std::string buf; - auto SS = raw_string_ostream(buf); - llvm::PrintStatistics(SS); - SS.flush(); - *Len = buf.length(); - char *CStr = (char *)malloc(*Len); - memcpy(CStr, buf.c_str(), *Len); - return CStr; +extern "C" void LLVMRustPrintPassTimings(RustStringRef OutBuf) { + auto OS = RawRustStringOstream(OutBuf); + TimerGroup::printAll(OS); +} + +extern "C" void LLVMRustPrintStatistics(RustStringRef OutBuf) { + auto OS = RawRustStringOstream(OutBuf); + llvm::PrintStatistics(OS); } extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M, const char *Name, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index f06f2fdc5e5..045fd0565ba 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -384,6 +384,7 @@ provide! { tcx, def_id, other, cdata, crate_hash => { cdata.root.header.hash } crate_host_hash => { cdata.host_hash } crate_name => { cdata.root.header.name } + num_extern_def_ids => { cdata.num_def_ids() } extra_filename => { cdata.root.extra_filename.clone() } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f58426601cd..8ae89ea6e2c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1844,6 +1844,16 @@ rustc_queries! { desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id) } } + /// Gets the number of definitions in a foreign crate. + /// + /// This allows external tools to iterate over all definitions in a foreign crate. + /// + /// This should never be used for the local crate, instead use `iter_local_def_id`. + query num_extern_def_ids(_: CrateNum) -> usize { + desc { "fetching the number of definitions in a crate" } + separate_provide_extern + } + query lib_features(_: CrateNum) -> &'tcx LibFeatures { desc { "calculating the lib features defined in a crate" } separate_provide_extern diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 7ee13bc1725..0d1c56f0d38 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -71,7 +71,7 @@ pub enum InstanceKind<'tcx> { /// - coroutines Item(DefId), - /// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI). + /// An intrinsic `fn` item (with `"rust-intrinsic"` ABI). /// /// Alongside `Virtual`, this is the only `InstanceKind` that does not have its own callable MIR. /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 56e723ab517..fc5a3b762e5 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1785,9 +1785,9 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { /// the compiler to make some assumptions about its shape; if the user doesn't use a feature gate, they may /// cause an ICE that we otherwise may want to prevent. pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef> { - if (matches!(tcx.fn_sig(def_id).skip_binder().abi(), ExternAbi::RustIntrinsic) - && tcx.features().intrinsics()) - || (tcx.has_attr(def_id, sym::rustc_intrinsic) && tcx.features().rustc_attrs()) + if tcx.features().intrinsics() + && (matches!(tcx.fn_sig(def_id).skip_binder().abi(), ExternAbi::RustIntrinsic) + || tcx.has_attr(def_id, sym::rustc_intrinsic)) { Some(ty::IntrinsicDef { name: tcx.item_name(def_id.into()), diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 168262bf01c..092bce1de2c 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -1,7 +1,7 @@ use std::cmp::Ordering; use std::collections::VecDeque; -use std::iter; use std::ops::{Index, IndexMut}; +use std::{iter, mem, slice}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; @@ -127,10 +127,10 @@ impl CoverageGraph { let mut bcbs = IndexVec::<BasicCoverageBlock, _>::with_capacity(num_basic_blocks); let mut bb_to_bcb = IndexVec::from_elem_n(None, num_basic_blocks); - let mut add_basic_coverage_block = |basic_blocks: &mut Vec<BasicBlock>| { + let mut flush_chain_into_new_bcb = |current_chain: &mut Vec<BasicBlock>| { // Take the accumulated list of blocks, leaving the vector empty // to be used by subsequent BCBs. - let basic_blocks = std::mem::take(basic_blocks); + let basic_blocks = mem::take(current_chain); let bcb = bcbs.next_index(); for &bb in basic_blocks.iter() { @@ -141,48 +141,41 @@ impl CoverageGraph { bcb_filtered_successors(mir_body[bb].terminator()).is_out_summable() }); let bcb_data = BasicCoverageBlockData { basic_blocks, is_out_summable }; - debug!("adding bcb{}: {:?}", bcb.index(), bcb_data); + debug!("adding {bcb:?}: {bcb_data:?}"); bcbs.push(bcb_data); }; - // Walk the MIR CFG using a Preorder traversal, which starts from `START_BLOCK` and follows - // each block terminator's `successors()`. Coverage spans must map to actual source code, - // so compiler generated blocks and paths can be ignored. To that end, the CFG traversal - // intentionally omits unwind paths. - // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and - // `catch_unwind()` handlers. + // Traverse the MIR control-flow graph, accumulating chains of blocks + // that can be combined into a single node in the coverage graph. + // A depth-first search ensures that if two nodes can be chained + // together, they will be adjacent in the traversal order. // Accumulates a chain of blocks that will be combined into one BCB. - let mut basic_blocks = Vec::new(); + let mut current_chain = vec![]; - let filtered_successors = |bb| bcb_filtered_successors(mir_body[bb].terminator()); - for bb in short_circuit_preorder(mir_body, filtered_successors) + let subgraph = CoverageRelevantSubgraph::new(&mir_body.basic_blocks); + for bb in graph::depth_first_search(subgraph, mir::START_BLOCK) .filter(|&bb| mir_body[bb].terminator().kind != TerminatorKind::Unreachable) { - // If the previous block can't be chained into `bb`, flush the accumulated - // blocks into a new BCB, then start building the next chain. - if let Some(&prev) = basic_blocks.last() - && (!filtered_successors(prev).is_chainable() || { - // If `bb` has multiple predecessor blocks, or `prev` isn't - // one of its predecessors, we can't chain and must flush. - let predecessors = &mir_body.basic_blocks.predecessors()[bb]; - predecessors.len() > 1 || !predecessors.contains(&prev) - }) - { - debug!( - terminator_kind = ?mir_body[prev].terminator().kind, - predecessors = ?&mir_body.basic_blocks.predecessors()[bb], - "can't chain from {prev:?} to {bb:?}" - ); - add_basic_coverage_block(&mut basic_blocks); + if let Some(&prev) = current_chain.last() { + // Adding a block to a non-empty chain is allowed if the + // previous block permits chaining, and the current block has + // `prev` as its sole predecessor. + let can_chain = subgraph.coverage_successors(prev).is_out_chainable() + && mir_body.basic_blocks.predecessors()[bb].as_slice() == &[prev]; + if !can_chain { + // The current block can't be added to the existing chain, so + // flush that chain into a new BCB, and start a new chain. + flush_chain_into_new_bcb(&mut current_chain); + } } - basic_blocks.push(bb); + current_chain.push(bb); } - if !basic_blocks.is_empty() { + if !current_chain.is_empty() { debug!("flushing accumulated blocks into one last BCB"); - add_basic_coverage_block(&mut basic_blocks); + flush_chain_into_new_bcb(&mut current_chain); } (bcbs, bb_to_bcb) @@ -389,34 +382,28 @@ impl BasicCoverageBlockData { /// indicates whether that block can potentially be combined into the same BCB /// as its sole successor. #[derive(Clone, Copy, Debug)] -enum CoverageSuccessors<'a> { - /// The terminator has exactly one straight-line successor, so its block can - /// potentially be combined into the same BCB as that successor. - Chainable(BasicBlock), - /// The block cannot be combined into the same BCB as its successor(s). - NotChainable(&'a [BasicBlock]), - /// Yield terminators are not chainable, and their execution count can also - /// differ from the execution count of their out-edge. - Yield(BasicBlock), +struct CoverageSuccessors<'a> { + /// Coverage-relevant successors of the corresponding terminator. + /// There might be 0, 1, or multiple targets. + targets: &'a [BasicBlock], + /// `Yield` terminators are not chainable, because their sole out-edge is + /// only followed if/when the generator is resumed after the yield. + is_yield: bool, } impl CoverageSuccessors<'_> { - fn is_chainable(&self) -> bool { - match self { - Self::Chainable(_) => true, - Self::NotChainable(_) => false, - Self::Yield(_) => false, - } + /// If `false`, this terminator cannot be chained into another block when + /// building the coverage graph. + fn is_out_chainable(&self) -> bool { + // If a terminator is out-summable and has exactly one out-edge, then + // it is eligible to be chained into its successor block. + self.is_out_summable() && self.targets.len() == 1 } /// Returns true if the terminator itself is assumed to have the same /// execution count as the sum of its out-edges (assuming no panics). fn is_out_summable(&self) -> bool { - match self { - Self::Chainable(_) => true, - Self::NotChainable(_) => true, - Self::Yield(_) => false, - } + !self.is_yield && !self.targets.is_empty() } } @@ -425,12 +412,7 @@ impl IntoIterator for CoverageSuccessors<'_> { type IntoIter = impl DoubleEndedIterator<Item = Self::Item>; fn into_iter(self) -> Self::IntoIter { - match self { - Self::Chainable(bb) | Self::Yield(bb) => { - Some(bb).into_iter().chain((&[]).iter().copied()) - } - Self::NotChainable(bbs) => None.into_iter().chain(bbs.iter().copied()), - } + self.targets.iter().copied() } } @@ -440,14 +422,17 @@ impl IntoIterator for CoverageSuccessors<'_> { // `catch_unwind()` handlers. fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> CoverageSuccessors<'a> { use TerminatorKind::*; - match terminator.kind { + let mut is_yield = false; + let targets = match &terminator.kind { // A switch terminator can have many coverage-relevant successors. - // (If there is exactly one successor, we still treat it as not chainable.) - SwitchInt { ref targets, .. } => CoverageSuccessors::NotChainable(targets.all_targets()), + SwitchInt { targets, .. } => targets.all_targets(), // A yield terminator has exactly 1 successor, but should not be chained, // because its resume edge has a different execution count. - Yield { resume, .. } => CoverageSuccessors::Yield(resume), + Yield { resume, .. } => { + is_yield = true; + slice::from_ref(resume) + } // These terminators have exactly one coverage-relevant successor, // and can be chained into it. @@ -455,24 +440,15 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera | Drop { target, .. } | FalseEdge { real_target: target, .. } | FalseUnwind { real_target: target, .. } - | Goto { target } => CoverageSuccessors::Chainable(target), + | Goto { target } => slice::from_ref(target), // A call terminator can normally be chained, except when it has no // successor because it is known to diverge. - Call { target: maybe_target, .. } => match maybe_target { - Some(target) => CoverageSuccessors::Chainable(target), - None => CoverageSuccessors::NotChainable(&[]), - }, + Call { target: maybe_target, .. } => maybe_target.as_slice(), // An inline asm terminator can normally be chained, except when it // diverges or uses asm goto. - InlineAsm { ref targets, .. } => { - if let [target] = targets[..] { - CoverageSuccessors::Chainable(target) - } else { - CoverageSuccessors::NotChainable(targets) - } - } + InlineAsm { targets, .. } => &targets, // These terminators have no coverage-relevant successors. CoroutineDrop @@ -480,8 +456,10 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera | TailCall { .. } | Unreachable | UnwindResume - | UnwindTerminate(_) => CoverageSuccessors::NotChainable(&[]), - } + | UnwindTerminate(_) => &[], + }; + + CoverageSuccessors { targets, is_yield } } /// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the @@ -616,28 +594,31 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { } } -fn short_circuit_preorder<'a, 'tcx, F, Iter>( - body: &'a mir::Body<'tcx>, - filtered_successors: F, -) -> impl Iterator<Item = BasicBlock> + Captures<'a> + Captures<'tcx> -where - F: Fn(BasicBlock) -> Iter, - Iter: IntoIterator<Item = BasicBlock>, -{ - let mut visited = BitSet::new_empty(body.basic_blocks.len()); - let mut worklist = vec![mir::START_BLOCK]; - - std::iter::from_fn(move || { - while let Some(bb) = worklist.pop() { - if !visited.insert(bb) { - continue; - } - - worklist.extend(filtered_successors(bb)); +/// Wrapper around a [`mir::BasicBlocks`] graph that restricts each node's +/// successors to only the ones considered "relevant" when building a coverage +/// graph. +#[derive(Clone, Copy)] +struct CoverageRelevantSubgraph<'a, 'tcx> { + basic_blocks: &'a mir::BasicBlocks<'tcx>, +} +impl<'a, 'tcx> CoverageRelevantSubgraph<'a, 'tcx> { + fn new(basic_blocks: &'a mir::BasicBlocks<'tcx>) -> Self { + Self { basic_blocks } + } - return Some(bb); - } + fn coverage_successors(&self, bb: BasicBlock) -> CoverageSuccessors<'_> { + bcb_filtered_successors(self.basic_blocks[bb].terminator()) + } +} +impl<'a, 'tcx> graph::DirectedGraph for CoverageRelevantSubgraph<'a, 'tcx> { + type Node = BasicBlock; - None - }) + fn num_nodes(&self) -> usize { + self.basic_blocks.num_nodes() + } +} +impl<'a, 'tcx> graph::Successors for CoverageRelevantSubgraph<'a, 'tcx> { + fn successors(&self, bb: Self::Node) -> impl Iterator<Item = Self::Node> { + self.coverage_successors(bb).into_iter() + } } diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index fdf44e12378..451c215566b 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" derive-where = "1.2.7" rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index e5e70ba2033..6f0bcf5c3f0 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -679,10 +679,6 @@ passes_rustc_pub_transparent = attribute should be applied to `#[repr(transparent)]` types .label = not a `#[repr(transparent)]` type -passes_rustc_safe_intrinsic = - attribute should be applied to intrinsic functions - .label = not an intrinsic function - passes_rustc_std_internal_symbol = attribute should be applied to functions or statics .label = not a function or static diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 0a2926c0404..64a527ef106 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -210,9 +210,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_promotable, ..] => self.check_stability_promotable(attr, target), [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target), [sym::rustc_confusables, ..] => self.check_confusables(attr, target), - [sym::rustc_safe_intrinsic, ..] => { - self.check_rustc_safe_intrinsic(hir_id, attr, span, target) - } [sym::cold, ..] => self.check_cold(hir_id, attr, span, target), [sym::link, ..] => self.check_link(hir_id, attr, span, target), [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), @@ -2055,25 +2052,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_rustc_safe_intrinsic( - &self, - hir_id: HirId, - attr: &Attribute, - span: Span, - target: Target, - ) { - if let Target::ForeignFn = target - && let hir::Node::Item(Item { - kind: ItemKind::ForeignMod { abi: Abi::RustIntrinsic, .. }, - .. - }) = self.tcx.parent_hir_node(hir_id) - { - return; - } - - self.dcx().emit_err(errors::RustcSafeIntrinsic { attr_span: attr.span, span }); - } - fn check_rustc_std_internal_symbol(&self, attr: &Attribute, span: Span, target: Target) { match target { Target::Fn | Target::Static => {} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 8bd767c1243..70c92f0144c 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -642,15 +642,6 @@ pub(crate) struct RustcAllowConstFnUnstable { } #[derive(Diagnostic)] -#[diag(passes_rustc_safe_intrinsic)] -pub(crate) struct RustcSafeIntrinsic { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(passes_rustc_std_internal_symbol)] pub(crate) struct RustcStdInternalSymbol { #[primary_span] diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 29d3d608388..3e2cbc18933 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -130,6 +130,11 @@ impl DllImport { None } } + + pub fn is_missing_decorations(&self) -> bool { + self.import_name_type == Some(PeImportNameType::Undecorated) + || self.import_name_type == Some(PeImportNameType::NoPrefix) + } } /// Calling convention for a function defined in an external library. diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 2d6ca3571fa..3db65692af7 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -34,7 +34,7 @@ use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, I use crate::rustc_internal::RustcInternal; use crate::rustc_smir::builder::BodyBuilder; -use crate::rustc_smir::{Stable, Tables, alloc, new_item_kind, smir_crate}; +use crate::rustc_smir::{Stable, Tables, alloc, filter_def_ids, new_item_kind, smir_crate}; impl<'tcx> Context for TablesWrapper<'tcx> { fn target_info(&self) -> MachineInfo { @@ -80,6 +80,20 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } + fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let krate = crate_num.internal(&mut *tables, tcx); + filter_def_ids(tcx, krate, |def_id| tables.to_fn_def(def_id)) + } + + fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let krate = crate_num.internal(&mut *tables, tcx); + filter_def_ids(tcx, krate, |def_id| tables.to_static(def_id)) + } + fn foreign_module( &self, mod_def: stable_mir::ty::ForeignModuleDef, diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 9032156b257..c5d33f090a0 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -15,8 +15,8 @@ use rustc_middle::mir::interpret::AllocId; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use stable_mir::abi::Layout; -use stable_mir::mir::mono::InstanceDef; -use stable_mir::ty::{MirConstId, Span, TyConstId}; +use stable_mir::mir::mono::{InstanceDef, StaticDef}; +use stable_mir::ty::{FnDef, MirConstId, Span, TyConstId}; use stable_mir::{CtorKind, ItemKind}; use tracing::debug; @@ -79,6 +79,36 @@ impl<'tcx> Tables<'tcx> { }; !must_override && self.tcx.is_mir_available(def_id) } + + fn to_fn_def(&mut self, def_id: DefId) -> Option<FnDef> { + if matches!(self.tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { + Some(self.fn_def(def_id)) + } else { + None + } + } + + fn to_static(&mut self, def_id: DefId) -> Option<StaticDef> { + matches!(self.tcx.def_kind(def_id), DefKind::Static { .. }).then(|| self.static_def(def_id)) + } +} + +/// Iterate over the definitions of the given crate. +pub(crate) fn filter_def_ids<F, T>(tcx: TyCtxt<'_>, krate: CrateNum, mut func: F) -> Vec<T> +where + F: FnMut(DefId) -> Option<T>, +{ + if krate == LOCAL_CRATE { + tcx.iter_local_def_id().filter_map(|did| func(did.to_def_id())).collect() + } else { + let num_definitions = tcx.num_extern_def_ids(krate); + (0..num_definitions) + .filter_map(move |i| { + let def_id = DefId { krate, index: rustc_span::def_id::DefIndex::from_usize(i) }; + func(def_id) + }) + .collect() + } } /// Build a stable mir crate from a given crate number. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 21a74bd4020..82cfbd28fff 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1733,7 +1733,6 @@ symbols! { rustc_reallocator, rustc_regions, rustc_reservation_impl, - rustc_safe_intrinsic, rustc_serialize, rustc_skip_during_method_dispatch, rustc_specialization_trait, @@ -2175,6 +2174,7 @@ symbols! { yes, yield_expr, ymm_reg, + yreg, zfh, zfhmin, zmm_reg, diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index c7d24154e8b..e33431ba122 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -8,9 +8,7 @@ edition = "2021" bitflags = "2.4.1" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } -rustc_feature = { path = "../rustc_feature" } rustc_fs_util = { path = "../rustc_fs_util" } -rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 460b6e4b647..10778e9acf1 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -191,6 +191,7 @@ mod nvptx; mod powerpc; mod riscv; mod s390x; +mod sparc; mod spirv; mod wasm; mod x86; @@ -209,6 +210,7 @@ pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use s390x::{S390xInlineAsmReg, S390xInlineAsmRegClass}; +pub use sparc::{SparcInlineAsmReg, SparcInlineAsmRegClass}; pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass}; pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; @@ -230,6 +232,8 @@ pub enum InlineAsmArch { PowerPC, PowerPC64, S390x, + Sparc, + Sparc64, SpirV, Wasm32, Wasm64, @@ -260,6 +264,8 @@ impl FromStr for InlineAsmArch { "mips" | "mips32r6" => Ok(Self::Mips), "mips64" | "mips64r6" => Ok(Self::Mips64), "s390x" => Ok(Self::S390x), + "sparc" => Ok(Self::Sparc), + "sparc64" => Ok(Self::Sparc64), "spirv" => Ok(Self::SpirV), "wasm32" => Ok(Self::Wasm32), "wasm64" => Ok(Self::Wasm64), @@ -286,6 +292,7 @@ pub enum InlineAsmReg { LoongArch(LoongArchInlineAsmReg), Mips(MipsInlineAsmReg), S390x(S390xInlineAsmReg), + Sparc(SparcInlineAsmReg), SpirV(SpirVInlineAsmReg), Wasm(WasmInlineAsmReg), Bpf(BpfInlineAsmReg), @@ -309,6 +316,7 @@ impl InlineAsmReg { Self::LoongArch(r) => r.name(), Self::Mips(r) => r.name(), Self::S390x(r) => r.name(), + Self::Sparc(r) => r.name(), Self::Bpf(r) => r.name(), Self::Avr(r) => r.name(), Self::Msp430(r) => r.name(), @@ -329,6 +337,7 @@ impl InlineAsmReg { Self::LoongArch(r) => InlineAsmRegClass::LoongArch(r.reg_class()), Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()), Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()), + Self::Sparc(r) => InlineAsmRegClass::Sparc(r.reg_class()), Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()), Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()), Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()), @@ -361,6 +370,9 @@ impl InlineAsmReg { Self::Mips(MipsInlineAsmReg::parse(name)?) } InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(name)?), + InlineAsmArch::Sparc | InlineAsmArch::Sparc64 => { + Self::Sparc(SparcInlineAsmReg::parse(name)?) + } InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(name)?), InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => { Self::Wasm(WasmInlineAsmReg::parse(name)?) @@ -393,6 +405,7 @@ impl InlineAsmReg { } Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), + Self::Sparc(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Avr(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Msp430(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), @@ -420,6 +433,7 @@ impl InlineAsmReg { Self::LoongArch(r) => r.emit(out, arch, modifier), Self::Mips(r) => r.emit(out, arch, modifier), Self::S390x(r) => r.emit(out, arch, modifier), + Self::Sparc(r) => r.emit(out, arch, modifier), Self::Bpf(r) => r.emit(out, arch, modifier), Self::Avr(r) => r.emit(out, arch, modifier), Self::Msp430(r) => r.emit(out, arch, modifier), @@ -440,6 +454,7 @@ impl InlineAsmReg { Self::LoongArch(_) => cb(self), Self::Mips(_) => cb(self), Self::S390x(r) => r.overlapping_regs(|r| cb(Self::S390x(r))), + Self::Sparc(_) => cb(self), Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))), Self::Msp430(_) => cb(self), @@ -463,6 +478,7 @@ pub enum InlineAsmRegClass { LoongArch(LoongArchInlineAsmRegClass), Mips(MipsInlineAsmRegClass), S390x(S390xInlineAsmRegClass), + Sparc(SparcInlineAsmRegClass), SpirV(SpirVInlineAsmRegClass), Wasm(WasmInlineAsmRegClass), Bpf(BpfInlineAsmRegClass), @@ -487,6 +503,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.name(), Self::Mips(r) => r.name(), Self::S390x(r) => r.name(), + Self::Sparc(r) => r.name(), Self::SpirV(r) => r.name(), Self::Wasm(r) => r.name(), Self::Bpf(r) => r.name(), @@ -513,6 +530,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::LoongArch), Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x), + Self::Sparc(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Sparc), Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV), Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm), Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf), @@ -542,6 +560,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.suggest_modifier(arch, ty), Self::Mips(r) => r.suggest_modifier(arch, ty), Self::S390x(r) => r.suggest_modifier(arch, ty), + Self::Sparc(r) => r.suggest_modifier(arch, ty), Self::SpirV(r) => r.suggest_modifier(arch, ty), Self::Wasm(r) => r.suggest_modifier(arch, ty), Self::Bpf(r) => r.suggest_modifier(arch, ty), @@ -571,6 +590,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.default_modifier(arch), Self::Mips(r) => r.default_modifier(arch), Self::S390x(r) => r.default_modifier(arch), + Self::Sparc(r) => r.default_modifier(arch), Self::SpirV(r) => r.default_modifier(arch), Self::Wasm(r) => r.default_modifier(arch), Self::Bpf(r) => r.default_modifier(arch), @@ -599,6 +619,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.supported_types(arch), Self::Mips(r) => r.supported_types(arch), Self::S390x(r) => r.supported_types(arch), + Self::Sparc(r) => r.supported_types(arch), Self::SpirV(r) => r.supported_types(arch), Self::Wasm(r) => r.supported_types(arch), Self::Bpf(r) => r.supported_types(arch), @@ -632,6 +653,9 @@ impl InlineAsmRegClass { Self::Mips(MipsInlineAsmRegClass::parse(name)?) } InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(name)?), + InlineAsmArch::Sparc | InlineAsmArch::Sparc64 => { + Self::Sparc(SparcInlineAsmRegClass::parse(name)?) + } InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(name)?), InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => { Self::Wasm(WasmInlineAsmRegClass::parse(name)?) @@ -658,6 +682,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.valid_modifiers(arch), Self::Mips(r) => r.valid_modifiers(arch), Self::S390x(r) => r.valid_modifiers(arch), + Self::Sparc(r) => r.valid_modifiers(arch), Self::SpirV(r) => r.valid_modifiers(arch), Self::Wasm(r) => r.valid_modifiers(arch), Self::Bpf(r) => r.valid_modifiers(arch), @@ -843,6 +868,11 @@ pub fn allocatable_registers( s390x::fill_reg_map(arch, reloc_model, target_features, target, &mut map); map } + InlineAsmArch::Sparc | InlineAsmArch::Sparc64 => { + let mut map = sparc::regclass_map(); + sparc::fill_reg_map(arch, reloc_model, target_features, target, &mut map); + map + } InlineAsmArch::SpirV => { let mut map = spirv::regclass_map(); spirv::fill_reg_map(arch, reloc_model, target_features, target, &mut map); @@ -1128,6 +1158,21 @@ impl InlineAsmClobberAbi { }, InlineAsmClobberAbi::PowerPC => clobbered_regs! { PowerPC PowerPCInlineAsmReg { + // Refs: + // - PPC32 SysV: "3.2. Function Calling Sequence" in Power Architecture® 32-bit Application Binary Interface Supplement 1.0 - Linux® & Embedded + // https://web.archive.org/web/20120608163804/https://www.power.org/resources/downloads/Power-Arch-32-bit-ABI-supp-1.0-Unified.pdf + // - PPC64 ELFv1: "3.2. Function Calling Sequence" in 64-bit PowerPC ELF Application Binary Interface Supplement 1.9 + // https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUNC-CALL + // - PPC64 ELFv2: "2.2 Function Calling Sequence" in 64-Bit ELF V2 ABI Specification: Power Architecture, Revision 1.5 + // https://openpowerfoundation.org/specifications/64bitelfabi/ + // - AIX: + // - Register usage and conventions + // https://www.ibm.com/docs/en/aix/7.3?topic=overview-register-usage-conventions + // - Special registers in the PowerPC® + // https://www.ibm.com/docs/en/aix/7.3?topic=overview-special-registers-in-powerpc + // - AIX vector programming + // https://www.ibm.com/docs/en/aix/7.3?topic=concepts-aix-vector-programming + // r0, r3-r12 r0, r3, r4, r5, r6, r7, @@ -1138,8 +1183,6 @@ impl InlineAsmClobberAbi { f8, f9, f10, f11, f12, f13, // v0-v19 - // FIXME: PPC32 SysV ABI does not mention vector registers processing. - // https://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, diff --git a/compiler/rustc_target/src/asm/sparc.rs b/compiler/rustc_target/src/asm/sparc.rs new file mode 100644 index 00000000000..6261708642b --- /dev/null +++ b/compiler/rustc_target/src/asm/sparc.rs @@ -0,0 +1,138 @@ +use std::fmt; + +use rustc_data_structures::fx::FxIndexSet; +use rustc_span::Symbol; + +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; +use crate::spec::{RelocModel, Target}; + +def_reg_class! { + Sparc SparcInlineAsmRegClass { + reg, + yreg, + } +} + +impl SparcInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<ModifierInfo> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> { + None + } + + pub fn supported_types( + self, + arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<Symbol>)] { + match self { + Self::reg => { + if arch == InlineAsmArch::Sparc { + types! { + _: I8, I16, I32; + // FIXME: i64 is ok for g*/o* registers on SPARC-V8+ ("h" constraint in GCC), + // but not yet supported in LLVM. + // v8plus: I64; + } + } else { + types! { _: I8, I16, I32, I64; } + } + } + Self::yreg => &[], + } + } +} + +fn reserved_g5( + arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxIndexSet<Symbol>, + _target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + if arch == InlineAsmArch::Sparc { + // FIXME: Section 2.1.5 "Function Registers with Unassigned Roles" of the V8+ Technical + // Specification says "%g5; no longer reserved for system software" [1], but LLVM always + // reserves it on SPARC32 [2]. + // [1]: https://temlib.org/pub/SparcStation/Standards/V8plus.pdf + // [2]: https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp#L64-L66 + Err("g5 is reserved for system on SPARC32") + } else { + Ok(()) + } +} + +def_regs! { + Sparc SparcInlineAsmReg SparcInlineAsmRegClass { + // FIXME: + // - LLVM has reserve-{g,o,l,i}N feature to reserve each general-purpose registers. + // - g2-g4 are reserved for application (optional in both LLVM and GCC, and GCC has -mno-app-regs option to reserve them). + // There are currently no builtin targets that use them, but in the future they may need to + // be supported via options similar to AArch64's -Z fixed-x18. + r2: reg = ["r2", "g2"], // % reserved_g2 + r3: reg = ["r3", "g3"], // % reserved_g3 + r4: reg = ["r4", "g4"], // % reserved_g4 + r5: reg = ["r5", "g5"] % reserved_g5, + r8: reg = ["r8", "o0"], // % reserved_o0 + r9: reg = ["r9", "o1"], // % reserved_o1 + r10: reg = ["r10", "o2"], // % reserved_o2 + r11: reg = ["r11", "o3"], // % reserved_o3 + r12: reg = ["r12", "o4"], // % reserved_o4 + r13: reg = ["r13", "o5"], // % reserved_o5 + r15: reg = ["r15", "o7"], // % reserved_o7 + r16: reg = ["r16", "l0"], // % reserved_l0 + r17: reg = ["r17", "l1"], // % reserved_l1 + r18: reg = ["r18", "l2"], // % reserved_l2 + r19: reg = ["r19", "l3"], // % reserved_l3 + r20: reg = ["r20", "l4"], // % reserved_l4 + r21: reg = ["r21", "l5"], // % reserved_l5 + r22: reg = ["r22", "l6"], // % reserved_l6 + r23: reg = ["r23", "l7"], // % reserved_l7 + r24: reg = ["r24", "i0"], // % reserved_i0 + r25: reg = ["r25", "i1"], // % reserved_i1 + r26: reg = ["r26", "i2"], // % reserved_i2 + r27: reg = ["r27", "i3"], // % reserved_i3 + r28: reg = ["r28", "i4"], // % reserved_i4 + r29: reg = ["r29", "i5"], // % reserved_i5 + y: yreg = ["y"], + #error = ["r0", "g0"] => + "g0 is always zero and cannot be used as an operand for inline asm", + // FIXME: %g1 is volatile in ABI, but used internally by LLVM. + // https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp#L55-L56 + // > FIXME: G1 reserved for now for large imm generation by frame code. + #error = ["r1", "g1"] => + "reserved by LLVM and cannot be used as an operand for inline asm", + #error = ["r6", "g6", "r7", "g7"] => + "reserved for system and cannot be used as an operand for inline asm", + #error = ["sp", "r14", "o6"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["fp", "r30", "i6"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["r31", "i7"] => + "the return address register cannot be used as an operand for inline asm", + } +} + +impl SparcInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option<char>, + ) -> fmt::Result { + write!(out, "%{}", self.name()) + } +} diff --git a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs index e83a43c1df2..b7415bf683d 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs @@ -20,7 +20,7 @@ pub(crate) fn target() -> Target { std: None, // ? }, pointer_width: 64, - data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), + data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: "mips64".into(), options: TargetOptions { abi: "abi64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs index 252d614e9ac..75da4abc6b6 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs @@ -11,7 +11,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), + data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: "mips64".into(), options: TargetOptions { abi: "abi64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs index a1a596c9f1b..69af2da1100 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), + data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: "mips64".into(), options: TargetOptions { abi: "abi64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs index 35d2911fa9d..c7d24871225 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs @@ -10,7 +10,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: "mips64".into(), options: TargetOptions { abi: "abi64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs index 9dab932aed4..4f50e8b7033 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: "mips64".into(), options: TargetOptions { abi: "abi64".into(), mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs index 89ba7b889ec..c5948b745ff 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs @@ -11,7 +11,7 @@ pub(crate) fn target() -> Target { std: None, // ? }, pointer_width: 64, - data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), + data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: "mips64r6".into(), options: TargetOptions { abi: "abi64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs index 195894d9aac..60bda7a5996 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs @@ -10,7 +10,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: "mips64r6".into(), options: TargetOptions { abi: "abi64".into(), diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 86072a6dd60..e29ed9a4b56 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -19,8 +19,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_next_trait_solver = { path = "../rustc_next_trait_solver" } rustc_parse_format = { path = "../rustc_parse_format" } -rustc_query_system = { path = "../rustc_query_system" } -rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index a1c97a38567..1109b11d2a7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1707,15 +1707,31 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // one crate version and the type comes from another crate version, even though they both // are from the same crate. let trait_def_id = trait_ref.def_id(); - if let ty::Adt(def, _) = trait_ref.self_ty().skip_binder().peel_refs().kind() - && let found_type = def.did() - && trait_def_id.krate != found_type.krate - && self.tcx.crate_name(trait_def_id.krate) == self.tcx.crate_name(found_type.krate) - { - let name = self.tcx.crate_name(trait_def_id.krate); - let spans: Vec<_> = [trait_def_id, found_type] - .into_iter() - .filter(|def_id| def_id.krate != LOCAL_CRATE) + let trait_name = self.tcx.item_name(trait_def_id); + let crate_name = self.tcx.crate_name(trait_def_id.krate); + if let Some(other_trait_def_id) = self.tcx.all_traits().find(|def_id| { + trait_name == self.tcx.item_name(trait_def_id) + && trait_def_id.krate != def_id.krate + && crate_name == self.tcx.crate_name(def_id.krate) + }) { + // We've found two different traits with the same name, same crate name, but + // different crate `DefId`. We highlight the traits. + + let found_type = + if let ty::Adt(def, _) = trait_ref.self_ty().skip_binder().peel_refs().kind() { + Some(def.did()) + } else { + None + }; + let candidates = if impl_candidates.is_empty() { + alternative_candidates(trait_def_id) + } else { + impl_candidates.into_iter().map(|cand| cand.trait_ref).collect() + }; + let mut span: MultiSpan = self.tcx.def_span(trait_def_id).into(); + span.push_span_label(self.tcx.def_span(trait_def_id), "this is the required trait"); + for (sp, label) in [trait_def_id, other_trait_def_id] + .iter() .filter_map(|def_id| self.tcx.extern_crate(def_id.krate)) .map(|data| { let dependency = if data.dependency_of == LOCAL_CRATE { @@ -1726,57 +1742,86 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; ( data.span, - format!("one version of crate `{name}` is used here, as a {dependency}"), + format!( + "one version of crate `{crate_name}` is used here, as a {dependency}" + ), ) }) - .collect(); - let mut span: MultiSpan = spans.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into(); - for (sp, label) in spans.into_iter() { + { span.push_span_label(sp, label); } - err.highlighted_span_help(span, vec![ + let mut points_at_type = false; + if let Some(found_type) = found_type { + span.push_span_label( + self.tcx.def_span(found_type), + "this type doesn't implement the required trait", + ); + for trait_ref in candidates { + if let ty::Adt(def, _) = trait_ref.self_ty().peel_refs().kind() + && let candidate_def_id = def.did() + && let Some(name) = self.tcx.opt_item_name(candidate_def_id) + && let Some(found) = self.tcx.opt_item_name(found_type) + && name == found + && candidate_def_id.krate != found_type.krate + && self.tcx.crate_name(candidate_def_id.krate) + == self.tcx.crate_name(found_type.krate) + { + // A candidate was found of an item with the same name, from two separate + // versions of the same crate, let's clarify. + let candidate_span = self.tcx.def_span(candidate_def_id); + span.push_span_label( + candidate_span, + "this type implements the required trait", + ); + points_at_type = true; + } + } + } + span.push_span_label(self.tcx.def_span(other_trait_def_id), "this is the found trait"); + err.highlighted_span_note(span, vec![ StringPart::normal("there are ".to_string()), StringPart::highlighted("multiple different versions".to_string()), StringPart::normal(" of crate `".to_string()), - StringPart::highlighted(format!("{name}")), - StringPart::normal("` in the dependency graph".to_string()), + StringPart::highlighted(format!("{crate_name}")), + StringPart::normal("` in the dependency graph\n".to_string()), ]); - let candidates = if impl_candidates.is_empty() { - alternative_candidates(trait_def_id) - } else { - impl_candidates.into_iter().map(|cand| cand.trait_ref).collect() - }; - if let Some((sp_candidate, sp_found)) = candidates.iter().find_map(|trait_ref| { - if let ty::Adt(def, _) = trait_ref.self_ty().peel_refs().kind() - && let candidate_def_id = def.did() - && let Some(name) = self.tcx.opt_item_name(candidate_def_id) - && let Some(found) = self.tcx.opt_item_name(found_type) - && name == found - && candidate_def_id.krate != found_type.krate - && self.tcx.crate_name(candidate_def_id.krate) - == self.tcx.crate_name(found_type.krate) - { - // A candidate was found of an item with the same name, from two separate - // versions of the same crate, let's clarify. - Some((self.tcx.def_span(candidate_def_id), self.tcx.def_span(found_type))) - } else { - None - } - }) { - let mut span: MultiSpan = vec![sp_candidate, sp_found].into(); - span.push_span_label(self.tcx.def_span(trait_def_id), "this is the required trait"); - span.push_span_label(sp_candidate, "this type implements the required trait"); - span.push_span_label(sp_found, "this type doesn't implement the required trait"); - err.highlighted_span_note(span, vec![ + if points_at_type { + // We only clarify that the same type from different crate versions are not the + // same when we *find* the same type coming from different crate versions, otherwise + // it could be that it was a type provided by a different crate than the one that + // provides the trait, and mentioning this adds verbosity without clarification. + err.highlighted_note(vec![ StringPart::normal( "two types coming from two different versions of the same crate are \ - different types " + different types " .to_string(), ), StringPart::highlighted("even if they look the same".to_string()), ]); } - err.help("you can use `cargo tree` to explore your dependency tree"); + err.highlighted_help(vec![ + StringPart::normal("you can use `".to_string()), + StringPart::highlighted("cargo tree".to_string()), + StringPart::normal("` to explore your dependency tree".to_string()), + ]); + + // FIXME: this is a giant hack for the benefit of this specific diagnostic. Because + // we're so nested in method calls before the error gets emitted, bubbling a single bit + // flag informing the top level caller to stop adding extra detail to the diagnostic, + // would actually be harder to follow. So we do something naughty here: we consume the + // diagnostic, emit it and leave in its place a "delayed bug" that will continue being + // modified but won't actually be printed to end users. This *is not ideal*, but allows + // us to reduce the verbosity of an error that is already quite verbose and increase its + // specificity. Below we modify the main message as well, in a way that *could* break if + // the implementation of Diagnostics change significantly, but that would be caught with + // a make test failure when this diagnostic is tested. + err.primary_message(format!( + "{} because the trait comes from a different crate version", + err.messages[0].0.as_str().unwrap(), + )); + let diag = err.clone(); + err.downgrade_to_delayed_bug(); + self.tcx.dcx().emit_diagnostic(diag); return true; } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 0838978a891..0184e93acf1 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -463,43 +463,64 @@ fn fn_abi_sanity_check<'tcx>( arg: &ArgAbi<'tcx, Ty<'tcx>>, ) { let tcx = cx.tcx(); + + if spec_abi == ExternAbi::Rust + || spec_abi == ExternAbi::RustCall + || spec_abi == ExternAbi::RustCold + { + if arg.layout.is_zst() { + // Casting closures to function pointers depends on ZST closure types being + // omitted entirely in the calling convention. + assert!(arg.is_ignore()); + } + if let PassMode::Indirect { on_stack, .. } = arg.mode { + assert!(!on_stack, "rust abi shouldn't use on_stack"); + } + } + match &arg.mode { - PassMode::Ignore => {} + PassMode::Ignore => { + assert!(arg.layout.is_zst() || arg.layout.is_uninhabited()); + } PassMode::Direct(_) => { // Here the Rust type is used to determine the actual ABI, so we have to be very - // careful. Scalar/ScalarPair is fine, since backends will generally use - // `layout.abi` and ignore everything else. We should just reject `Aggregate` - // entirely here, but some targets need to be fixed first. - if matches!(arg.layout.backend_repr, BackendRepr::Memory { .. }) { - // For an unsized type we'd only pass the sized prefix, so there is no universe - // in which we ever want to allow this. - assert!( - arg.layout.is_sized(), - "`PassMode::Direct` for unsized type in ABI: {:#?}", - fn_abi - ); - // This really shouldn't happen even for sized aggregates, since - // `immediate_llvm_type` will use `layout.fields` to turn this Rust type into an - // LLVM type. This means all sorts of Rust type details leak into the ABI. - // However wasm sadly *does* currently use this mode so we have to allow it -- - // but we absolutely shouldn't let any more targets do that. - // (Also see <https://github.com/rust-lang/rust/issues/115666>.) - // - // The unstable abi `PtxKernel` also uses Direct for now. - // It needs to switch to something else before stabilization can happen. - // (See issue: https://github.com/rust-lang/rust/issues/117271) - assert!( - matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64") - || matches!(spec_abi, ExternAbi::PtxKernel | ExternAbi::Unadjusted), - "`PassMode::Direct` for aggregates only allowed for \"unadjusted\" and \"ptx-kernel\" functions and on wasm\n\ + // careful. Scalar/Vector is fine, since backends will generally use + // `layout.backend_repr` and ignore everything else. We should just reject + //`Aggregate` entirely here, but some targets need to be fixed first. + match arg.layout.backend_repr { + BackendRepr::Uninhabited + | BackendRepr::Scalar(_) + | BackendRepr::Vector { .. } => {} + BackendRepr::ScalarPair(..) => { + panic!("`PassMode::Direct` used for ScalarPair type {}", arg.layout.ty) + } + BackendRepr::Memory { sized } => { + // For an unsized type we'd only pass the sized prefix, so there is no universe + // in which we ever want to allow this. + assert!(sized, "`PassMode::Direct` for unsized type in ABI: {:#?}", fn_abi); + // This really shouldn't happen even for sized aggregates, since + // `immediate_llvm_type` will use `layout.fields` to turn this Rust type into an + // LLVM type. This means all sorts of Rust type details leak into the ABI. + // However wasm sadly *does* currently use this mode so we have to allow it -- + // but we absolutely shouldn't let any more targets do that. + // (Also see <https://github.com/rust-lang/rust/issues/115666>.) + // + // The unstable abi `PtxKernel` also uses Direct for now. + // It needs to switch to something else before stabilization can happen. + // (See issue: https://github.com/rust-lang/rust/issues/117271) + assert!( + matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64") + || matches!(spec_abi, ExternAbi::PtxKernel | ExternAbi::Unadjusted), + "`PassMode::Direct` for aggregates only allowed for \"unadjusted\" and \"ptx-kernel\" functions and on wasm\n\ Problematic type: {:#?}", - arg.layout, - ); + arg.layout, + ); + } } } PassMode::Pair(_, _) => { - // Similar to `Direct`, we need to make sure that backends use `layout.abi` and - // ignore the rest of the layout. + // Similar to `Direct`, we need to make sure that backends use `layout.backend_repr` + // and ignore the rest of the layout. assert!( matches!(arg.layout.backend_repr, BackendRepr::ScalarPair(..)), "PassMode::Pair for type {}", diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 4b7707ebccf..a6f7c254583 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -34,6 +34,12 @@ pub trait Context { /// Check whether the body of a function is available. fn has_body(&self, item: DefId) -> bool; fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef>; + + /// Retrieve all functions defined in this crate. + fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef>; + + /// Retrieve all static items defined in this crate. + fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef>; fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule; fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef>; fn all_trait_decls(&self) -> TraitDecls; diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index b523e949cde..0b4cebadad1 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -25,8 +25,9 @@ use serde::Serialize; use crate::compiler_interface::with; pub use crate::crate_def::{CrateDef, CrateDefType, DefId}; pub use crate::error::*; +use crate::mir::mono::StaticDef; use crate::mir::{Body, Mutability}; -use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty}; +use crate::ty::{FnDef, ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty}; pub mod abi; #[macro_use] @@ -96,6 +97,16 @@ impl Crate { pub fn trait_impls(&self) -> ImplTraitDecls { with(|cx| cx.trait_impls(self.id)) } + + /// Return a list of function definitions from this crate independent on their visibility. + pub fn fn_defs(&self) -> Vec<FnDef> { + with(|cx| cx.crate_functions(self.id)) + } + + /// Return a list of static items defined in this crate independent on their visibility. + pub fn statics(&self) -> Vec<StaticDef> { + with(|cx| cx.crate_statics(self.id)) + } } #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 13e3d229d06..01a50d46b2d 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -1,13 +1,14 @@ +//! Implement methods to pretty print stable MIR body. use std::fmt::Debug; use std::io::Write; use std::{fmt, io, iter}; use fmt::{Display, Formatter}; -use super::{AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind}; +use super::{AggregateKind, AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind}; use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents}; -use crate::ty::{IndexedVal, MirConst, Ty, TyConst}; -use crate::{Body, Mutability, with}; +use crate::ty::{AdtKind, IndexedVal, MirConst, Ty, TyConst}; +use crate::{Body, CrateDef, Mutability, with}; impl Display for Ty { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -23,10 +24,11 @@ impl Debug for Place { pub(crate) fn function_body<W: Write>(writer: &mut W, body: &Body, name: &str) -> io::Result<()> { write!(writer, "fn {name}(")?; - body.arg_locals() - .iter() - .enumerate() - .try_for_each(|(index, local)| write!(writer, "_{}: {}", index + 1, local.ty))?; + let mut sep = ""; + for (index, local) in body.arg_locals().iter().enumerate() { + write!(writer, "{}_{}: {}", sep, index + 1, local.ty)?; + sep = ", "; + } write!(writer, ")")?; let return_local = body.ret_local(); @@ -73,39 +75,40 @@ pub(crate) fn function_body<W: Write>(writer: &mut W, body: &Body, name: &str) - } fn pretty_statement<W: Write>(writer: &mut W, statement: &StatementKind) -> io::Result<()> { + const INDENT: &str = " "; match statement { StatementKind::Assign(place, rval) => { - write!(writer, " {place:?} = ")?; + write!(writer, "{INDENT}{place:?} = ")?; pretty_rvalue(writer, rval)?; writeln!(writer, ";") } // FIXME: Add rest of the statements StatementKind::FakeRead(cause, place) => { - writeln!(writer, "FakeRead({cause:?}, {place:?});") + writeln!(writer, "{INDENT}FakeRead({cause:?}, {place:?});") } StatementKind::SetDiscriminant { place, variant_index } => { - writeln!(writer, "discriminant({place:?} = {};", variant_index.to_index()) + writeln!(writer, "{INDENT}discriminant({place:?} = {};", variant_index.to_index()) } StatementKind::Deinit(place) => writeln!(writer, "Deinit({place:?};"), StatementKind::StorageLive(local) => { - writeln!(writer, "StorageLive(_{local});") + writeln!(writer, "{INDENT}StorageLive(_{local});") } StatementKind::StorageDead(local) => { - writeln!(writer, "StorageDead(_{local});") + writeln!(writer, "{INDENT}StorageDead(_{local});") } StatementKind::Retag(kind, place) => writeln!(writer, "Retag({kind:?}, {place:?});"), StatementKind::PlaceMention(place) => { - writeln!(writer, "PlaceMention({place:?};") + writeln!(writer, "{INDENT}PlaceMention({place:?};") } StatementKind::ConstEvalCounter => { - writeln!(writer, "ConstEvalCounter;") + writeln!(writer, "{INDENT}ConstEvalCounter;") } - StatementKind::Nop => writeln!(writer, "nop;"), + StatementKind::Nop => writeln!(writer, "{INDENT}nop;"), StatementKind::AscribeUserType { .. } | StatementKind::Coverage(_) | StatementKind::Intrinsic(_) => { // FIX-ME: Make them pretty. - writeln!(writer, "{statement:?};") + writeln!(writer, "{INDENT}{statement:?};") } } } @@ -322,15 +325,11 @@ fn pretty_ty_const(ct: &TyConst) -> String { fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> { match rval { Rvalue::AddressOf(mutability, place) => { - write!(writer, "&raw {}(*{:?})", pretty_mut(*mutability), place) + write!(writer, "&raw {} {:?}", pretty_mut(*mutability), place) } Rvalue::Aggregate(aggregate_kind, operands) => { // FIXME: Add pretty_aggregate function that returns a pretty string - write!(writer, "{aggregate_kind:?} (")?; - let mut op_iter = operands.iter(); - op_iter.next().map_or(Ok(()), |op| write!(writer, "{}", pretty_operand(op)))?; - op_iter.try_for_each(|op| write!(writer, ", {}", pretty_operand(op)))?; - write!(writer, ")") + pretty_aggregate(writer, aggregate_kind, operands) } Rvalue::BinaryOp(bin, op1, op2) => { write!(writer, "{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2)) @@ -360,22 +359,74 @@ fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> { write!(writer, "{kind}{place:?}") } Rvalue::Repeat(op, cnst) => { - write!(writer, "{} \" \" {}", pretty_operand(op), pretty_ty_const(cnst)) + write!(writer, "[{}; {}]", pretty_operand(op), pretty_ty_const(cnst)) } Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::ThreadLocalRef(item) => { write!(writer, "thread_local_ref{item:?}") } Rvalue::NullaryOp(nul, ty) => { - write!(writer, "{nul:?} {ty} \" \"") + write!(writer, "{nul:?}::<{ty}>() \" \"") } Rvalue::UnaryOp(un, op) => { - write!(writer, "{} \" \" {:?}", pretty_operand(op), un) + write!(writer, "{:?}({})", un, pretty_operand(op)) } Rvalue::Use(op) => write!(writer, "{}", pretty_operand(op)), } } +fn pretty_aggregate<W: Write>( + writer: &mut W, + aggregate_kind: &AggregateKind, + operands: &Vec<Operand>, +) -> io::Result<()> { + let suffix = match aggregate_kind { + AggregateKind::Array(_) => { + write!(writer, "[")?; + "]" + } + AggregateKind::Tuple => { + write!(writer, "(")?; + ")" + } + AggregateKind::Adt(def, var, _, _, _) => { + if def.kind() == AdtKind::Enum { + write!(writer, "{}::{}", def.name(), def.variant(*var).unwrap().name())?; + } else { + write!(writer, "{}", def.variant(*var).unwrap().name())?; + } + if operands.is_empty() { + return Ok(()); + } + // FIXME: Change this once we have CtorKind in StableMIR. + write!(writer, "(")?; + ")" + } + AggregateKind::Closure(def, _) => { + write!(writer, "{{closure@{}}}(", def.span().diagnostic())?; + ")" + } + AggregateKind::Coroutine(def, _, _) => { + write!(writer, "{{coroutine@{}}}(", def.span().diagnostic())?; + ")" + } + AggregateKind::RawPtr(ty, mutability) => { + write!( + writer, + "*{} {ty} from (", + if *mutability == Mutability::Mut { "mut" } else { "const" } + )?; + ")" + } + }; + let mut separator = ""; + for op in operands { + write!(writer, "{}{}", separator, pretty_operand(op))?; + separator = ", "; + } + write!(writer, "{suffix}") +} + fn pretty_mut(mutability: Mutability) -> &'static str { match mutability { Mutability::Not => " ", diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 8db1258b65f..9ce72f155f9 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -271,6 +271,14 @@ impl Span { pub fn get_lines(&self) -> LineInfo { with(|c| c.get_lines(self)) } + + /// Return the span location to be printed in diagnostic messages. + /// + /// This may leak local file paths and should not be used to build artifacts that may be + /// distributed. + pub fn diagnostic(&self) -> String { + with(|c| c.span_to_string(*self)) + } } #[derive(Clone, Copy, Debug, Serialize)] diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics/mod.rs index d33a403cfda..b6e22c42eee 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics/mod.rs @@ -904,38 +904,6 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn prefetch_write_instruction<T>(data: *const T, locality: i32); - /// Magic intrinsic that derives its meaning from attributes - /// attached to the function. - /// - /// For example, dataflow uses this to inject static assertions so - /// that `rustc_peek(potentially_uninitialized)` would actually - /// double-check that dataflow did indeed compute that it is - /// uninitialized at that point in the control flow. - /// - /// This intrinsic should not be used outside of the compiler. - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn rustc_peek<T>(_: T) -> T; - - /// Aborts the execution of the process. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// [`std::process::abort`](../../std/process/fn.abort.html) is to be preferred if possible, - /// as its behavior is more user-friendly and more stable. - /// - /// The current implementation of `intrinsics::abort` is to invoke an invalid instruction, - /// on most platforms. - /// On Unix, the - /// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or - /// `SIGBUS`. The precise behavior is not guaranteed and not stable. - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn abort() -> !; - /// Executes a breakpoint trap, for inspection by a debugger. /// /// This intrinsic does not have a stable counterpart. @@ -943,6 +911,44 @@ extern "rust-intrinsic" { pub fn breakpoint(); } +/// Magic intrinsic that derives its meaning from attributes +/// attached to the function. +/// +/// For example, dataflow uses this to inject static assertions so +/// that `rustc_peek(potentially_uninitialized)` would actually +/// double-check that dataflow did indeed compute that it is +/// uninitialized at that point in the control flow. +/// +/// This intrinsic should not be used outside of the compiler. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn rustc_peek<T>(_: T) -> T { + unreachable!() +} + +/// Aborts the execution of the process. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// [`std::process::abort`](../../std/process/fn.abort.html) is to be preferred if possible, +/// as its behavior is more user-friendly and more stable. +/// +/// The current implementation of `intrinsics::abort` is to invoke an invalid instruction, +/// on most platforms. +/// On Unix, the +/// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or +/// `SIGBUS`. The precise behavior is not guaranteed and not stable. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn abort() -> ! { + unreachable!() +} + /// Informs the optimizer that this point in the code is not reachable, /// enabling further optimizations. /// @@ -1512,19 +1518,22 @@ pub const unsafe fn arith_offset<T>(_dst: *const T, _offset: isize) -> *const T unreachable!() } -extern "rust-intrinsic" { - /// Masks out bits of the pointer according to a mask. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// Consider using [`pointer::mask`] instead. - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T; +/// Masks out bits of the pointer according to a mask. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// Consider using [`pointer::mask`] instead. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn ptr_mask<T>(_ptr: *const T, _mask: usize) -> *const T { + unreachable!() +} +extern "rust-intrinsic" { /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with /// a size of `count` * `size_of::<T>()` and an alignment of /// `min_align_of::<T>()` @@ -2140,47 +2149,62 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn frem_fast<T: Copy>(a: T, b: T) -> T; - /// Float addition that allows optimizations based on algebraic rules. + /// Converts with LLVM’s fptoui/fptosi, which may return undef for values out of range + /// (<https://github.com/rust-lang/rust/issues/10184>) /// - /// This intrinsic does not have a stable counterpart. + /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. #[rustc_nounwind] - #[rustc_safe_intrinsic] - pub fn fadd_algebraic<T: Copy>(a: T, b: T) -> T; + pub fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +} - /// Float subtraction that allows optimizations based on algebraic rules. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_safe_intrinsic] - pub fn fsub_algebraic<T: Copy>(a: T, b: T) -> T; +/// Float addition that allows optimizations based on algebraic rules. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn fadd_algebraic<T: Copy>(_a: T, _b: T) -> T { + unimplemented!() +} - /// Float multiplication that allows optimizations based on algebraic rules. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_safe_intrinsic] - pub fn fmul_algebraic<T: Copy>(a: T, b: T) -> T; +/// Float subtraction that allows optimizations based on algebraic rules. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn fsub_algebraic<T: Copy>(_a: T, _b: T) -> T { + unimplemented!() +} - /// Float division that allows optimizations based on algebraic rules. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_safe_intrinsic] - pub fn fdiv_algebraic<T: Copy>(a: T, b: T) -> T; +/// Float multiplication that allows optimizations based on algebraic rules. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn fmul_algebraic<T: Copy>(_a: T, _b: T) -> T { + unimplemented!() +} - /// Float remainder that allows optimizations based on algebraic rules. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_safe_intrinsic] - pub fn frem_algebraic<T: Copy>(a: T, b: T) -> T; +/// Float division that allows optimizations based on algebraic rules. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn fdiv_algebraic<T: Copy>(_a: T, _b: T) -> T { + unimplemented!() +} - /// Converts with LLVM’s fptoui/fptosi, which may return undef for values out of range - /// (<https://github.com/rust-lang/rust/issues/10184>) - /// - /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. - #[rustc_nounwind] - pub fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +/// Float remainder that allows optimizations based on algebraic rules. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn frem_algebraic<T: Copy>(_a: T, _b: T) -> T { + unimplemented!() } /// Returns the number of bits set in an integer type `T` diff --git a/library/std/src/f128/tests.rs b/library/std/src/f128/tests.rs index 7051c051bf7..cbcf9f96239 100644 --- a/library/std/src/f128/tests.rs +++ b/library/std/src/f128/tests.rs @@ -2,7 +2,10 @@ #![cfg(reliable_f128)] use crate::f128::consts; -use crate::num::{FpCategory as Fp, *}; +use crate::num::FpCategory as Fp; +#[cfg(reliable_f128_math)] +use crate::ops::Rem; +use crate::ops::{Add, Div, Mul, Sub}; // Note these tolerances make sense around zero, but not for more extreme exponents. @@ -53,7 +56,22 @@ macro_rules! assert_f128_biteq { #[test] fn test_num_f128() { - test_num(10f128, 2f128); + // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128` + // function is available on all platforms. + let ten = 10f128; + let two = 2f128; + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_num_f128_rem() { + let ten = 10f128; + let two = 2f128; + assert_eq!(ten.rem(two), ten % two); } #[test] diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs index 88a8c75f7c8..523e6d2f3bb 100644 --- a/library/std/src/sync/mpmc/list.rs +++ b/library/std/src/sync/mpmc/list.rs @@ -63,14 +63,14 @@ struct Block<T> { impl<T> Block<T> { /// Creates an empty block. - fn new() -> Block<T> { + fn new() -> Box<Block<T>> { // SAFETY: This is safe because: // [1] `Block::next` (AtomicPtr) may be safely zero initialized. // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4]. // [3] `Slot::msg` (UnsafeCell) may be safely zero initialized because it // holds a MaybeUninit. // [4] `Slot::state` (AtomicUsize) may be safely zero initialized. - unsafe { MaybeUninit::zeroed().assume_init() } + unsafe { Box::new_zeroed().assume_init() } } /// Waits until the next pointer is set. @@ -199,13 +199,13 @@ impl<T> Channel<T> { // If we're going to have to install the next block, allocate it in advance in order to // make the wait for other threads as short as possible. if offset + 1 == BLOCK_CAP && next_block.is_none() { - next_block = Some(Box::new(Block::<T>::new())); + next_block = Some(Block::<T>::new()); } // If this is the first message to be sent into the channel, we need to allocate the // first block and install it. if block.is_null() { - let new = Box::into_raw(Box::new(Block::<T>::new())); + let new = Box::into_raw(Block::<T>::new()); if self .tail diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index e9ec79e417b..409a644b9be 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -33,7 +33,7 @@ fn main() { // Display PID of process holding the lock // PID will be stored in a lock file let lock_path = config.out.join("lock"); - let pid = fs::read_to_string(&lock_path).unwrap_or_default(); + let pid = fs::read_to_string(&lock_path); build_lock = fd_lock::RwLock::new(t!(fs::OpenOptions::new() .write(true) @@ -47,7 +47,11 @@ fn main() { } err => { drop(err); - println!("WARNING: build directory locked by process {pid}, waiting for lock"); + if let Ok(pid) = pid { + println!("WARNING: build directory locked by process {pid}, waiting for lock"); + } else { + println!("WARNING: build directory locked, waiting for lock"); + } let mut lock = t!(build_lock.write()); t!(lock.write(process::id().to_string().as_ref())); lock diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index bcce2748c2e..2c36d8bab82 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1938,9 +1938,13 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--json"); - if builder.config.rust_debug_assertions_std { - cmd.arg("--with-debug-assertions"); - }; + if builder.config.rustc_debug_assertions { + cmd.arg("--with-rustc-debug-assertions"); + } + + if builder.config.std_debug_assertions { + cmd.arg("--with-std-debug-assertions"); + } let mut llvm_components_passed = false; let mut copts_passed = false; diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index c3d0994f164..134da5db96d 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -833,9 +833,9 @@ impl Builder<'_> { cargo.env( profile_var("DEBUG_ASSERTIONS"), if mode == Mode::Std { - self.config.rust_debug_assertions_std.to_string() + self.config.std_debug_assertions.to_string() } else { - self.config.rust_debug_assertions.to_string() + self.config.rustc_debug_assertions.to_string() }, ); cargo.env( diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 8115aea033d..f977c285a74 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -263,8 +263,10 @@ pub struct Config { pub rust_optimize: RustOptimize, pub rust_codegen_units: Option<u32>, pub rust_codegen_units_std: Option<u32>, - pub rust_debug_assertions: bool, - pub rust_debug_assertions_std: bool, + + pub rustc_debug_assertions: bool, + pub std_debug_assertions: bool, + pub rust_overflow_checks: bool, pub rust_overflow_checks_std: bool, pub rust_debug_logging: bool, @@ -1115,9 +1117,9 @@ define_config! { debug: Option<bool> = "debug", codegen_units: Option<u32> = "codegen-units", codegen_units_std: Option<u32> = "codegen-units-std", - debug_assertions: Option<bool> = "debug-assertions", + rustc_debug_assertions: Option<bool> = "debug-assertions", randomize_layout: Option<bool> = "randomize-layout", - debug_assertions_std: Option<bool> = "debug-assertions-std", + std_debug_assertions: Option<bool> = "debug-assertions-std", overflow_checks: Option<bool> = "overflow-checks", overflow_checks_std: Option<bool> = "overflow-checks-std", debug_logging: Option<bool> = "debug-logging", @@ -1652,8 +1654,8 @@ impl Config { let mut llvm_offload = None; let mut llvm_plugins = None; let mut debug = None; - let mut debug_assertions = None; - let mut debug_assertions_std = None; + let mut rustc_debug_assertions = None; + let mut std_debug_assertions = None; let mut overflow_checks = None; let mut overflow_checks_std = None; let mut debug_logging = None; @@ -1675,8 +1677,8 @@ impl Config { debug: debug_toml, codegen_units, codegen_units_std, - debug_assertions: debug_assertions_toml, - debug_assertions_std: debug_assertions_std_toml, + rustc_debug_assertions: rustc_debug_assertions_toml, + std_debug_assertions: std_debug_assertions_toml, overflow_checks: overflow_checks_toml, overflow_checks_std: overflow_checks_std_toml, debug_logging: debug_logging_toml, @@ -1734,8 +1736,8 @@ impl Config { config.download_ci_rustc_commit(download_rustc, config.llvm_assertions); debug = debug_toml; - debug_assertions = debug_assertions_toml; - debug_assertions_std = debug_assertions_std_toml; + rustc_debug_assertions = rustc_debug_assertions_toml; + std_debug_assertions = std_debug_assertions_toml; overflow_checks = overflow_checks_toml; overflow_checks_std = overflow_checks_std_toml; debug_logging = debug_logging_toml; @@ -2148,14 +2150,13 @@ impl Config { config.rust_std_features = std_features.unwrap_or(default_std_features); let default = debug == Some(true); - config.rust_debug_assertions = debug_assertions.unwrap_or(default); - config.rust_debug_assertions_std = - debug_assertions_std.unwrap_or(config.rust_debug_assertions); + config.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default); + config.std_debug_assertions = std_debug_assertions.unwrap_or(config.rustc_debug_assertions); config.rust_overflow_checks = overflow_checks.unwrap_or(default); config.rust_overflow_checks_std = overflow_checks_std.unwrap_or(config.rust_overflow_checks); - config.rust_debug_logging = debug_logging.unwrap_or(config.rust_debug_assertions); + config.rust_debug_logging = debug_logging.unwrap_or(config.rustc_debug_assertions); let with_defaults = |debuginfo_level_specific: Option<_>| { debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) { @@ -3075,8 +3076,8 @@ fn check_incompatible_options_for_ci_rustc( debug: _, codegen_units: _, codegen_units_std: _, - debug_assertions: _, - debug_assertions_std: _, + rustc_debug_assertions: _, + std_debug_assertions: _, overflow_checks: _, overflow_checks_std: _, debuginfo_level: _, diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index 5264f778a93..3029c3989c9 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -20,6 +20,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - CSKY - s390x - Arm64EC +- SPARC ## Register classes @@ -56,6 +57,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | s390x | `freg` | `f[0-15]` | `f` | | s390x | `vreg` | `v[0-31]` | Only clobbers | | s390x | `areg` | `a[2-15]` | Only clobbers | +| SPARC | `reg` | `r[2-29]` | `r` | +| SPARC | `yreg` | `y` | Only clobbers | | Arm64EC | `reg` | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r` | | Arm64EC | `vreg` | `v[0-15]` | `w` | | Arm64EC | `vreg_low16` | `v[0-15]` | `x` | @@ -97,6 +100,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | s390x | `freg` | None | `f32`, `f64` | | s390x | `vreg` | N/A | Only clobbers | | s390x | `areg` | N/A | Only clobbers | +| SPARC | `reg` | None | `i8`, `i16`, `i32`, `i64` (SPARC64 only) | +| SPARC | `yreg` | N/A | Only clobbers | | Arm64EC | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | | Arm64EC | `vreg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | @@ -135,6 +140,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `r29` | `rtb` | | CSKY | `r30` | `svbr` | | CSKY | `r31` | `tls` | +| SPARC | `r[0-7]` | `g[0-7]` | +| SPARC | `r[8-15]` | `o[0-7]` | +| SPARC | `r[16-23]` | `l[0-7]` | +| SPARC | `r[24-31]` | `i[0-7]` | | Arm64EC | `x[0-30]` | `w[0-30]` | | Arm64EC | `x29` | `fp` | | Arm64EC | `x30` | `lr` | @@ -150,8 +159,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | +| All | `sp`, `r15` (s390x), `r14`/`o6` (SPARC) | The stack pointer must be restored to its original value at the end of an asm code block. | +| All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `r30`/`i6` (SPARC), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | | All | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC), `x19` (Arm64EC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | @@ -174,6 +183,11 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `r31` | This is the TLS register. | | s390x | `c[0-15]` | Reserved by the kernel. | | s390x | `a[0-1]` | Reserved for system use. | +| SPARC | `r0`/`g0` | This is always zero and cannot be used as inputs or outputs. | +| SPARC | `r1`/`g1` | Used internally by LLVM. | +| SPARC | `r5`/`g5` | Reserved for system. (SPARC32 only) | +| SPARC | `r6`/`g6`, `r7`/`g7` | Reserved for system. | +| SPARC | `r31`/`i7` | Return address cannot be used as inputs or outputs. | | Arm64EC | `xzr` | This is a constant zero register which can't be modified. | | Arm64EC | `x18` | This is an OS-reserved register. | | Arm64EC | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]` | These are AArch64 registers that are not supported for Arm64EC. | @@ -195,6 +209,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | s390x | `reg` | None | `%r0` | None | | s390x | `reg_addr` | None | `%r1` | None | | s390x | `freg` | None | `%f0` | None | +| SPARC | `reg` | None | `%o0` | None | | CSKY | `reg` | None | `r0` | None | | CSKY | `freg` | None | `f0` | None | | Arm64EC | `reg` | None | `x0` | `x` | @@ -219,6 +234,9 @@ These flags registers must be restored upon exiting the asm block if the `preser - The condition code register `ccr`. - s390x - The condition code register `cc`. +- SPARC + - Integer condition codes (`icc` and `xcc`) + - Floating-point condition codes (`fcc[0-3]`) - Arm64EC - Condition flags (`NZCV` register). - Floating-point status (`FPSR` register). diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md index c262d3f6da1..13a6814d31b 100644 --- a/src/doc/unstable-book/src/language-features/intrinsics.md +++ b/src/doc/unstable-book/src/language-features/intrinsics.md @@ -18,7 +18,7 @@ All intrinsic fallback bodies are automatically made cross-crate inlineable (lik by the codegen backend, but not the MIR inliner. ```rust -#![feature(rustc_attrs)] +#![feature(intrinsics)] #![allow(internal_features)] #[rustc_intrinsic] @@ -28,7 +28,7 @@ const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} Since these are just regular functions, it is perfectly ok to create the intrinsic twice: ```rust -#![feature(rustc_attrs)] +#![feature(intrinsics)] #![allow(internal_features)] #[rustc_intrinsic] diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 3134d25e544..980a9f7a47c 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -42,10 +42,16 @@ impl ScrapeExamplesOptions { scrape_tests, }), (Some(_), false, _) | (None, true, _) => { - dcx.fatal("must use --scrape-examples-output-path and --scrape-examples-target-crate together"); + dcx.fatal( + "must use --scrape-examples-output-path and --scrape-examples-target-crate \ + together", + ); } (None, false, true) => { - dcx.fatal("must use --scrape-examples-output-path and --scrape-examples-target-crate with --scrape-tests"); + dcx.fatal( + "must use --scrape-examples-output-path and \ + --scrape-examples-target-crate with --scrape-tests", + ); } (None, false, false) => None, } @@ -163,14 +169,15 @@ where }; // If this span comes from a macro expansion, then the source code may not actually show - // a use of the given item, so it would be a poor example. Hence, we skip all uses in macros. + // a use of the given item, so it would be a poor example. Hence, we skip all uses in + // macros. if call_span.from_expansion() { trace!("Rejecting expr from macro: {call_span:?}"); return; } - // If the enclosing item has a span coming from a proc macro, then we also don't want to include - // the example. + // If the enclosing item has a span coming from a proc macro, then we also don't want to + // include the example. let enclosing_item_span = tcx.hir().span_with_body(tcx.hir().get_parent_item(ex.hir_id).into()); if enclosing_item_span.from_expansion() { @@ -178,11 +185,12 @@ where return; } - // If the enclosing item doesn't actually enclose the call, this means we probably have a weird - // macro issue even though the spans aren't tagged as being from an expansion. + // If the enclosing item doesn't actually enclose the call, this means we probably have a + // weird macro issue even though the spans aren't tagged as being from an expansion. if !enclosing_item_span.contains(call_span) { warn!( - "Attempted to scrape call at [{call_span:?}] whose enclosing item [{enclosing_item_span:?}] doesn't contain the span of the call." + "Attempted to scrape call at [{call_span:?}] whose enclosing item \ + [{enclosing_item_span:?}] doesn't contain the span of the call." ); return; } @@ -190,7 +198,8 @@ where // Similarly for the call w/ the function ident. if !call_span.contains(ident_span) { warn!( - "Attempted to scrape call at [{call_span:?}] whose identifier [{ident_span:?}] was not contained in the span of the call." + "Attempted to scrape call at [{call_span:?}] whose identifier [{ident_span:?}] was \ + not contained in the span of the call." ); return; } @@ -224,7 +233,8 @@ where Some(url) => url, None => { trace!( - "Rejecting expr ({call_span:?}) whose clean span ({clean_span:?}) cannot be turned into a link" + "Rejecting expr ({call_span:?}) whose clean span ({clean_span:?}) \ + cannot be turned into a link" ); return; } @@ -272,7 +282,8 @@ pub(crate) fn run( let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?; // Collect CrateIds corresponding to provided target crates - // If two different versions of the crate in the dependency tree, then examples will be collected from both. + // If two different versions of the crate in the dependency tree, then examples will be + // collected from both. let all_crates = tcx .crates(()) .iter() diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index ecb8343fba3..e6fbba943a4 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -236,8 +236,11 @@ pub struct Config { /// Run ignored tests pub run_ignored: bool, - /// Whether to run tests with `ignore-debug` header - pub with_debug_assertions: bool, + /// Whether rustc was built with debug assertions. + pub with_rustc_debug_assertions: bool, + + /// Whether std was built with debug assertions. + pub with_std_debug_assertions: bool, /// Only run tests that match these filters pub filters: Vec<String>, diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 980b3f6829a..8570a8ce115 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -46,7 +46,6 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-coverage-map", "ignore-coverage-run", "ignore-cross-compile", - "ignore-debug", "ignore-eabi", "ignore-emscripten", "ignore-endian-big", @@ -82,6 +81,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-powerpc", "ignore-remote", "ignore-riscv64", + "ignore-rustc-debug-assertions", "ignore-s390x", "ignore-sgx", "ignore-sparc64", @@ -89,6 +89,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-stable", "ignore-stage1", "ignore-stage2", + "ignore-std-debug-assertions", "ignore-test", "ignore-thumb", "ignore-thumbv8m.base-none-eabi", @@ -135,6 +136,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-relocation-model-pic", "needs-run-enabled", "needs-rust-lld", + "needs-rustc-debug-assertions", "needs-sanitizer-address", "needs-sanitizer-cfi", "needs-sanitizer-dataflow", @@ -147,6 +149,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-sanitizer-shadow-call-stack", "needs-sanitizer-support", "needs-sanitizer-thread", + "needs-std-debug-assertions", "needs-symlink", "needs-threads", "needs-unwind", diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index b9314f0abbb..3ab552903dc 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -202,9 +202,14 @@ pub(super) fn parse_cfg_name_directive<'a>( message: "when running tests remotely", } condition! { - name: "debug", - condition: config.with_debug_assertions, - message: "when running tests with `ignore-debug` header", + name: "rustc-debug-assertions", + condition: config.with_rustc_debug_assertions, + message: "when rustc is built with debug assertions", + } + condition! { + name: "std-debug-assertions", + condition: config.with_std_debug_assertions, + message: "when std is built with debug assertions", } condition! { name: config.debugger.as_ref().map(|d| d.to_str()), diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index a744fb61b9c..77570c58db5 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -159,6 +159,16 @@ pub(super) fn handle_needs( condition: cache.llvm_zstd, ignore_reason: "ignored if LLVM wasn't build with zstd for ELF section compression", }, + Need { + name: "needs-rustc-debug-assertions", + condition: config.with_rustc_debug_assertions, + ignore_reason: "ignored if rustc wasn't built with debug assertions", + }, + Need { + name: "needs-std-debug-assertions", + condition: config.with_std_debug_assertions, + ignore_reason: "ignored if std wasn't built with debug assertions", + }, ]; let (name, comment) = match ln.split_once([':', ' ']) { diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index c79825e9e2a..c3fb8d4ab80 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -74,6 +74,8 @@ struct ConfigBuilder { git_hash: bool, system_llvm: bool, profiler_runtime: bool, + rustc_debug_assertions: bool, + std_debug_assertions: bool, } impl ConfigBuilder { @@ -122,6 +124,16 @@ impl ConfigBuilder { self } + fn rustc_debug_assertions(&mut self, is_enabled: bool) -> &mut Self { + self.rustc_debug_assertions = is_enabled; + self + } + + fn std_debug_assertions(&mut self, is_enabled: bool) -> &mut Self { + self.std_debug_assertions = is_enabled; + self + } + fn build(&mut self) -> Config { let args = &[ "compiletest", @@ -170,6 +182,12 @@ impl ConfigBuilder { if self.profiler_runtime { args.push("--profiler-runtime".to_owned()); } + if self.rustc_debug_assertions { + args.push("--with-rustc-debug-assertions".to_owned()); + } + if self.std_debug_assertions { + args.push("--with-std-debug-assertions".to_owned()); + } args.push("--rustc-path".to_string()); // This is a subtle/fragile thing. On rust-lang CI, there is no global @@ -315,6 +333,32 @@ fn only_target() { } #[test] +fn rustc_debug_assertions() { + let config: Config = cfg().rustc_debug_assertions(false).build(); + + assert!(check_ignore(&config, "//@ needs-rustc-debug-assertions")); + assert!(!check_ignore(&config, "//@ ignore-rustc-debug-assertions")); + + let config: Config = cfg().rustc_debug_assertions(true).build(); + + assert!(!check_ignore(&config, "//@ needs-rustc-debug-assertions")); + assert!(check_ignore(&config, "//@ ignore-rustc-debug-assertions")); +} + +#[test] +fn std_debug_assertions() { + let config: Config = cfg().std_debug_assertions(false).build(); + + assert!(check_ignore(&config, "//@ needs-std-debug-assertions")); + assert!(!check_ignore(&config, "//@ ignore-std-debug-assertions")); + + let config: Config = cfg().std_debug_assertions(true).build(); + + assert!(!check_ignore(&config, "//@ needs-std-debug-assertions")); + assert!(check_ignore(&config, "//@ ignore-std-debug-assertions")); +} + +#[test] fn stage() { let config: Config = cfg().stage_id("stage1-x86_64-unknown-linux-gnu").build(); diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 5c06a39c477..bf4a3124075 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -88,7 +88,8 @@ pub fn parse_config(args: Vec<String>) -> Config { .optopt("", "run", "whether to execute run-* tests", "auto | always | never") .optflag("", "ignored", "run tests marked as ignored") .optflag("", "has-enzyme", "run tests that require enzyme") - .optflag("", "with-debug-assertions", "whether to run tests with `ignore-debug` header") + .optflag("", "with-rustc-debug-assertions", "whether rustc was built with debug assertions") + .optflag("", "with-std-debug-assertions", "whether std was built with debug assertions") .optmulti( "", "skip", @@ -235,7 +236,8 @@ pub fn parse_config(args: Vec<String>) -> Config { let src_base = opt_path(matches, "src-base"); let run_ignored = matches.opt_present("ignored"); - let with_debug_assertions = matches.opt_present("with-debug-assertions"); + let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions"); + let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions"); let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); let has_html_tidy = if mode == Mode::Rustdoc { Command::new("tidy") @@ -293,7 +295,8 @@ pub fn parse_config(args: Vec<String>) -> Config { suite: matches.opt_str("suite").unwrap(), debugger: None, run_ignored, - with_debug_assertions, + with_rustc_debug_assertions, + with_std_debug_assertions, filters, skip: matches.opt_strs("skip"), filter_exact: matches.opt_present("exact"), diff --git a/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs b/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs index fa7c0bf5c0c..e95ef4d9062 100644 --- a/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs +++ b/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs @@ -1,4 +1,4 @@ -#![feature(rustc_attrs)] +#![feature(intrinsics, rustc_attrs)] #[rustc_intrinsic] #[rustc_nounwind] diff --git a/tests/assembly/asm/sparc-types.rs b/tests/assembly/asm/sparc-types.rs new file mode 100644 index 00000000000..2270679e837 --- /dev/null +++ b/tests/assembly/asm/sparc-types.rs @@ -0,0 +1,168 @@ +//@ revisions: sparc sparcv8plus sparc64 +//@ assembly-output: emit-asm +//@[sparc] compile-flags: --target sparc-unknown-none-elf +//@[sparc] needs-llvm-components: sparc +//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu +//@[sparcv8plus] needs-llvm-components: sparc +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc +//@ compile-flags: -Zmerge-functions=disabled + +#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for u8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for f32 {} +impl Copy for f64 {} +impl Copy for ptr {} + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov," {}, {}"), in($class) x, out($class) y); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " %", $reg, ", %", $reg), in($reg) x, lateout($reg) y); + y + } +};} + +// CHECK-LABEL: sym_fn_32: +// CHECK: !APP +// CHECK-NEXT: call extern_func +// CHECK-NEXT: !NO_APP +#[no_mangle] +pub unsafe fn sym_fn_32() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: !APP +// CHECK-NEXT: call extern_static +// CHECK-NEXT: !NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("call {}", sym extern_static); +} + +// CHECK-LABEL: reg_i8: +// CHECK: !APP +// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} +// CHECK-NEXT: !NO_APP +check!(reg_i8, i8, reg, "mov"); + +// CHECK-LABEL: reg_i16: +// CHECK: !APP +// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} +// CHECK-NEXT: !NO_APP +check!(reg_i16, i16, reg, "mov"); + +// CHECK-LABEL: reg_i32: +// CHECK: !APP +// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} +// CHECK-NEXT: !NO_APP +check!(reg_i32, i32, reg, "mov"); + +// FIXME: should be allowed for sparcv8plus but not yet supported in LLVM +// sparc64-LABEL: reg_i64: +// sparc64: !APP +// sparc64-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} +// sparc64-NEXT: !NO_APP +#[cfg(sparc64)] +check!(reg_i64, i64, reg, "mov"); + +// CHECK-LABEL: reg_ptr: +// CHECK: !APP +// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} +// CHECK-NEXT: !NO_APP +check!(reg_ptr, ptr, reg, "mov"); + +// CHECK-LABEL: o0_i8: +// CHECK: !APP +// CHECK-NEXT: mov %o0, %o0 +// CHECK-NEXT: !NO_APP +check_reg!(o0_i8, i8, "o0", "mov"); + +// CHECK-LABEL: o0_i16: +// CHECK: !APP +// CHECK-NEXT: mov %o0, %o0 +// CHECK-NEXT: !NO_APP +check_reg!(o0_i16, i16, "o0", "mov"); + +// CHECK-LABEL: o0_i32: +// CHECK: !APP +// CHECK-NEXT: mov %o0, %o0 +// CHECK-NEXT: !NO_APP +check_reg!(o0_i32, i32, "o0", "mov"); + +// FIXME: should be allowed for sparcv8plus but not yet supported in LLVM +// sparc64-LABEL: o0_i64: +// sparc64: !APP +// sparc64-NEXT: mov %o0, %o0 +// sparc64-NEXT: !NO_APP +#[cfg(sparc64)] +check_reg!(o0_i64, i64, "o0", "mov"); + +// CHECK-LABEL: r9_i8: +// CHECK: !APP +// CHECK-NEXT: mov %o1, %o1 +// CHECK-NEXT: !NO_APP +check_reg!(r9_i8, i8, "r9", "mov"); + +// CHECK-LABEL: r9_i16: +// CHECK: !APP +// CHECK-NEXT: mov %o1, %o1 +// CHECK-NEXT: !NO_APP +check_reg!(r9_i16, i16, "r9", "mov"); + +// CHECK-LABEL: r9_i32: +// CHECK: !APP +// CHECK-NEXT: mov %o1, %o1 +// CHECK-NEXT: !NO_APP +check_reg!(r9_i32, i32, "r9", "mov"); + +// FIXME: should be allowed for sparcv8plus but not yet supported in LLVM +// sparc64-LABEL: r9_i64: +// sparc64: !APP +// sparc64-NEXT: mov %o1, %o1 +// sparc64-NEXT: !NO_APP +#[cfg(sparc64)] +check_reg!(r9_i64, i64, "r9", "mov"); diff --git a/tests/assembly/rust-abi-arg-attr.rs b/tests/assembly/rust-abi-arg-attr.rs index 2a113eed4ba..e55a53fbdeb 100644 --- a/tests/assembly/rust-abi-arg-attr.rs +++ b/tests/assembly/rust-abi-arg-attr.rs @@ -50,9 +50,10 @@ enum Ordering { Greater = 1, } -extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - fn three_way_compare<T: Copy>(lhs: T, rhs: T) -> Ordering; +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +fn three_way_compare<T: Copy>(lhs: T, rhs: T) -> Ordering { + loop {} } // ^^^^^ core diff --git a/tests/codegen/asm/sparc-clobbers.rs b/tests/codegen/asm/sparc-clobbers.rs new file mode 100644 index 00000000000..843abd55352 --- /dev/null +++ b/tests/codegen/asm/sparc-clobbers.rs @@ -0,0 +1,40 @@ +//@ revisions: sparc sparcv8plus sparc64 +//@[sparc] compile-flags: --target sparc-unknown-none-elf +//@[sparc] needs-llvm-components: sparc +//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu +//@[sparcv8plus] needs-llvm-components: sparc +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc + +#![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 "", "~{icc},~{fcc0},~{fcc1},~{fcc2},~{fcc3}"() +#[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: @y_clobber +// CHECK: call void asm sideeffect "", "~{y}"() +#[no_mangle] +pub unsafe fn y_clobber() { + asm!("", out("y") _, options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs b/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs index 9cf4f210e52..e3bc9a4761c 100644 --- a/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs +++ b/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs @@ -1,5 +1,5 @@ //@ compile-flags: -O -//@ ignore-debug +//@ ignore-std-debug-assertions #![crate_type = "lib"] use std::collections::binary_heap::PeekMut; diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs index e62f1a953df..e62adfa0ba6 100644 --- a/tests/codegen/mem-replace-big-type.rs +++ b/tests/codegen/mem-replace-big-type.rs @@ -4,7 +4,8 @@ // known to be `1` after inlining). //@ compile-flags: -C no-prepopulate-passes -Zinline-mir=no -//@ ignore-debug: precondition checks in ptr::read make them a bad candidate for MIR inlining +//@ ignore-std-debug-assertions +// Reason: precondition checks in ptr::read make them a bad candidate for MIR inlining //@ needs-deterministic-layouts #![crate_type = "lib"] diff --git a/tests/codegen/mem-replace-simple-type.rs b/tests/codegen/mem-replace-simple-type.rs index 7209fa21925..41c3660dc15 100644 --- a/tests/codegen/mem-replace-simple-type.rs +++ b/tests/codegen/mem-replace-simple-type.rs @@ -1,6 +1,7 @@ //@ compile-flags: -O -C no-prepopulate-passes //@ only-x86_64 (to not worry about usize differing) -//@ ignore-debug: precondition checks make mem::replace not a candidate for MIR inlining +//@ ignore-std-debug-assertions +// Reason: precondition checks make mem::replace not a candidate for MIR inlining #![crate_type = "lib"] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs index 81ac90269b7..e9112f1f321 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs @@ -31,7 +31,7 @@ extern "rust-intrinsic" { // CHECK-LABEL: @bitmask_int #[no_mangle] pub unsafe fn bitmask_int(x: i32x2) -> u8 { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, <i32 31, i32 31> + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}} // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2 // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8 @@ -41,7 +41,7 @@ pub unsafe fn bitmask_int(x: i32x2) -> u8 { // CHECK-LABEL: @bitmask_uint #[no_mangle] pub unsafe fn bitmask_uint(x: u32x2) -> u8 { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, <i32 31, i32 31> + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}} // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2 // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8 @@ -51,7 +51,7 @@ pub unsafe fn bitmask_uint(x: u32x2) -> u8 { // CHECK-LABEL: @bitmask_int16 #[no_mangle] pub unsafe fn bitmask_int16(x: i8x16) -> u16 { - // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1|2}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7> + // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1|2}}, {{<i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}} // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1> // CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16 // CHECK-NOT: zext diff --git a/tests/codegen/slice-reverse.rs b/tests/codegen/slice-reverse.rs index 21add929f05..87cdad47962 100644 --- a/tests/codegen/slice-reverse.rs +++ b/tests/codegen/slice-reverse.rs @@ -1,6 +1,6 @@ //@ compile-flags: -O //@ only-x86_64 -//@ ignore-debug: debug assertions prevent generating shufflevector +//@ ignore-std-debug-assertions (debug assertions prevent generating shufflevector) #![crate_type = "lib"] diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs index c6b77363a4e..5d05f242617 100644 --- a/tests/codegen/vec-in-place.rs +++ b/tests/codegen/vec-in-place.rs @@ -1,4 +1,4 @@ -//@ ignore-debug: FIXME: checks for call detect scoped noalias metadata +//@ ignore-std-debug-assertions (FIXME: checks for call detect scoped noalias metadata) //@ compile-flags: -O -Z merge-functions=disabled #![crate_type = "lib"] diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs index 4b798fe6c9c..873904c2569 100644 --- a/tests/codegen/vec-shrink-panik.rs +++ b/tests/codegen/vec-shrink-panik.rs @@ -1,7 +1,7 @@ // LLVM 17 realizes double panic is not possible and doesn't generate calls // to panic_cannot_unwind. //@ compile-flags: -O -//@ ignore-debug: plain old debug assertions +//@ ignore-std-debug-assertions (plain old debug assertions) //@ needs-unwind #![crate_type = "lib"] #![feature(shrink_to)] diff --git a/tests/codegen/vec-with-capacity.rs b/tests/codegen/vec-with-capacity.rs index 47051f2eef8..e8c5bc88bd0 100644 --- a/tests/codegen/vec-with-capacity.rs +++ b/tests/codegen/vec-with-capacity.rs @@ -1,5 +1,5 @@ //@ compile-flags: -O -//@ ignore-debug +//@ ignore-std-debug-assertions // (with debug assertions turned on, `assert_unchecked` generates a real assertion) #![crate_type = "lib"] diff --git a/tests/codegen/vecdeque-drain.rs b/tests/codegen/vecdeque-drain.rs index fca1ed367e6..8a34ba0674b 100644 --- a/tests/codegen/vecdeque-drain.rs +++ b/tests/codegen/vecdeque-drain.rs @@ -2,7 +2,7 @@ //@ compile-flags: -O //@ needs-deterministic-layouts -//@ ignore-debug: FIXME: checks for call detect scoped noalias metadata +//@ ignore-std-debug-assertions (FIXME: checks for call detect scoped noalias metadata) #![crate_type = "lib"] diff --git a/tests/codegen/vecdeque_no_panic.rs b/tests/codegen/vecdeque_no_panic.rs index be2c4810ebc..da948d12254 100644 --- a/tests/codegen/vecdeque_no_panic.rs +++ b/tests/codegen/vecdeque_no_panic.rs @@ -1,7 +1,7 @@ // This test checks that `VecDeque::front[_mut]()` and `VecDeque::back[_mut]()` can't panic. //@ compile-flags: -O -//@ ignore-debug: plain old debug assertions +//@ ignore-std-debug-assertions (plain old debug assertions) #![crate_type = "lib"] diff --git a/tests/mir-opt/pre-codegen/mem_replace.rs b/tests/mir-opt/pre-codegen/mem_replace.rs index a68fe31f609..be23dcdb22a 100644 --- a/tests/mir-opt/pre-codegen/mem_replace.rs +++ b/tests/mir-opt/pre-codegen/mem_replace.rs @@ -1,6 +1,7 @@ // skip-filecheck //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Zinline-mir -//@ ignore-debug: precondition checks on ptr::read/write are under cfg(debug_assertions) +//@ ignore-std-debug-assertions +// Reason: precondition checks on ptr::read/write are under cfg(debug_assertions) // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![crate_type = "lib"] diff --git a/tests/mir-opt/pre-codegen/ptr_offset.rs b/tests/mir-opt/pre-codegen/ptr_offset.rs index 88ee00296a0..120be99fc94 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.rs +++ b/tests/mir-opt/pre-codegen/ptr_offset.rs @@ -1,6 +1,6 @@ // skip-filecheck //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Zinline-mir -//@ ignore-debug: precondition checks are under cfg(debug_assertions) +//@ ignore-std-debug-assertions (precondition checks are under cfg(debug_assertions)) // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![crate_type = "lib"] diff --git a/tests/mir-opt/pre-codegen/slice_iter.rs b/tests/mir-opt/pre-codegen/slice_iter.rs index fee4214982d..46ded729852 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.rs +++ b/tests/mir-opt/pre-codegen/slice_iter.rs @@ -1,7 +1,7 @@ // skip-filecheck //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 //@ only-64bit (constants for `None::<&T>` show in the output) -//@ ignore-debug: precondition checks on ptr::add are under cfg(debug_assertions) +//@ ignore-std-debug-assertions (precondition checks on ptr::add are under cfg(debug_assertions)) // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![crate_type = "lib"] diff --git a/tests/run-make/crate-loading/multiple-dep-versions-3.rs b/tests/run-make/crate-loading/multiple-dep-versions-3.rs index 07d888e9f10..f5c4d1baa81 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions-3.rs +++ b/tests/run-make/crate-loading/multiple-dep-versions-3.rs @@ -3,3 +3,8 @@ extern crate dependency; pub use dependency::Type; +pub struct OtherType; +impl dependency::Trait for OtherType { + fn foo(&self) {} + fn bar() {} +} diff --git a/tests/run-make/crate-loading/multiple-dep-versions.rs b/tests/run-make/crate-loading/multiple-dep-versions.rs index 113af9c3025..c68a9e6489f 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions.rs +++ b/tests/run-make/crate-loading/multiple-dep-versions.rs @@ -1,10 +1,11 @@ extern crate dep_2_reexport; extern crate dependency; -use dep_2_reexport::Type; +use dep_2_reexport::{OtherType, Type}; use dependency::{Trait, do_something}; fn main() { do_something(Type); Type.foo(); Type::bar(); + do_something(OtherType); } diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs index 5d3302c7b02..2d5913c4bcb 100644 --- a/tests/run-make/crate-loading/rmake.rs +++ b/tests/run-make/crate-loading/rmake.rs @@ -18,47 +18,39 @@ fn main() { .extern_("dependency", rust_lib_name("dependency")) .extern_("dep_2_reexport", rust_lib_name("foo")) .run_fail() - .assert_stderr_contains( - r#"error[E0277]: the trait bound `dep_2_reexport::Type: Trait` is not satisfied - --> multiple-dep-versions.rs:7:18 - | -7 | do_something(Type); - | ------------ ^^^^ the trait `Trait` is not implemented for `dep_2_reexport::Type` - | | - | required by a bound introduced by this call - | -help: there are multiple different versions of crate `dependency` in the dependency graph - --> multiple-dep-versions.rs:1:1 - | -1 | extern crate dep_2_reexport; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one version of crate `dependency` is used here, as a dependency of crate `foo` -2 | extern crate dependency; - | ^^^^^^^^^^^^^^^^^^^^^^^^ one version of crate `dependency` is used here, as a direct dependency of the current crate"#, - ) - .assert_stderr_contains( - r#" -3 | pub struct Type(pub i32); - | ^^^^^^^^^^^^^^^ this type implements the required trait -4 | pub trait Trait { - | --------------- this is the required trait"#, - ) - .assert_stderr_contains( - r#" -3 | pub struct Type; - | ^^^^^^^^^^^^^^^ this type doesn't implement the required trait"#, - ) - .assert_stderr_contains( - r#" -error[E0599]: no method named `foo` found for struct `dep_2_reexport::Type` in the current scope + .assert_stderr_contains(r#"error[E0277]: the trait bound `dep_2_reexport::Type: Trait` is not satisfied because the trait comes from a different crate version + --> multiple-dep-versions.rs:7:18 + | +7 | do_something(Type); + | ^^^^ the trait `Trait` is not implemented for `dep_2_reexport::Type` + | +note: there are multiple different versions of crate `dependency` in the dependency graph"#) + .assert_stderr_contains(r#" +3 | pub struct Type(pub i32); + | --------------- this type implements the required trait +4 | pub trait Trait { + | ^^^^^^^^^^^^^^^ this is the required trait +"#) + .assert_stderr_contains(r#" +1 | extern crate dep_2_reexport; + | ---------------------------- one version of crate `dependency` is used here, as a dependency of crate `foo` +2 | extern crate dependency; + | ------------------------ one version of crate `dependency` is used here, as a direct dependency of the current crate"#) + .assert_stderr_contains(r#" +3 | pub struct Type; + | --------------- this type doesn't implement the required trait +4 | pub trait Trait { + | --------------- this is the found trait + = note: two types coming from two different versions of the same crate are different types even if they look the same + = help: you can use `cargo tree` to explore your dependency tree"#) + .assert_stderr_contains(r#"error[E0599]: no method named `foo` found for struct `dep_2_reexport::Type` in the current scope --> multiple-dep-versions.rs:8:10 | 8 | Type.foo(); | ^^^ method not found in `Type` | -note: there are multiple different versions of crate `dependency` in the dependency graph"#, - ) - .assert_stderr_contains( - r#" +note: there are multiple different versions of crate `dependency` in the dependency graph"#) + .assert_stderr_contains(r#" 4 | pub trait Trait { | ^^^^^^^^^^^^^^^ this is the trait that is needed 5 | fn foo(&self); @@ -67,25 +59,19 @@ note: there are multiple different versions of crate `dependency` in the depende ::: multiple-dep-versions.rs:4:18 | 4 | use dependency::{Trait, do_something}; - | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#, - ) - .assert_stderr_contains( - r#" + | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#) + .assert_stderr_contains(r#" 4 | pub trait Trait { - | --------------- this is the trait that was imported"#, - ) - .assert_stderr_contains( - r#" + | --------------- this is the trait that was imported"#) + .assert_stderr_contains(r#" error[E0599]: no function or associated item named `bar` found for struct `dep_2_reexport::Type` in the current scope --> multiple-dep-versions.rs:9:11 | 9 | Type::bar(); | ^^^ function or associated item not found in `Type` | -note: there are multiple different versions of crate `dependency` in the dependency graph"#, - ) - .assert_stderr_contains( - r#" +note: there are multiple different versions of crate `dependency` in the dependency graph"#) + .assert_stderr_contains(r#" 4 | pub trait Trait { | ^^^^^^^^^^^^^^^ this is the trait that is needed 5 | fn foo(&self); @@ -95,6 +81,9 @@ note: there are multiple different versions of crate `dependency` in the depende ::: multiple-dep-versions.rs:4:18 | 4 | use dependency::{Trait, do_something}; - | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#, - ); + | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#) + .assert_stderr_contains( + r#" +6 | pub struct OtherType; + | -------------------- this type doesn't implement the required trait"#); } diff --git a/tests/rustdoc/safe-intrinsic.rs b/tests/rustdoc/safe-intrinsic.rs index b46ffed99c3..07af04ace60 100644 --- a/tests/rustdoc/safe-intrinsic.rs +++ b/tests/rustdoc/safe-intrinsic.rs @@ -5,18 +5,17 @@ #![no_core] #![crate_name = "foo"] -extern "rust-intrinsic" { - //@ has 'foo/fn.abort.html' - //@ has - '//pre[@class="rust item-decl"]' 'pub extern "rust-intrinsic" fn abort() -> !' - #[rustc_safe_intrinsic] - pub fn abort() -> !; - //@ has 'foo/fn.unreachable.html' - //@ has - '//pre[@class="rust item-decl"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !' - pub fn unreachable() -> !; +//@ has 'foo/fn.abort.html' +//@ has - '//pre[@class="rust item-decl"]' 'pub fn abort() -> !' +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn abort() -> ! { + loop {} } - -extern "C" { - //@ has 'foo/fn.needs_drop.html' - //@ has - '//pre[@class="rust item-decl"]' 'pub unsafe extern "C" fn needs_drop() -> !' - pub fn needs_drop() -> !; +//@ has 'foo/fn.unreachable.html' +//@ has - '//pre[@class="rust item-decl"]' 'pub unsafe fn unreachable() -> !' +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub unsafe fn unreachable() -> ! { + loop {} } diff --git a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs new file mode 100644 index 00000000000..e039ca07dd4 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs @@ -0,0 +1,149 @@ +//@ run-pass +//! Test information about crate definitions (local and external). + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 + +#![feature(rustc_private)] +#![feature(assert_matches)] + +extern crate rustc_hir; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_smir::rustc_internal; +use stable_mir::CrateDef; +use std::collections::HashSet; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "crate_defs"; + +/// This function uses the Stable MIR APIs to get information about the test crate. +fn test_stable_mir() -> ControlFlow<()> { + // Find items in the local crate. + let local = stable_mir::local_crate(); + check_items(&local.statics(), &["PRIVATE_STATIC", "dummy::PUBLIC_STATIC"]); + check_items( + &local.fn_defs(), + &[ + "top_level", + "dummy::public_fn", + "dummy::private_fn", + "dummy::PrivateStruct::new", + "<dummy::PrivateStruct as std::ops::Drop>::drop", + "DummyTrait::method", + "<T as DummyTrait>::method", + ], + ); + + // Find items inside core crate. + // FIXME: We are currently missing primitive type methods and trait implementations for external + // crates. + let core = stable_mir::find_crates("core").pop().expect("Cannot find `core` crate"); + contains( + &core.fn_defs(), + &[ + "std::fmt::Debug::fmt", + "std::option::Option::<T>::is_some", + "std::ptr::swap", + "<std::slice::Iter<'a, T> as std::iter::Iterator>::next", + "core::num::<impl u8>::abs_diff", + ], + ); + // Ensure nothing crashes. There is no public static in core that we can test here. + let _ = core.statics(); + + ControlFlow::Continue(()) +} + +/// Check if the list of definitions matches the expected list. +/// Note that order doesn't matter. +fn check_items<T: CrateDef>(items: &[T], expected: &[&str]) { + let expected: HashSet<_> = expected.iter().map(|s| s.to_string()).collect(); + let item_names: HashSet<_> = items.iter().map(|item| item.name()).collect(); + assert_eq!(item_names, expected); +} + +/// Check that the list contains the expected items. +fn contains<T: CrateDef + std::fmt::Debug>(items: &[T], expected: &[&str]) { + let expected: HashSet<_> = expected.iter().map(|s| s.to_string()).collect(); + let item_names = items.iter().map(|item| item.name()).collect(); + let not_found: Vec<_> = expected.difference(&item_names).collect(); + assert!(not_found.is_empty(), "Missing items: {:?}", not_found); +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "crate_definitions.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "--crate-type=lib".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, test_stable_mir).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + #![allow(dead_code, unused_variables)] + static PRIVATE_STATIC: u8 = 0; + fn top_level() -> &'static str {{ + "hello" + }} + + pub trait DummyTrait {{ + fn method(&self) -> Self; + }} + + impl<T: Copy> DummyTrait for T {{ + fn method(&self) -> T {{ + *self + }} + }} + + pub mod dummy {{ + pub static mut PUBLIC_STATIC: Option<char> = None; + + pub fn public_fn(input: bool) -> bool {{ + private_fn(!input) + }} + + fn private_fn(input: bool) -> bool {{ + todo!() + }} + + struct PrivateStruct {{ + field: u32, + }} + + impl PrivateStruct {{ + fn new() -> Self {{ + Self {{ field: 42 }} + }} + }} + + impl Drop for PrivateStruct {{ + fn drop(&mut self) {{ + println!("Dropping PrivateStruct"); + }} + }} + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui/asm/bad-arch.rs b/tests/ui/asm/bad-arch.rs deleted file mode 100644 index f84b9944b36..00000000000 --- a/tests/ui/asm/bad-arch.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ compile-flags: --target sparc-unknown-linux-gnu -//@ needs-llvm-components: sparc - -#![feature(no_core, lang_items, rustc_attrs)] -#![no_core] - -#[rustc_builtin_macro] -macro_rules! asm { - () => {}; -} -#[rustc_builtin_macro] -macro_rules! global_asm { - () => {}; -} -#[lang = "sized"] -trait Sized {} - -fn main() { - unsafe { - asm!(""); - //~^ ERROR inline assembly is unsupported on this target - } -} - -global_asm!(""); -//~^ ERROR inline assembly is unsupported on this target diff --git a/tests/ui/asm/bad-arch.stderr b/tests/ui/asm/bad-arch.stderr deleted file mode 100644 index c6f726600eb..00000000000 --- a/tests/ui/asm/bad-arch.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0472]: inline assembly is unsupported on this target - --> $DIR/bad-arch.rs:20:9 - | -LL | asm!(""); - | ^^^^^^^^ - -error[E0472]: inline assembly is unsupported on this target - --> $DIR/bad-arch.rs:25:1 - | -LL | global_asm!(""); - | ^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0472`. diff --git a/tests/ui/asm/sparc/bad-reg.rs b/tests/ui/asm/sparc/bad-reg.rs new file mode 100644 index 00000000000..b824f5adf3a --- /dev/null +++ b/tests/ui/asm/sparc/bad-reg.rs @@ -0,0 +1,66 @@ +//@ revisions: sparc sparcv8plus sparc64 +//@[sparc] compile-flags: --target sparc-unknown-none-elf +//@[sparc] needs-llvm-components: sparc +//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu +//@[sparcv8plus] needs-llvm-components: sparc +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc +//@ needs-asm-support + +#![crate_type = "rlib"] +#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +impl Copy for i32 {} + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +fn f() { + let mut x = 0; + unsafe { + // Unsupported registers + asm!("", out("g0") _); + //~^ ERROR invalid register `g0`: g0 is always zero and cannot be used as an operand for inline asm + // FIXME: see FIXME in compiler/rustc_target/src/asm/sparc.rs. + asm!("", out("g1") _); + //~^ ERROR invalid register `g1`: reserved by LLVM and cannot be used as an operand for inline asm + asm!("", out("g2") _); + asm!("", out("g3") _); + asm!("", out("g4") _); + asm!("", out("g5") _); + //[sparc,sparcv8plus]~^ ERROR cannot use register `r5`: g5 is reserved for system on SPARC32 + asm!("", out("g6") _); + //~^ ERROR invalid register `g6`: reserved for system and cannot be used as an operand for inline asm + asm!("", out("g7") _); + //~^ ERROR invalid register `g7`: reserved for system and cannot be used as an operand for inline asm + asm!("", out("sp") _); + //~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + asm!("", out("fp") _); + //~^ ERROR invalid register `fp`: the frame pointer cannot be used as an operand for inline asm + asm!("", out("i7") _); + //~^ ERROR invalid register `i7`: the return address register cannot be used as an operand for inline asm + + // Clobber-only registers + // yreg + asm!("", out("y") _); // ok + asm!("", in("y") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("", out("y") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", in(yreg) x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", out(yreg) _); + //~^ ERROR can only be used as a clobber + } +} diff --git a/tests/ui/asm/sparc/bad-reg.sparc.stderr b/tests/ui/asm/sparc/bad-reg.sparc.stderr new file mode 100644 index 00000000000..cb7558c0f43 --- /dev/null +++ b/tests/ui/asm/sparc/bad-reg.sparc.stderr @@ -0,0 +1,98 @@ +error: invalid register `g0`: g0 is always zero and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:30:18 + | +LL | asm!("", out("g0") _); + | ^^^^^^^^^^^ + +error: invalid register `g1`: reserved by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:33:18 + | +LL | asm!("", out("g1") _); + | ^^^^^^^^^^^ + +error: invalid register `g6`: reserved for system and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:40:18 + | +LL | asm!("", out("g6") _); + | ^^^^^^^^^^^ + +error: invalid register `g7`: reserved for system and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:42:18 + | +LL | asm!("", out("g7") _); + | ^^^^^^^^^^^ + +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:44:18 + | +LL | asm!("", out("sp") _); + | ^^^^^^^^^^^ + +error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:46:18 + | +LL | asm!("", out("fp") _); + | ^^^^^^^^^^^ + +error: invalid register `i7`: the return address register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:48:18 + | +LL | asm!("", out("i7") _); + | ^^^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:54:18 + | +LL | asm!("", in("y") x); + | ^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:57:18 + | +LL | asm!("", out("y") x); + | ^^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:60:26 + | +LL | asm!("/* {} */", in(yreg) x); + | ^^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:63:26 + | +LL | asm!("/* {} */", out(yreg) _); + | ^^^^^^^^^^^ + +error: cannot use register `r5`: g5 is reserved for system on SPARC32 + --> $DIR/bad-reg.rs:38:18 + | +LL | asm!("", out("g5") _); + | ^^^^^^^^^^^ + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:54:26 + | +LL | asm!("", in("y") x); + | ^ + | + = note: register class `yreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:57:27 + | +LL | asm!("", out("y") x); + | ^ + | + = note: register class `yreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:60:35 + | +LL | asm!("/* {} */", in(yreg) x); + | ^ + | + = note: register class `yreg` supports these types: + +error: aborting due to 15 previous errors + diff --git a/tests/ui/asm/sparc/bad-reg.sparc64.stderr b/tests/ui/asm/sparc/bad-reg.sparc64.stderr new file mode 100644 index 00000000000..e5606ab3124 --- /dev/null +++ b/tests/ui/asm/sparc/bad-reg.sparc64.stderr @@ -0,0 +1,92 @@ +error: invalid register `g0`: g0 is always zero and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:30:18 + | +LL | asm!("", out("g0") _); + | ^^^^^^^^^^^ + +error: invalid register `g1`: reserved by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:33:18 + | +LL | asm!("", out("g1") _); + | ^^^^^^^^^^^ + +error: invalid register `g6`: reserved for system and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:40:18 + | +LL | asm!("", out("g6") _); + | ^^^^^^^^^^^ + +error: invalid register `g7`: reserved for system and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:42:18 + | +LL | asm!("", out("g7") _); + | ^^^^^^^^^^^ + +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:44:18 + | +LL | asm!("", out("sp") _); + | ^^^^^^^^^^^ + +error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:46:18 + | +LL | asm!("", out("fp") _); + | ^^^^^^^^^^^ + +error: invalid register `i7`: the return address register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:48:18 + | +LL | asm!("", out("i7") _); + | ^^^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:54:18 + | +LL | asm!("", in("y") x); + | ^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:57:18 + | +LL | asm!("", out("y") x); + | ^^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:60:26 + | +LL | asm!("/* {} */", in(yreg) x); + | ^^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:63:26 + | +LL | asm!("/* {} */", out(yreg) _); + | ^^^^^^^^^^^ + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:54:26 + | +LL | asm!("", in("y") x); + | ^ + | + = note: register class `yreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:57:27 + | +LL | asm!("", out("y") x); + | ^ + | + = note: register class `yreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:60:35 + | +LL | asm!("/* {} */", in(yreg) x); + | ^ + | + = note: register class `yreg` supports these types: + +error: aborting due to 14 previous errors + diff --git a/tests/ui/asm/sparc/bad-reg.sparcv8plus.stderr b/tests/ui/asm/sparc/bad-reg.sparcv8plus.stderr new file mode 100644 index 00000000000..cb7558c0f43 --- /dev/null +++ b/tests/ui/asm/sparc/bad-reg.sparcv8plus.stderr @@ -0,0 +1,98 @@ +error: invalid register `g0`: g0 is always zero and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:30:18 + | +LL | asm!("", out("g0") _); + | ^^^^^^^^^^^ + +error: invalid register `g1`: reserved by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:33:18 + | +LL | asm!("", out("g1") _); + | ^^^^^^^^^^^ + +error: invalid register `g6`: reserved for system and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:40:18 + | +LL | asm!("", out("g6") _); + | ^^^^^^^^^^^ + +error: invalid register `g7`: reserved for system and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:42:18 + | +LL | asm!("", out("g7") _); + | ^^^^^^^^^^^ + +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:44:18 + | +LL | asm!("", out("sp") _); + | ^^^^^^^^^^^ + +error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:46:18 + | +LL | asm!("", out("fp") _); + | ^^^^^^^^^^^ + +error: invalid register `i7`: the return address register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:48:18 + | +LL | asm!("", out("i7") _); + | ^^^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:54:18 + | +LL | asm!("", in("y") x); + | ^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:57:18 + | +LL | asm!("", out("y") x); + | ^^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:60:26 + | +LL | asm!("/* {} */", in(yreg) x); + | ^^^^^^^^^^ + +error: register class `yreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:63:26 + | +LL | asm!("/* {} */", out(yreg) _); + | ^^^^^^^^^^^ + +error: cannot use register `r5`: g5 is reserved for system on SPARC32 + --> $DIR/bad-reg.rs:38:18 + | +LL | asm!("", out("g5") _); + | ^^^^^^^^^^^ + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:54:26 + | +LL | asm!("", in("y") x); + | ^ + | + = note: register class `yreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:57:27 + | +LL | asm!("", out("y") x); + | ^ + | + = note: register class `yreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:60:35 + | +LL | asm!("/* {} */", in(yreg) x); + | ^ + | + = note: register class `yreg` supports these types: + +error: aborting due to 15 previous errors + diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index 3426a768cb6..c3360c8b3e2 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -11,12 +11,12 @@ LL | *ptr = 0; | ^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required error[E0080]: evaluation of constant value failed - --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL | = note: accessing memory with alignment 1, but alignment 4 is required | note: inside `copy_nonoverlapping::<u32>` - --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL note: inside `std::ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `MISALIGNED_COPY` diff --git a/tests/ui/error-codes/E0094.rs b/tests/ui/error-codes/E0094.rs index 97ebcff99dc..da59d3decac 100644 --- a/tests/ui/error-codes/E0094.rs +++ b/tests/ui/error-codes/E0094.rs @@ -1,9 +1,10 @@ -#![feature(intrinsics, rustc_attrs)] +#![feature(intrinsics)] -extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - fn size_of<T, U>() -> usize; //~ ERROR E0094 +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +fn size_of<T, U>() -> usize { + //~^ ERROR E0094 + loop {} } -fn main() { -} +fn main() {} diff --git a/tests/ui/error-codes/E0094.stderr b/tests/ui/error-codes/E0094.stderr index 1bad5bd950e..e45cc0ea063 100644 --- a/tests/ui/error-codes/E0094.stderr +++ b/tests/ui/error-codes/E0094.stderr @@ -1,8 +1,8 @@ error[E0094]: intrinsic has wrong number of type parameters: found 2, expected 1 - --> $DIR/E0094.rs:5:15 + --> $DIR/E0094.rs:5:11 | -LL | fn size_of<T, U>() -> usize; - | ^^^^^^ expected 1 type parameter +LL | fn size_of<T, U>() -> usize { + | ^^^^^^ expected 1 type parameter error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0308.rs b/tests/ui/error-codes/E0308.rs index dd9e0b284ea..f8f93d49a8e 100644 --- a/tests/ui/error-codes/E0308.rs +++ b/tests/ui/error-codes/E0308.rs @@ -1,10 +1,11 @@ #![feature(intrinsics)] #![feature(rustc_attrs)] -extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - fn size_of<T>(); //~ ERROR E0308 +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +fn size_of<T>() { + //~^ ERROR E0308 + loop {} } -fn main() { -} +fn main() {} diff --git a/tests/ui/error-codes/E0308.stderr b/tests/ui/error-codes/E0308.stderr index 709b3119276..77e5c06e06a 100644 --- a/tests/ui/error-codes/E0308.stderr +++ b/tests/ui/error-codes/E0308.stderr @@ -1,11 +1,11 @@ error[E0308]: intrinsic has wrong type - --> $DIR/E0308.rs:6:20 + --> $DIR/E0308.rs:6:16 | -LL | fn size_of<T>(); - | ^ expected `usize`, found `()` +LL | fn size_of<T>() { + | ^ expected `usize`, found `()` | - = note: expected signature `extern "rust-intrinsic" fn() -> usize` - found signature `extern "rust-intrinsic" fn() -> ()` + = note: expected signature `fn() -> usize` + found signature `fn() -> ()` error: aborting due to 1 previous error diff --git a/tests/ui/extern/extern-with-type-bounds.rs b/tests/ui/extern/extern-with-type-bounds.rs index 99e9801fd40..3fbddfc99a6 100644 --- a/tests/ui/extern/extern-with-type-bounds.rs +++ b/tests/ui/extern/extern-with-type-bounds.rs @@ -1,18 +1,17 @@ #![feature(intrinsics, rustc_attrs)] -extern "rust-intrinsic" { - // Real example from libcore - #[rustc_safe_intrinsic] - fn type_id<T: ?Sized + 'static>() -> u64; +// Intrinsics are the only (?) extern blocks supporting generics. +// Once intrinsics have to be declared via `#[rustc_intrinsic]`, +// the entire support for generics in extern fn can probably be removed. +extern "rust-intrinsic" { // Silent bounds made explicit to make sure they are actually // resolved. fn transmute<T: Sized, U: Sized>(val: T) -> U; // Bounds aren't checked right now, so this should work // even though it's incorrect. - #[rustc_safe_intrinsic] - fn size_of<T: Clone>() -> usize; + fn size_of_val<T: Clone>(x: *const T) -> usize; // Unresolved bounds should still error. fn align_of<T: NoSuchTrait>() -> usize; diff --git a/tests/ui/extern/extern-with-type-bounds.stderr b/tests/ui/extern/extern-with-type-bounds.stderr index 42448d9e924..893947e831f 100644 --- a/tests/ui/extern/extern-with-type-bounds.stderr +++ b/tests/ui/extern/extern-with-type-bounds.stderr @@ -1,5 +1,5 @@ error[E0405]: cannot find trait `NoSuchTrait` in this scope - --> $DIR/extern-with-type-bounds.rs:18:20 + --> $DIR/extern-with-type-bounds.rs:17:20 | LL | fn align_of<T: NoSuchTrait>() -> usize; | ^^^^^^^^^^^ not found in this scope diff --git a/tests/ui/intrinsics/always-gets-overridden.rs b/tests/ui/intrinsics/always-gets-overridden.rs index ad2c2be4daa..2fb64f96d83 100644 --- a/tests/ui/intrinsics/always-gets-overridden.rs +++ b/tests/ui/intrinsics/always-gets-overridden.rs @@ -1,6 +1,6 @@ //! Check that `vtable_size` gets overridden by llvm backend even if there is no //! `rustc_intrinsic_must_be_overridden` attribute on this usage. -#![feature(rustc_attrs)] +#![feature(intrinsics)] //@run-pass #[rustc_intrinsic] diff --git a/tests/ui/intrinsics/const-eval-select-bad.stderr b/tests/ui/intrinsics/const-eval-select-bad.stderr index 50092edda4f..e317ed23ab1 100644 --- a/tests/ui/intrinsics/const-eval-select-bad.stderr +++ b/tests/ui/intrinsics/const-eval-select-bad.stderr @@ -27,7 +27,7 @@ LL | const_eval_select((), 42, 0xDEADBEEF); = help: the trait `FnOnce()` is not implemented for `{integer}` = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `const_eval_select` - --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL error[E0277]: expected a `FnOnce()` closure, found `{integer}` --> $DIR/const-eval-select-bad.rs:10:31 @@ -40,7 +40,7 @@ LL | const_eval_select((), 42, 0xDEADBEEF); = help: the trait `FnOnce()` is not implemented for `{integer}` = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `const_eval_select` - --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL error: this argument must be a function item --> $DIR/const-eval-select-bad.rs:10:27 @@ -69,7 +69,7 @@ LL | const_eval_select((1,), foo, bar); | required by a bound introduced by this call | note: required by a bound in `const_eval_select` - --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL error[E0631]: type mismatch in function arguments --> $DIR/const-eval-select-bad.rs:37:32 @@ -85,7 +85,7 @@ LL | const_eval_select((true,), foo, baz); = note: expected function signature `fn(bool) -> _` found function signature `fn(i32) -> _` note: required by a bound in `const_eval_select` - --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL help: consider wrapping the function in a closure | LL | const_eval_select((true,), |arg0: bool| foo(/* i32 */), baz); diff --git a/tests/ui/intrinsics/feature-gate-safe-intrinsic.rs b/tests/ui/intrinsics/feature-gate-safe-intrinsic.rs deleted file mode 100644 index ffaa4d771d9..00000000000 --- a/tests/ui/intrinsics/feature-gate-safe-intrinsic.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[rustc_safe_intrinsic] -//~^ ERROR the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe -//~| ERROR attribute should be applied to intrinsic functions -fn safe() {} - -fn main() {} diff --git a/tests/ui/intrinsics/feature-gate-safe-intrinsic.stderr b/tests/ui/intrinsics/feature-gate-safe-intrinsic.stderr deleted file mode 100644 index e49880e9bb8..00000000000 --- a/tests/ui/intrinsics/feature-gate-safe-intrinsic.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0658]: the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe - --> $DIR/feature-gate-safe-intrinsic.rs:1:1 - | -LL | #[rustc_safe_intrinsic] - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: attribute should be applied to intrinsic functions - --> $DIR/feature-gate-safe-intrinsic.rs:1:1 - | -LL | #[rustc_safe_intrinsic] - | ^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | fn safe() {} - | ------------ not an intrinsic function - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs index 4cb05f6a8df..ab99aa5fd03 100644 --- a/tests/ui/intrinsics/intrinsic-alignment.rs +++ b/tests/ui/intrinsics/intrinsic-alignment.rs @@ -1,14 +1,8 @@ //@ run-pass -#![feature(intrinsics, rustc_attrs)] +#![feature(core_intrinsics, rustc_attrs)] -mod rusti { - extern "rust-intrinsic" { - pub fn pref_align_of<T>() -> usize; - #[rustc_safe_intrinsic] - pub fn min_align_of<T>() -> usize; - } -} +use std::intrinsics as rusti; #[cfg(any( target_os = "android", diff --git a/tests/ui/intrinsics/intrinsics-integer.rs b/tests/ui/intrinsics/intrinsics-integer.rs index 7dbc4b8b7ce..8eb03924feb 100644 --- a/tests/ui/intrinsics/intrinsics-integer.rs +++ b/tests/ui/intrinsics/intrinsics-integer.rs @@ -1,24 +1,8 @@ //@ run-pass -#![feature(intrinsics)] -#![feature(rustc_attrs)] - -mod rusti { - extern "rust-intrinsic" { - #[rustc_safe_intrinsic] - pub fn ctpop<T>(x: T) -> u32; - #[rustc_safe_intrinsic] - pub fn ctlz<T>(x: T) -> u32; - pub fn ctlz_nonzero<T>(x: T) -> u32; - #[rustc_safe_intrinsic] - pub fn cttz<T>(x: T) -> u32; - pub fn cttz_nonzero<T>(x: T) -> u32; - #[rustc_safe_intrinsic] - pub fn bswap<T>(x: T) -> T; - #[rustc_safe_intrinsic] - pub fn bitreverse<T>(x: T) -> T; - } -} +#![feature(core_intrinsics)] + +use std::intrinsics as rusti; pub fn main() { use rusti::*; diff --git a/tests/ui/intrinsics/not-overridden.rs b/tests/ui/intrinsics/not-overridden.rs index e1f1bbe0951..16f8e9bcf6a 100644 --- a/tests/ui/intrinsics/not-overridden.rs +++ b/tests/ui/intrinsics/not-overridden.rs @@ -1,6 +1,6 @@ //! Check that intrinsics that do not get overridden, but are marked as such, //! cause an error instead of silently invoking the body. -#![feature(rustc_attrs)] +#![feature(intrinsics)] //@ build-fail //@ failure-status:101 //@ normalize-stderr-test: ".*note: .*\n\n" -> "" diff --git a/tests/ui/print_type_sizes/niche-filling.rs b/tests/ui/print_type_sizes/niche-filling.rs index 5dda0da8458..36739e3fc04 100644 --- a/tests/ui/print_type_sizes/niche-filling.rs +++ b/tests/ui/print_type_sizes/niche-filling.rs @@ -9,7 +9,7 @@ //! padding and overall computed sizes can be quite different. //! //@ compile-flags: -Z print-type-sizes --crate-type lib -//@ ignore-debug: debug assertions will print more types +//@ ignore-std-debug-assertions (debug assertions will print more types) //@ build-pass //@ ignore-pass // ^-- needed because `--pass check` does not emit the output needed. diff --git a/tests/ui/stable-mir-print/operands.rs b/tests/ui/stable-mir-print/operands.rs new file mode 100644 index 00000000000..34a74e2287e --- /dev/null +++ b/tests/ui/stable-mir-print/operands.rs @@ -0,0 +1,48 @@ +//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort +//@ check-pass +//@ only-x86_64 +//@ needs-unwind unwind edges are different with panic=abort +//! Check how stable mir pretty printer prints different operands and abort strategy. + +pub fn operands(val: u8) { + let array = [val; 10]; + let first = array[0]; + let last = array[10 - 1]; + assert_eq!(first, last); + + let reference = &first; + let dereferenced = *reference; + assert_eq!(dereferenced, first); + + let tuple = (first, last); + let (first_again, _) = tuple; + let first_again_again = tuple.0; + assert_eq!(first_again, first_again_again); + + let length = array.len(); + let size_of = std::mem::size_of_val(&length); + assert_eq!(length, size_of); +} + +pub struct Dummy { + c: char, + i: i32, +} + +pub enum Ctors { + Unit, + StructLike { d: Dummy }, + TupLike(bool), +} + +pub fn more_operands() -> [Ctors; 3] { + let dummy = Dummy { c: 'a', i: i32::MIN }; + let unit = Ctors::Unit; + let struct_like = Ctors::StructLike { d: dummy }; + let tup_like = Ctors::TupLike(false); + [unit, struct_like, tup_like] +} + +pub fn closures(x: bool, z: bool) -> impl FnOnce(bool) -> bool { + move |y: bool| (x ^ y) || z +} diff --git a/tests/ui/stable-mir-print/operands.stdout b/tests/ui/stable-mir-print/operands.stdout new file mode 100644 index 00000000000..3c27878b3cf --- /dev/null +++ b/tests/ui/stable-mir-print/operands.stdout @@ -0,0 +1,263 @@ +// WARNING: This is highly experimental output it's intended for stable-mir developers only. +// If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir. +fn operands(_1: u8) -> () { + let mut _0: (); + let _2: [u8; 10]; + let _3: u8; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + let _7: u8; + let _8: usize; + let mut _9: (usize, bool); + let mut _10: usize; + let mut _11: bool; + let mut _12: (&u8, &u8); + let mut _13: &u8; + let mut _14: &u8; + let _15: &u8; + let _16: &u8; + let mut _17: bool; + let mut _18: u8; + let mut _19: u8; + let _20: core::panicking::AssertKind; + let _21: !; + let mut _22: Option<Arguments<'_>>; + let _23: &u8; + let _24: u8; + let mut _25: (&u8, &u8); + let mut _26: &u8; + let mut _27: &u8; + let _28: &u8; + let _29: &u8; + let mut _30: bool; + let mut _31: u8; + let mut _32: u8; + let _33: core::panicking::AssertKind; + let _34: !; + let mut _35: Option<Arguments<'_>>; + let _36: (u8, u8); + let _37: u8; + let _38: u8; + let mut _39: (&u8, &u8); + let mut _40: &u8; + let mut _41: &u8; + let _42: &u8; + let _43: &u8; + let mut _44: bool; + let mut _45: u8; + let mut _46: u8; + let _47: core::panicking::AssertKind; + let _48: !; + let mut _49: Option<Arguments<'_>>; + let _50: usize; + let mut _51: &[u8]; + let mut _52: &[u8; 10]; + let _53: usize; + let _54: &usize; + let mut _55: (&usize, &usize); + let mut _56: &usize; + let mut _57: &usize; + let _58: &usize; + let _59: &usize; + let mut _60: bool; + let mut _61: usize; + let mut _62: usize; + let _63: core::panicking::AssertKind; + let _64: !; + let mut _65: Option<Arguments<'_>>; + debug val => _1; + debug array => _2; + debug first => _3; + debug last => _7; + debug left_val => _15; + debug right_val => _16; + debug kind => _20; + debug reference => _23; + debug dereferenced => _24; + debug left_val => _28; + debug right_val => _29; + debug kind => _33; + debug tuple => _36; + debug first_again => _37; + debug first_again_again => _38; + debug left_val => _42; + debug right_val => _43; + debug kind => _47; + debug length => _50; + debug size_of => _53; + debug left_val => _58; + debug right_val => _59; + debug kind => _63; + bb0: { + _2 = [_1; 10]; + _4 = 0_usize; + _5 = 10_usize; + _6 = Lt(_4, _5); + assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable]; + } + bb1: { + _3 = _2[_4]; + _9 = CheckedSub(10_usize, 1_usize); + assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable]; + } + bb2: { + _8 = move (_9.0: usize); + _10 = 10_usize; + _11 = Lt(_8, _10); + assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, _8) -> [success: bb3, unwind unreachable]; + } + bb3: { + _7 = _2[_8]; + _13 = &_3; + _14 = &_7; + _12 = (move _13, move _14); + _15 = (_12.0: &u8); + _16 = (_12.1: &u8); + _18 = (*_15); + _19 = (*_16); + _17 = Eq(move _18, move _19); + switchInt(move _17) -> [0: bb5, otherwise: bb4]; + } + bb4: { + _23 = &_3; + _24 = (*_23); + _26 = &_24; + _27 = &_3; + _25 = (move _26, move _27); + _28 = (_25.0: &u8); + _29 = (_25.1: &u8); + _31 = (*_28); + _32 = (*_29); + _30 = Eq(move _31, move _32); + switchInt(move _30) -> [0: bb7, otherwise: bb6]; + } + bb5: { + _20 = core::panicking::AssertKind::Eq; + _22 = std::option::Option::None; + _21 = core::panicking::assert_failed::<u8, u8>(move _20, _15, _16, move _22) -> unwind unreachable; + } + bb6: { + _36 = (_3, _7); + _37 = (_36.0: u8); + _38 = (_36.0: u8); + _40 = &_37; + _41 = &_38; + _39 = (move _40, move _41); + _42 = (_39.0: &u8); + _43 = (_39.1: &u8); + _45 = (*_42); + _46 = (*_43); + _44 = Eq(move _45, move _46); + switchInt(move _44) -> [0: bb9, otherwise: bb8]; + } + bb7: { + _33 = core::panicking::AssertKind::Eq; + _35 = std::option::Option::None; + _34 = core::panicking::assert_failed::<u8, u8>(move _33, _28, _29, move _35) -> unwind unreachable; + } + bb8: { + _52 = &_2; + _51 = move _52 as &[u8]; + _50 = PtrMetadata(move _51); + _54 = &_50; + _53 = std::mem::size_of_val::<usize>(_54) -> [return: bb10, unwind unreachable]; + } + bb9: { + _47 = core::panicking::AssertKind::Eq; + _49 = std::option::Option::None; + _48 = core::panicking::assert_failed::<u8, u8>(move _47, _42, _43, move _49) -> unwind unreachable; + } + bb10: { + _56 = &_50; + _57 = &_53; + _55 = (move _56, move _57); + _58 = (_55.0: &usize); + _59 = (_55.1: &usize); + _61 = (*_58); + _62 = (*_59); + _60 = Eq(move _61, move _62); + switchInt(move _60) -> [0: bb12, otherwise: bb11]; + } + bb11: { + return; + } + bb12: { + _63 = core::panicking::AssertKind::Eq; + _65 = std::option::Option::None; + _64 = core::panicking::assert_failed::<usize, usize>(move _63, _58, _59, move _65) -> unwind unreachable; + } +} +fn operands::{constant#0}() -> usize { + let mut _0: usize; + bb0: { + _0 = 10_usize; + return; + } +} +fn more_operands() -> [Ctors; 3] { + let mut _0: [Ctors; 3]; + let _1: Dummy; + let _2: Ctors; + let _3: Ctors; + let _4: Ctors; + debug dummy => _1; + debug unit => _2; + debug struct_like => _3; + debug tup_like => _4; + bb0: { + _1 = Dummy('a', core::num::<impl i32>::MIN); + _2 = Ctors::Unit; + _3 = Ctors::StructLike(move _1); + _4 = Ctors::TupLike(false); + _0 = [move _2, move _3, move _4]; + return; + } +} +fn more_operands::{constant#0}() -> usize { + let mut _0: usize; + bb0: { + _0 = 3_usize; + return; + } +} +fn closures(_1: bool, _2: bool) -> {closure@$DIR/operands.rs:47:5: 47:19} { + let mut _0: {closure@$DIR/operands.rs:47:5: 47:19}; + debug x => _1; + debug z => _2; + bb0: { + _0 = {closure@$DIR/operands.rs:47:5: 47:19}(_1, _2); + return; + } +} +fn closures::{closure#0}(_1: {closure@$DIR/operands.rs:47:5: 47:19}, _2: bool) -> bool { + let mut _0: bool; + let mut _3: bool; + let mut _4: bool; + debug y => _2; + debug x => (_1.0: bool); + debug z => (_1.1: bool); + bb0: { + _4 = (_1.0: bool); + _3 = BitXor(move _4, _2); + switchInt(move _3) -> [0: bb2, otherwise: bb1]; + } + bb1: { + _0 = true; + goto -> bb3; + } + bb2: { + _0 = (_1.1: bool); + goto -> bb3; + } + bb3: { + return; + } +} +fn Ctors::TupLike(_1: bool) -> Ctors { + let mut _0: Ctors; + bb0: { + _0 = Ctors::TupLike(move _1); + return; + } +} diff --git a/tests/ui/statics/static-mut-shared-parens.rs b/tests/ui/statics/static-mut-shared-parens.rs new file mode 100644 index 00000000000..8e58152e27a --- /dev/null +++ b/tests/ui/statics/static-mut-shared-parens.rs @@ -0,0 +1,13 @@ +//Missing paren in diagnostic msg: https://github.com/rust-lang/rust/issues/131977 +//@check-pass + + +static mut TEST: usize = 0; + +fn main() { + let _ = unsafe { (&TEST) as *const usize }; + //~^WARN creating a shared reference to mutable static is discouraged + + let _ = unsafe { ((&mut TEST)) as *const usize }; + //~^WARN creating a mutable reference to mutable static is discouraged +} diff --git a/tests/ui/statics/static-mut-shared-parens.stderr b/tests/ui/statics/static-mut-shared-parens.stderr new file mode 100644 index 00000000000..aa7a760ded8 --- /dev/null +++ b/tests/ui/statics/static-mut-shared-parens.stderr @@ -0,0 +1,29 @@ +warning: creating a shared reference to mutable static is discouraged + --> $DIR/static-mut-shared-parens.rs:8:22 + | +LL | let _ = unsafe { (&TEST) as *const usize }; + | ^^^^^^^ shared reference to mutable static + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html> + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + = note: `#[warn(static_mut_refs)]` on by default +help: use `&raw const` instead to create a raw pointer + | +LL | let _ = unsafe { (&raw const TEST) as *const usize }; + | ~~~~~~~~~~ + +warning: creating a mutable reference to mutable static is discouraged + --> $DIR/static-mut-shared-parens.rs:11:22 + | +LL | let _ = unsafe { ((&mut TEST)) as *const usize }; + | ^^^^^^^^^^^^^ mutable reference to mutable static + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html> + = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives +help: use `&raw mut` instead to create a raw pointer + | +LL | let _ = unsafe { ((&raw mut TEST)) as *const usize }; + | ~~~~~~~~ + +warning: 2 warnings emitted + diff --git a/tests/ui/std/channel-stack-overflow-issue-102246.rs b/tests/ui/std/channel-stack-overflow-issue-102246.rs new file mode 100644 index 00000000000..984ebdd553f --- /dev/null +++ b/tests/ui/std/channel-stack-overflow-issue-102246.rs @@ -0,0 +1,29 @@ +//@ run-pass +//@ needs-threads +//@ compile-flags: -Copt-level=0 + +// The channel's `Block::new` was causing a stack overflow because it held 32 item slots, which is +// 1MiB for this test's `BigStruct` -- instantiated on the stack before moving to `Box::new`. +// +// That block is now initialized directly on the heap. +// +// Ref: https://github.com/rust-lang/rust/issues/102246 + +use std::sync::mpsc::channel; +use std::thread; + +const N: usize = 32_768; +struct BigStruct { + _data: [u8; N], +} + +fn main() { + let (sender, receiver) = channel::<BigStruct>(); + + let thread1 = thread::spawn(move || { + sender.send(BigStruct { _data: [0u8; N] }).unwrap(); + }); + + thread1.join().unwrap(); + for _data in receiver.try_iter() {} +} diff --git a/tests/ui/structs-enums/rec-align-u32.rs b/tests/ui/structs-enums/rec-align-u32.rs index 9cd2a988871..44879189739 100644 --- a/tests/ui/structs-enums/rec-align-u32.rs +++ b/tests/ui/structs-enums/rec-align-u32.rs @@ -3,17 +3,10 @@ #![allow(unused_unsafe)] // Issue #2303 -#![feature(intrinsics, rustc_attrs)] +#![feature(core_intrinsics, rustc_attrs)] use std::mem; - -mod rusti { - extern "rust-intrinsic" { - pub fn pref_align_of<T>() -> usize; - #[rustc_safe_intrinsic] - pub fn min_align_of<T>() -> usize; - } -} +use std::intrinsics; // This is the type with the questionable alignment #[derive(Debug)] @@ -41,12 +34,12 @@ pub fn main() { // Send it through the shape code let y = format!("{:?}", x); - println!("align inner = {:?}", rusti::min_align_of::<Inner>()); + println!("align inner = {:?}", intrinsics::min_align_of::<Inner>()); println!("size outer = {:?}", mem::size_of::<Outer>()); println!("y = {:?}", y); // per clang/gcc the alignment of `inner` is 4 on x86. - assert_eq!(rusti::min_align_of::<Inner>(), m::align()); + assert_eq!(intrinsics::min_align_of::<Inner>(), m::align()); // per clang/gcc the size of `outer` should be 12 // because `inner`s alignment was 4. diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs index 313ce6d578d..8b501ea5509 100644 --- a/tests/ui/structs-enums/rec-align-u64.rs +++ b/tests/ui/structs-enums/rec-align-u64.rs @@ -4,17 +4,10 @@ // Issue #2303 -#![feature(intrinsics, rustc_attrs)] +#![feature(core_intrinsics, rustc_attrs)] use std::mem; - -mod rusti { - extern "rust-intrinsic" { - pub fn pref_align_of<T>() -> usize; - #[rustc_safe_intrinsic] - pub fn min_align_of<T>() -> usize; - } -} +use std::intrinsics; // This is the type with the questionable alignment #[derive(Debug)] @@ -90,12 +83,12 @@ pub fn main() { let y = format!("{:?}", x); - println!("align inner = {:?}", rusti::min_align_of::<Inner>()); + println!("align inner = {:?}", intrinsics::min_align_of::<Inner>()); println!("size outer = {:?}", mem::size_of::<Outer>()); println!("y = {:?}", y); // per clang/gcc the alignment of `Inner` is 4 on x86. - assert_eq!(rusti::min_align_of::<Inner>(), m::m::align()); + assert_eq!(intrinsics::min_align_of::<Inner>(), m::m::align()); // per clang/gcc the size of `Outer` should be 12 // because `Inner`s alignment was 4. diff --git a/tests/ui/typeck/foreign_struct_trait_unimplemented.stderr b/tests/ui/typeck/foreign_struct_trait_unimplemented.stderr index b9bb97548f6..70de107b1ae 100644 --- a/tests/ui/typeck/foreign_struct_trait_unimplemented.stderr +++ b/tests/ui/typeck/foreign_struct_trait_unimplemented.stderr @@ -6,12 +6,7 @@ LL | needs_test(foreign_struct_trait_unimplemented::B); | | | required by a bound introduced by this call | -help: there are multiple different versions of crate `foreign_struct_trait_unimplemented` in the dependency graph - --> $DIR/foreign_struct_trait_unimplemented.rs:3:1 - | -LL | extern crate foreign_struct_trait_unimplemented; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one version of crate `foreign_struct_trait_unimplemented` is used here, as a direct dependency of the current crate - = help: you can use `cargo tree` to explore your dependency tree + = help: the trait `Test` is implemented for `A` note: required by a bound in `needs_test` --> $DIR/foreign_struct_trait_unimplemented.rs:10:23 | |
