diff --git a/Cargo.lock b/Cargo.lock index 164617c909fea..3ebfc4b4c3741 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,7 +162,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4" dependencies = [ - "object", + "object 0.36.7", ] [[package]] @@ -235,7 +235,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.36.7", "rustc-demangle", "windows-targets 0.52.6", ] @@ -2509,7 +2509,19 @@ dependencies = [ "indexmap", "memchr", "ruzstd", - "wasmparser 0.222.1", +] + +[[package]] +name = "object" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6273adb7096cf9ab4335f258e627d8230e69d40d45567d678f552dcec6245215" +dependencies = [ + "crc32fast", + "hashbrown", + "indexmap", + "memchr", + "wasmparser 0.232.0", ] [[package]] @@ -3109,7 +3121,7 @@ dependencies = [ "build_helper", "gimli", "libc", - "object", + "object 0.36.7", "regex", "serde_json", "similar", @@ -3422,7 +3434,7 @@ dependencies = [ "itertools", "libc", "measureme", - "object", + "object 0.37.0", "rustc-demangle", "rustc_abi", "rustc_ast", @@ -3463,7 +3475,7 @@ dependencies = [ "either", "itertools", "libc", - "object", + "object 0.37.0", "pathdiff", "regex", "rustc_abi", @@ -4495,7 +4507,7 @@ name = "rustc_target" version = "0.0.0" dependencies = [ "bitflags", - "object", + "object 0.37.0", "rustc_abi", "rustc_data_structures", "rustc_fs_util", @@ -5247,7 +5259,7 @@ checksum = "9e9c1e705f82a260173f3eec93f2ff6d7807f23ad5a8cc2e7316a891733ea7a1" dependencies = [ "gimli", "hashbrown", - "object", + "object 0.36.7", "tracing", ] @@ -5908,15 +5920,6 @@ dependencies = [ "indexmap", ] -[[package]] -name = "wasmparser" -version = "0.222.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa210fd1788e6b37a1d1930f3389c48e1d6ebd1a013d34fa4b7f9e3e3bf03146" -dependencies = [ - "bitflags", -] - [[package]] name = "wasmparser" version = "0.229.0" @@ -5941,6 +5944,15 @@ dependencies = [ "semver", ] +[[package]] +name = "wasmparser" +version = "0.232.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917739b33bb1eb0e9a49bcd2637a351931be4578d0cc4d37b908d7a797784fbb" +dependencies = [ + "bitflags", +] + [[package]] name = "wast" version = "230.0.0" diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index dd8d5ae624a3c..7dee2ed17b4be 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -22,7 +22,7 @@ pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'st } } -pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable"; +pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable_v2"; pub enum AllocatorTy { Layout, diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 9cff8a84db3d9..ffb932a3c38e6 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -1,6 +1,7 @@ //! Allocator shim // Adapted from rustc +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_ast::expand::allocator::{ ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name, default_fn_name, global_fn_name, @@ -97,16 +98,31 @@ fn codegen_inner( data.define(Box::new([val])); module.define_data(data_id, &data).unwrap(); - let data_id = module - .declare_data( - &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), - Linkage::Export, - false, - false, - ) - .unwrap(); - let mut data = DataDescription::new(); - data.set_align(1); - data.define(Box::new([0])); - module.define_data(data_id, &data).unwrap(); + { + let sig = Signature { + call_conv: module.target_config().default_call_conv, + params: vec![], + returns: vec![], + }; + let func_id = module + .declare_function( + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + Linkage::Export, + &sig, + ) + .unwrap(); + + let mut ctx = Context::new(); + ctx.func.signature = sig; + let mut func_ctx = FunctionBuilderContext::new(); + let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); + + let block = bcx.create_block(); + bcx.switch_to_block(block); + bcx.ins().return_(&[]); + bcx.seal_all_blocks(); + bcx.finalize(); + + module.define_function(func_id, &mut ctx).unwrap(); + } } diff --git a/compiler/rustc_codegen_gcc/example/alloc_system.rs b/compiler/rustc_codegen_gcc/example/alloc_system.rs index 945d34063a63c..4d70122496b72 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_system.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_system.rs @@ -8,6 +8,7 @@ // add fast paths for low alignment values. #[cfg(any(target_arch = "x86", target_arch = "arm", + target_arch = "loongarch32", target_arch = "m68k", target_arch = "mips", target_arch = "mips32r6", diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index f4ebd42ee2dc0..cf8aa500c778f 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen( let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); - create_wrapper_function(tcx, context, &from_name, &to_name, &types, output); + create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output); } } @@ -66,7 +66,7 @@ pub(crate) unsafe fn codegen( tcx, context, &mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - &mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)), + Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))), &[usize, usize], None, ); @@ -81,21 +81,21 @@ pub(crate) unsafe fn codegen( let value = context.new_rvalue_from_int(i8, value as i32); global.global_set_initializer_rvalue(value); - let name = mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE); - let global = context.new_global(None, GlobalKind::Exported, i8, name); - #[cfg(feature = "master")] - global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc( - tcx.sess.default_visibility(), - ))); - let value = context.new_rvalue_from_int(i8, 0); - global.global_set_initializer_rvalue(value); + create_wrapper_function( + tcx, + context, + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + None, + &[], + None, + ); } fn create_wrapper_function( tcx: TyCtxt<'_>, context: &Context<'_>, from_name: &str, - to_name: &str, + to_name: Option<&str>, types: &[Type<'_>], output: Option>, ) { @@ -124,34 +124,40 @@ fn create_wrapper_function( // TODO(antoyo): emit unwind tables. } - let args: Vec<_> = types - .iter() - .enumerate() - .map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index))) - .collect(); - let callee = context.new_function( - None, - FunctionType::Extern, - output.unwrap_or(void), - &args, - to_name, - false, - ); - #[cfg(feature = "master")] - callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - let block = func.new_block("entry"); - let args = args - .iter() - .enumerate() - .map(|(i, _)| func.get_param(i as i32).to_rvalue()) - .collect::>(); - let ret = context.new_call(None, callee, &args); - //llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - block.end_with_return(None, ret); + if let Some(to_name) = to_name { + let args: Vec<_> = types + .iter() + .enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index))) + .collect(); + let callee = context.new_function( + None, + FunctionType::Extern, + output.unwrap_or(void), + &args, + to_name, + false, + ); + #[cfg(feature = "master")] + callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| func.get_param(i as i32).to_rvalue()) + .collect::>(); + let ret = context.new_call(None, callee, &args); + //llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + block.end_with_return(None, ret); + } else { + block.add_eval(None, ret); + block.end_with_void_return(None); + } } else { + assert!(output.is_none()); block.end_with_void_return(None); } diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index bf8ec8c3b9158..88efc8ac96b57 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -15,7 +15,7 @@ gimli = "0.31" itertools = "0.12" libc = "0.2" measureme = "12.0.1" -object = { version = "0.36.3", default-features = false, features = ["std", "read"] } +object = { version = "0.37.0", default-features = false, features = ["std", "read"] } rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 4a78e69497994..9dca63cfc8d4f 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen( let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); - create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false); + create_wrapper_function(tcx, &cx, &from_name, Some(&to_name), &args, output, false); } } @@ -66,7 +66,7 @@ pub(crate) unsafe fn codegen( tcx, &cx, &mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - &mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)), + Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))), &[usize, usize], // size, align None, true, @@ -81,11 +81,16 @@ pub(crate) unsafe fn codegen( let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::set_initializer(ll_g, llval); - let name = mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE); - let ll_g = cx.declare_global(&name, i8); - llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); - let llval = llvm::LLVMConstInt(i8, 0, False); - llvm::set_initializer(ll_g, llval); + // __rust_no_alloc_shim_is_unstable_v2 + create_wrapper_function( + tcx, + &cx, + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + None, + &[], + None, + false, + ); } if tcx.sess.opts.debuginfo != DebugInfo::None { @@ -99,7 +104,7 @@ fn create_wrapper_function( tcx: TyCtxt<'_>, cx: &SimpleCx<'_>, from_name: &str, - to_name: &str, + to_name: Option<&str>, args: &[&Type], output: Option<&Type>, no_return: bool, @@ -128,33 +133,38 @@ fn create_wrapper_function( attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); } - let callee = declare_simple_fn( - &cx, - to_name, - llvm::CallConv::CCallConv, - llvm::UnnamedAddr::Global, - llvm::Visibility::Hidden, - ty, - ); - if let Some(no_return) = no_return { - // -> ! DIFlagNoReturn - attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); - } - llvm::set_visibility(callee, llvm::Visibility::Hidden); - let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) }; - let mut bx = SBuilder::build(&cx, llbb); - let args = args - .iter() - .enumerate() - .map(|(i, _)| llvm::get_param(llfn, i as c_uint)) - .collect::>(); - let ret = bx.call(ty, callee, &args, None); - llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - bx.ret(ret); + + if let Some(to_name) = to_name { + let callee = declare_simple_fn( + &cx, + to_name, + llvm::CallConv::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::Hidden, + ty, + ); + if let Some(no_return) = no_return { + // -> ! DIFlagNoReturn + attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); + } + llvm::set_visibility(callee, llvm::Visibility::Hidden); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| llvm::get_param(llfn, i as c_uint)) + .collect::>(); + let ret = bx.call(ty, callee, &args, None); + llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + bx.ret(ret); + } else { + bx.ret_void() + } } else { + assert!(output.is_none()); bx.ret_void() } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 9e3893d5314ae..4185aef8b31c2 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -251,7 +251,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { InlineAsmArch::Nvptx64 => {} InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {} InlineAsmArch::Hexagon => {} - InlineAsmArch::LoongArch64 => { + InlineAsmArch::LoongArch32 | InlineAsmArch::LoongArch64 => { constraints.extend_from_slice(&[ "~{$fcc0}".to_string(), "~{$fcc1}".to_string(), diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 337c694417790..e9c4c255bce08 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -54,7 +54,7 @@ libc = "0.2.50" # tidy-alphabetical-end [dependencies.object] -version = "0.36.2" +version = "0.37.0" default-features = false features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"] diff --git a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs index 2c24378afe13b..74f39022afb7b 100644 --- a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs +++ b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs @@ -287,6 +287,7 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport] (Architecture::X86_64, None) => elf::EM_X86_64, (Architecture::X86_64_X32, None) => elf::EM_X86_64, (Architecture::Hexagon, None) => elf::EM_HEXAGON, + (Architecture::LoongArch32, None) => elf::EM_LOONGARCH, (Architecture::LoongArch64, None) => elf::EM_LOONGARCH, (Architecture::M68k, None) => elf::EM_68K, (Architecture::Mips, None) => elf::EM_MIPS, diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index ec46c71b0e401..a16862c41ee53 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -348,7 +348,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { e_flags } - Architecture::LoongArch64 => { + Architecture::LoongArch32 | Architecture::LoongArch64 => { // Source: https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc#e_flags-identifies-abi-type-and-version let mut e_flags: u32 = elf::EF_LARCH_OBJABI_V1; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 92b9b6e132e74..d0b6c7470fb9a 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -219,6 +219,7 @@ fn exported_symbols_provider_local<'tcx>( .chain([ mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), mangle_internal_symbol(tcx, OomStrategy::SYMBOL), + mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), ]) { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); @@ -232,19 +233,6 @@ fn exported_symbols_provider_local<'tcx>( }, )); } - - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new( - tcx, - &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), - )); - symbols.push(( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Data, - used: false, - }, - )) } if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index bd421a441f95c..6f0090a0bd659 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1529,7 +1529,7 @@ impl DiagCtxtInner { // Future breakages aren't emitted if they're `Level::Allow` or // `Level::Expect`, but they still need to be constructed and // stashed below, so they'll trigger the must_produce_diag check. - assert_matches!(diagnostic.level, Error | Warning | Allow | Expect); + assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect); self.future_breakage_diagnostics.push(diagnostic.clone()); } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 96e03e3bea564..e9b58eb959bda 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -823,6 +823,13 @@ impl<'tcx> InferCtxt<'tcx> { ty::Region::new_var(self.tcx, region_var) } + pub fn next_term_var_of_kind(&self, term: ty::Term<'tcx>, span: Span) -> ty::Term<'tcx> { + match term.kind() { + ty::TermKind::Ty(_) => self.next_ty_var(span).into(), + ty::TermKind::Const(_) => self.next_const_var(span).into(), + } + } + /// Return the universe that the region `r` was created in. For /// most regions (e.g., `'static`, named regions from the user, /// etc) this is the root universe U0. For inference variables or diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5b7d45bb1526f..dc29b03083f32 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1266,13 +1266,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { true } - /// Checks that `doc(test(...))` attribute contains only valid attributes. Returns `true` if - /// valid. - fn check_test_attr(&self, meta: &MetaItemInner, hir_id: HirId) { + /// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place. + fn check_test_attr(&self, attr: &Attribute, meta: &MetaItemInner, hir_id: HirId) { if let Some(metas) = meta.meta_item_list() { for i_meta in metas { match (i_meta.name(), i_meta.meta_item()) { - (Some(sym::attr | sym::no_crate_inject), _) => {} + (Some(sym::attr), _) => { + // Allowed everywhere like `#[doc]` + } + (Some(sym::no_crate_inject), _) => { + self.check_attr_crate_level(attr, meta, hir_id); + } (_, Some(m)) => { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, @@ -1359,9 +1363,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Some(sym::test) => { - if self.check_attr_crate_level(attr, meta, hir_id) { - self.check_test_attr(meta, hir_id); - } + self.check_test_attr(attr, meta, hir_id); } Some( diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 49a5e20d7cf8b..1db8ad72b321c 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -85,10 +85,6 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin if item_name == "rust_eh_personality" { // rust_eh_personality must not be renamed as LLVM hard-codes the name return "rust_eh_personality".to_owned(); - } else if item_name == "__rust_no_alloc_shim_is_unstable" { - // Temporary back compat hack to give people the chance to migrate to - // include #[rustc_std_internal_symbol]. - return "__rust_no_alloc_shim_is_unstable".to_owned(); } let prefix = "_R"; diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 189b19b028617..0121c752dbdde 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -20,5 +20,5 @@ tracing = "0.1" # tidy-alphabetical-start default-features = false features = ["elf", "macho"] -version = "0.36.2" +version = "0.37.0" # tidy-alphabetical-end diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 9f791603c723c..e06f881e4b1c7 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -226,6 +226,7 @@ pub enum InlineAsmArch { RiscV64, Nvptx64, Hexagon, + LoongArch32, LoongArch64, Mips, Mips64, @@ -260,6 +261,7 @@ impl FromStr for InlineAsmArch { "powerpc" => Ok(Self::PowerPC), "powerpc64" => Ok(Self::PowerPC64), "hexagon" => Ok(Self::Hexagon), + "loongarch32" => Ok(Self::LoongArch32), "loongarch64" => Ok(Self::LoongArch64), "mips" | "mips32r6" => Ok(Self::Mips), "mips64" | "mips64r6" => Ok(Self::Mips64), @@ -365,7 +367,9 @@ impl InlineAsmReg { Self::PowerPC(PowerPCInlineAsmReg::parse(name)?) } InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?), - InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmReg::parse(name)?), + InlineAsmArch::LoongArch32 | InlineAsmArch::LoongArch64 => { + Self::LoongArch(LoongArchInlineAsmReg::parse(name)?) + } InlineAsmArch::Mips | InlineAsmArch::Mips64 => { Self::Mips(MipsInlineAsmReg::parse(name)?) } @@ -652,7 +656,9 @@ impl InlineAsmRegClass { Self::PowerPC(PowerPCInlineAsmRegClass::parse(name)?) } InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(name)?), - InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmRegClass::parse(name)?), + InlineAsmArch::LoongArch32 | InlineAsmArch::LoongArch64 => { + Self::LoongArch(LoongArchInlineAsmRegClass::parse(name)?) + } InlineAsmArch::Mips | InlineAsmArch::Mips64 => { Self::Mips(MipsInlineAsmRegClass::parse(name)?) } @@ -860,7 +866,7 @@ pub fn allocatable_registers( hexagon::fill_reg_map(arch, reloc_model, target_features, target, &mut map); map } - InlineAsmArch::LoongArch64 => { + InlineAsmArch::LoongArch32 | InlineAsmArch::LoongArch64 => { let mut map = loongarch::regclass_map(); loongarch::fill_reg_map(arch, reloc_model, target_features, target, &mut map); map @@ -992,7 +998,7 @@ impl InlineAsmClobberAbi { "C" | "system" => Ok(InlineAsmClobberAbi::Avr), _ => Err(&["C", "system"]), }, - InlineAsmArch::LoongArch64 => match name { + InlineAsmArch::LoongArch32 | InlineAsmArch::LoongArch64 => match name { "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch), _ => Err(&["C", "system"]), }, diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index dcb79cce75933..f9ecf02f857f1 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -648,7 +648,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { "amdgpu" => amdgpu::compute_abi_info(cx, self), "arm" => arm::compute_abi_info(cx, self), "avr" => avr::compute_abi_info(self), - "loongarch64" => loongarch::compute_abi_info(cx, self), + "loongarch32" | "loongarch64" => loongarch::compute_abi_info(cx, self), "m68k" => m68k::compute_abi_info(self), "csky" => csky::compute_abi_info(self), "mips" | "mips32r6" => mips::compute_abi_info(cx, self), @@ -691,7 +691,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { match &*spec.arch { "x86" => x86::compute_rust_abi_info(cx, self), "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self), - "loongarch64" => loongarch::compute_rust_abi_info(cx, self), + "loongarch32" | "loongarch64" => loongarch::compute_rust_abi_info(cx, self), "aarch64" => aarch64::compute_rust_abi_info(cx, self), _ => {} }; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 6529c2d72c827..b7916df77c8cb 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1981,6 +1981,8 @@ supported_targets! { ("sparc-unknown-none-elf", sparc_unknown_none_elf), + ("loongarch32-unknown-none", loongarch32_unknown_none), + ("loongarch32-unknown-none-softfloat", loongarch32_unknown_none_softfloat), ("loongarch64-unknown-none", loongarch64_unknown_none), ("loongarch64-unknown-none-softfloat", loongarch64_unknown_none_softfloat), @@ -3502,6 +3504,7 @@ impl Target { "msp430" => (Architecture::Msp430, None), "hexagon" => (Architecture::Hexagon, None), "bpf" => (Architecture::Bpf, None), + "loongarch32" => (Architecture::LoongArch32, None), "loongarch64" => (Architecture::LoongArch64, None), "csky" => (Architecture::Csky, None), "arm64ec" => (Architecture::Aarch64, Some(object::SubArchitecture::Arm64EC)), diff --git a/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none.rs new file mode 100644 index 0000000000000..fb4963b88b0f4 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none.rs @@ -0,0 +1,29 @@ +use crate::spec::{ + Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, +}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "loongarch32-unknown-none".into(), + metadata: TargetMetadata { + description: Some("Freestanding/bare-metal LoongArch32".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), + arch: "loongarch32".into(), + options: TargetOptions { + cpu: "generic".into(), + features: "+f,+d".into(), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + llvm_abiname: "ilp32d".into(), + max_atomic_width: Some(32), + relocation_model: RelocModel::Static, + panic_strategy: PanicStrategy::Abort, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none_softfloat.rs new file mode 100644 index 0000000000000..0e65f83a71cff --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none_softfloat.rs @@ -0,0 +1,30 @@ +use crate::spec::{ + Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, +}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "loongarch32-unknown-none".into(), + metadata: TargetMetadata { + description: Some("Freestanding/bare-metal LoongArch32 softfloat".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), + arch: "loongarch32".into(), + options: TargetOptions { + cpu: "generic".into(), + features: "-f,-d".into(), + abi: "softfloat".into(), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + llvm_abiname: "ilp32s".into(), + max_atomic_width: Some(32), + relocation_model: RelocModel::Static, + panic_strategy: PanicStrategy::Abort, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 682c4c5068f9e..c1f128fdc87a4 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -846,7 +846,7 @@ impl Target { "wasm32" | "wasm64" => WASM_FEATURES, "bpf" => BPF_FEATURES, "csky" => CSKY_FEATURES, - "loongarch64" => LOONGARCH_FEATURES, + "loongarch32" | "loongarch64" => LOONGARCH_FEATURES, "s390x" => IBMZ_FEATURES, "sparc" | "sparc64" => SPARC_FEATURES, "m68k" => M68K_FEATURES, @@ -860,7 +860,7 @@ impl Target { "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI, "arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI, "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI, - "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI, + "loongarch32" | "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI, "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI, "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI, "s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI, @@ -1034,7 +1034,7 @@ impl Target { _ => unreachable!(), } } - "loongarch64" => { + "loongarch32" | "loongarch64" => { // LoongArch handles ABI in a very sane way, being fully explicit via `llvm_abiname` // about what the intended ABI is. match &*self.llvm_abiname { diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 1193a9059ca9a..de1bd724052b9 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -206,10 +206,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let infcx = self.goal.infcx; match goal.predicate.kind().no_bound_vars() { Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => { - let unconstrained_term = match term.kind() { - ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(), - ty::TermKind::Const(_) => infcx.next_const_var(span).into(), - }; + let unconstrained_term = infcx.next_term_var_of_kind(term, span); let goal = goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term }); // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index d903f94b489d3..8f44c26b70dad 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -1,4 +1,3 @@ -use std::assert_matches::assert_matches; use std::fmt::Debug; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -16,7 +15,6 @@ use tracing::instrument; use super::{FulfillmentCtxt, NextSolverError}; use crate::error_reporting::InferCtxtErrorExt; use crate::error_reporting::traits::OverflowCause; -use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError}; /// Deeply normalize all aliases in `value`. This does not handle inference and expects @@ -97,19 +95,18 @@ impl<'tcx, E> NormalizationFolder<'_, 'tcx, E> where E: FromSolverError<'tcx, NextSolverError<'tcx>>, { - fn normalize_alias_ty(&mut self, alias_ty: Ty<'tcx>) -> Result, Vec> { - assert_matches!(alias_ty.kind(), ty::Alias(..)); - + fn normalize_alias_term( + &mut self, + alias_term: ty::Term<'tcx>, + ) -> Result, Vec> { let infcx = self.at.infcx; let tcx = infcx.tcx; let recursion_limit = tcx.recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { - let ty::Alias(_, data) = *alias_ty.kind() else { - unreachable!(); - }; + let term = alias_term.to_alias_term().unwrap(); self.at.infcx.err_ctxt().report_overflow_error( - OverflowCause::DeeplyNormalize(data.into()), + OverflowCause::DeeplyNormalize(term), self.at.cause.span, true, |_| {}, @@ -118,14 +115,14 @@ where self.depth += 1; - let new_infer_ty = infcx.next_ty_var(self.at.cause.span); + let infer_term = infcx.next_term_var_of_kind(alias_term, self.at.cause.span); let obligation = Obligation::new( tcx, self.at.cause.clone(), self.at.param_env, ty::PredicateKind::AliasRelate( - alias_ty.into(), - new_infer_ty.into(), + alias_term.into(), + infer_term.into(), ty::AliasRelationDirection::Equate, ), ); @@ -135,50 +132,13 @@ where // Alias is guaranteed to be fully structurally resolved, // so we can super fold here. - let ty = infcx.resolve_vars_if_possible(new_infer_ty); - let result = ty.try_super_fold_with(self)?; - self.depth -= 1; - Ok(result) - } - - fn normalize_unevaluated_const( - &mut self, - uv: ty::UnevaluatedConst<'tcx>, - ) -> Result, Vec> { - let infcx = self.at.infcx; - let tcx = infcx.tcx; - let recursion_limit = tcx.recursion_limit(); - if !recursion_limit.value_within_limit(self.depth) { - self.at.infcx.err_ctxt().report_overflow_error( - OverflowCause::DeeplyNormalize(uv.into()), - self.at.cause.span, - true, - |_| {}, - ); - } - - self.depth += 1; - - let new_infer_ct = infcx.next_const_var(self.at.cause.span); - let obligation = Obligation::new( - tcx, - self.at.cause.clone(), - self.at.param_env, - ty::NormalizesTo { alias: uv.into(), term: new_infer_ct.into() }, - ); - - let result = if infcx.predicate_may_hold(&obligation) { - self.fulfill_cx.register_predicate_obligation(infcx, obligation); - let errors = self.fulfill_cx.select_where_possible(infcx); - if !errors.is_empty() { - return Err(errors); - } - let ct = infcx.resolve_vars_if_possible(new_infer_ct); - ct.try_fold_with(self)? - } else { - ty::Const::new_unevaluated(tcx, uv).try_super_fold_with(self)? + let term = infcx.resolve_vars_if_possible(infer_term); + // super-folding the `term` will directly fold the `Ty` or `Const` so + // we have to match on the term and super-fold them manually. + let result = match term.kind() { + ty::TermKind::Ty(ty) => ty.try_super_fold_with(self)?.into(), + ty::TermKind::Const(ct) => ct.try_super_fold_with(self)?.into(), }; - self.depth -= 1; Ok(result) } @@ -238,7 +198,8 @@ where if ty.has_escaping_bound_vars() { let (ty, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ty); - let result = ensure_sufficient_stack(|| self.normalize_alias_ty(ty))?; + let result = + ensure_sufficient_stack(|| self.normalize_alias_term(ty.into()))?.expect_type(); Ok(PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, @@ -248,7 +209,7 @@ where result, )) } else { - ensure_sufficient_stack(|| self.normalize_alias_ty(ty)) + Ok(ensure_sufficient_stack(|| self.normalize_alias_term(ty.into()))?.expect_type()) } } @@ -260,15 +221,13 @@ where return Ok(ct); } - let uv = match ct.kind() { - ty::ConstKind::Unevaluated(ct) => ct, - _ => return ct.try_super_fold_with(self), - }; + let ty::ConstKind::Unevaluated(..) = ct.kind() else { return ct.try_super_fold_with(self) }; - if uv.has_escaping_bound_vars() { - let (uv, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, uv); - let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv))?; + if ct.has_escaping_bound_vars() { + let (ct, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ct); + let result = + ensure_sufficient_stack(|| self.normalize_alias_term(ct.into()))?.expect_const(); Ok(PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, @@ -278,7 +237,7 @@ where result, )) } else { - ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv)) + Ok(ensure_sufficient_stack(|| self.normalize_alias_term(ct.into()))?.expect_const()) } } } diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 3f7413454047d..2e20ede2f50a8 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -39,10 +39,7 @@ impl<'tcx> At<'_, 'tcx> { return Ok(term); } - let new_infer = match term.kind() { - ty::TermKind::Ty(_) => self.infcx.next_ty_var(self.cause.span).into(), - ty::TermKind::Const(_) => self.infcx.next_const_var(self.cause.span).into(), - }; + let new_infer = self.infcx.next_term_var_of_kind(term, self.cause.span); // We simply emit an `alias-eq` goal here, since that will take care of // normalizing the LHS of the projection until it is a rigid projection diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index e1cc4ba25c4ea..b4176e9c1f4d0 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -31,8 +31,9 @@ unsafe extern "Rust" { #[rustc_std_internal_symbol] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; + #[rustc_nounwind] #[rustc_std_internal_symbol] - static __rust_no_alloc_shim_is_unstable: u8; + fn __rust_no_alloc_shim_is_unstable_v2(); } /// The global memory allocator. @@ -88,7 +89,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { unsafe { // Make sure we don't accidentally allow omitting the allocator shim in // stable code until it is actually stabilized. - core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); + __rust_no_alloc_shim_is_unstable_v2(); __rust_alloc(layout.size(), layout.align()) } @@ -171,7 +172,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { unsafe { // Make sure we don't accidentally allow omitting the allocator shim in // stable code until it is actually stabilized. - core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); + __rust_no_alloc_shim_is_unstable_v2(); __rust_alloc_zeroed(layout.size(), layout.align()) } diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index f88661ee00151..5d65b55bcdabe 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -29,6 +29,8 @@ debug_typeid = [] [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ + # #[cfg(bootstrap)] loongarch32 + 'cfg(target_arch, values("loongarch32"))', 'cfg(no_fp_fmt_parse)', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index bf923d4070ad7..b460c7d0205bf 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1879,7 +1879,7 @@ pub mod math { /// /// let x = 2.0_f32; /// let abs_difference = (f32::math::powi(x, 2) - (x * x)).abs(); - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-5); /// /// assert_eq!(f32::math::powi(f32::NAN, 0), 1.0); /// ``` diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index be933cfa41ae9..2f10e6db58c8a 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1877,7 +1877,7 @@ pub mod math { /// /// let x = 2.0_f64; /// let abs_difference = (f64::math::powi(x, 2) - (x * x)).abs(); - /// assert!(abs_difference <= f64::EPSILON); + /// assert!(abs_difference <= 1e-6); /// /// assert_eq!(f64::math::powi(f64::NAN, 0), 1.0); /// ``` diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index ea459f6d92d86..e07a372943c55 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -178,7 +178,7 @@ //! //! | `target_arch` | Size limit | //! |---------------|---------| -//! | `x86`, `arm`, `mips`, `mips32r6`, `powerpc`, `riscv32`, `sparc`, `hexagon` | 4 bytes | +//! | `x86`, `arm`, `loongarch32`, `mips`, `mips32r6`, `powerpc`, `riscv32`, `sparc`, `hexagon` | 4 bytes | //! | `x86_64`, `aarch64`, `loongarch64`, `mips64`, `mips64r6`, `powerpc64`, `riscv64`, `sparc64`, `s390x` | 8 bytes | //! //! Atomics loads that are larger than this limit as well as atomic loads with ordering other @@ -349,8 +349,12 @@ pub type Atomic = ::AtomicInner; // This list should only contain architectures which have word-sized atomic-or/ // atomic-and instructions but don't natively support byte-sized atomics. #[cfg(target_has_atomic = "8")] -const EMULATE_ATOMIC_BOOL: bool = - cfg!(any(target_arch = "riscv32", target_arch = "riscv64", target_arch = "loongarch64")); +const EMULATE_ATOMIC_BOOL: bool = cfg!(any( + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "loongarch32", + target_arch = "loongarch64" +)); /// A boolean type which can be safely shared between threads. /// diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 4e6509ead2ba8..98e9695d09036 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -23,6 +23,11 @@ const NAN_MASK1: u32 = 0x002a_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u32 = 0x0055_5555; +/// Miri adds some extra errors to float functions; make sure the tests still pass. +/// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides. +/// They serve as a way to get an idea of the real precision of floating point operations on different platforms. +const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; + #[test] fn test_num_f32() { super::test_num(10f32, 2f32); @@ -437,8 +442,8 @@ fn test_powi() { let nan: f32 = f32::NAN; let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; - assert_biteq!(1.0f32.powi(1), 1.0); - assert_approx_eq!((-3.1f32).powi(2), 9.61); + assert_approx_eq!(1.0f32.powi(1), 1.0); + assert_approx_eq!((-3.1f32).powi(2), 9.61, APPROX_DELTA); assert_approx_eq!(5.9f32.powi(-2), 0.028727); assert_biteq!(8.3f32.powi(0), 1.0); assert!(nan.powi(2).is_nan()); diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 74202a3740916..dd5b67c251dc0 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -422,7 +422,7 @@ fn test_powi() { let nan: f64 = f64::NAN; let inf: f64 = f64::INFINITY; let neg_inf: f64 = f64::NEG_INFINITY; - assert_biteq!(1.0f64.powi(1), 1.0); + assert_approx_eq!(1.0f64.powi(1), 1.0); assert_approx_eq!((-3.1f64).powi(2), 9.61); assert_approx_eq!(5.9f64.powi(-2), 0.028727); assert_biteq!(8.3f64.powi(0), 1.0); diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs index 264de061be98c..2407ba50ca31c 100644 --- a/library/coretests/tests/num/dec2flt/float.rs +++ b/library/coretests/tests/num/dec2flt/float.rs @@ -23,7 +23,8 @@ fn test_f16_integer_decode() { fn test_f32_integer_decode() { assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); - assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); + // Set 2^100 directly instead of using powf, because it doesn't guarentee precision + assert_eq!(1.2676506e30_f32.integer_decode(), (8388608, 77, 1)); assert_eq!(0f32.integer_decode(), (0, -150, 1)); assert_eq!((-0f32).integer_decode(), (0, -150, -1)); assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1)); @@ -39,7 +40,8 @@ fn test_f32_integer_decode() { fn test_f64_integer_decode() { assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); - assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); + // Set 2^100 directly instead of using powf, because it doesn't guarentee precision + assert_eq!(1.2676506002282294e30_f64.integer_decode(), (4503599627370496, 48, 1)); assert_eq!(0f64.integer_decode(), (0, -1075, 1)); assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1)); diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 196b904d56a1e..0419336e13a29 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -157,6 +157,8 @@ test = true [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ + # #[cfg(bootstrap)] loongarch32 + 'cfg(target_arch, values("loongarch32"))', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/std/src/env.rs b/library/std/src/env.rs index ce2dc79522076..6d7d576b32a10 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -1046,6 +1046,7 @@ pub mod consts { /// * `"sparc"` /// * `"sparc64"` /// * `"hexagon"` + /// * `"loongarch32"` /// * `"loongarch64"` /// /// diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index b7f6529ac4027..e79ec2ae966ff 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -304,7 +304,7 @@ impl f32 { /// ``` /// let x = 2.0_f32; /// let abs_difference = (x.powi(2) - (x * x)).abs(); - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-5); /// /// assert_eq!(f32::powi(f32::NAN, 0), 1.0); /// ``` @@ -328,7 +328,7 @@ impl f32 { /// ``` /// let x = 2.0_f32; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-5); /// /// assert_eq!(f32::powf(1.0, f32::NAN), 1.0); /// assert_eq!(f32::powf(f32::NAN, 0.0), 1.0); @@ -388,7 +388,7 @@ impl f32 { /// // ln(e) - 1 == 0 /// let abs_difference = (e.ln() - 1.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -413,7 +413,7 @@ impl f32 { /// // 2^2 - 4 == 0 /// let abs_difference = (f.exp2() - 4.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-5); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -442,7 +442,7 @@ impl f32 { /// // ln(e) - 1 == 0 /// let abs_difference = (e.ln() - 1.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` /// /// Non-positive values: @@ -479,7 +479,7 @@ impl f32 { /// // log5(5) - 1 == 0 /// let abs_difference = (five.log(5.0) - 1.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` /// /// Non-positive values: @@ -512,7 +512,7 @@ impl f32 { /// // log2(2) - 1 == 0 /// let abs_difference = (two.log2() - 1.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` /// /// Non-positive values: @@ -545,7 +545,7 @@ impl f32 { /// // log10(10) - 1 == 0 /// let abs_difference = (ten.log10() - 1.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` /// /// Non-positive values: @@ -652,7 +652,7 @@ impl f32 { /// // sqrt(x^2 + y^2) /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -676,7 +676,7 @@ impl f32 { /// /// let abs_difference = (x.sin() - 1.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -700,7 +700,7 @@ impl f32 { /// /// let abs_difference = (x.cos() - 1.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -754,7 +754,7 @@ impl f32 { /// // asin(sin(pi/2)) /// let abs_difference = (f.sin().asin() - std::f32::consts::FRAC_PI_2).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-3); /// ``` #[doc(alias = "arcsin")] #[rustc_allow_incoherent_impl] @@ -784,7 +784,7 @@ impl f32 { /// // acos(cos(pi/4)) /// let abs_difference = (f.cos().acos() - std::f32::consts::FRAC_PI_4).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[doc(alias = "arccos")] #[rustc_allow_incoherent_impl] @@ -884,8 +884,8 @@ impl f32 { /// let abs_difference_0 = (f.0 - x.sin()).abs(); /// let abs_difference_1 = (f.1 - x.cos()).abs(); /// - /// assert!(abs_difference_0 <= f32::EPSILON); - /// assert!(abs_difference_1 <= f32::EPSILON); + /// assert!(abs_difference_0 <= 1e-6); + /// assert!(abs_difference_1 <= 1e-6); /// ``` #[doc(alias = "sincos")] #[rustc_allow_incoherent_impl] @@ -1067,7 +1067,7 @@ impl f32 { /// /// let abs_difference = (f - x).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-7); /// ``` #[doc(alias = "arcsinh")] #[rustc_allow_incoherent_impl] @@ -1095,7 +1095,7 @@ impl f32 { /// /// let abs_difference = (f - x).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[doc(alias = "arccosh")] #[rustc_allow_incoherent_impl] diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 75e35a8db3354..853417825f97a 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -304,7 +304,7 @@ impl f64 { /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powi(2) - (x * x)).abs(); - /// assert!(abs_difference <= f64::EPSILON); + /// assert!(abs_difference <= 1e-14); /// /// assert_eq!(f64::powi(f64::NAN, 0), 1.0); /// ``` @@ -328,7 +328,7 @@ impl f64 { /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); - /// assert!(abs_difference <= f64::EPSILON); + /// assert!(abs_difference <= 1e-14); /// /// assert_eq!(f64::powf(1.0, f64::NAN), 1.0); /// assert_eq!(f64::powf(f64::NAN, 0.0), 1.0); @@ -754,7 +754,7 @@ impl f64 { /// // asin(sin(pi/2)) /// let abs_difference = (f.sin().asin() - std::f64::consts::FRAC_PI_2).abs(); /// - /// assert!(abs_difference < 1e-10); + /// assert!(abs_difference < 1e-7); /// ``` #[doc(alias = "arcsin")] #[rustc_allow_incoherent_impl] diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index d53674d3c5f2c..6483f0861139b 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -231,6 +231,7 @@ mod arch { } #[cfg(any( + target_arch = "loongarch32", target_arch = "loongarch64", target_arch = "mips64", target_arch = "mips64r6", diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs index 8489e17c971d9..f3af1f7f5991e 100644 --- a/library/std/src/sys/alloc/mod.rs +++ b/library/std/src/sys/alloc/mod.rs @@ -17,6 +17,7 @@ const MIN_ALIGN: usize = if cfg!(any( target_arch = "arm", target_arch = "m68k", target_arch = "csky", + target_arch = "loongarch32", target_arch = "mips", target_arch = "mips32r6", target_arch = "powerpc", diff --git a/library/std/src/sys/personality/gcc.rs b/library/std/src/sys/personality/gcc.rs index b012e47f9aa24..75e793f18b835 100644 --- a/library/std/src/sys/personality/gcc.rs +++ b/library/std/src/sys/personality/gcc.rs @@ -86,7 +86,7 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 #[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 -#[cfg(target_arch = "loongarch64")] +#[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1 // The following code is based on GCC's C and C++ personality routines. For reference, see: diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs index e54f227bb774b..38c906c1d8771 100644 --- a/library/std/tests/floats/f32.rs +++ b/library/std/tests/floats/f32.rs @@ -1,5 +1,10 @@ use std::f32::consts; +/// Miri adds some extra errors to float functions; make sure the tests still pass. +/// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides. +/// They serve as a way to get an idea of the real precision of floating point operations on different platforms. +const APPROX_DELTA: f32 = if cfg!(miri) { 1e-3 } else { 1e-6 }; + #[allow(unused_macros)] macro_rules! assert_f32_biteq { ($left : expr, $right : expr) => { @@ -17,9 +22,9 @@ fn test_powf() { let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; assert_eq!(1.0f32.powf(1.0), 1.0); - assert_approx_eq!(3.4f32.powf(4.5), 246.408218); + assert_approx_eq!(3.4f32.powf(4.5), 246.408218, APPROX_DELTA); assert_approx_eq!(2.7f32.powf(-3.2), 0.041652); - assert_approx_eq!((-3.1f32).powf(2.0), 9.61); + assert_approx_eq!((-3.1f32).powf(2.0), 9.61, APPROX_DELTA); assert_approx_eq!(5.9f32.powf(-2.0), 0.028727); assert_eq!(8.3f32.powf(0.0), 1.0); assert!(nan.powf(2.0).is_nan()); @@ -30,8 +35,8 @@ fn test_powf() { #[test] fn test_exp() { assert_eq!(1.0, 0.0f32.exp()); - assert_approx_eq!(2.718282, 1.0f32.exp()); - assert_approx_eq!(148.413162, 5.0f32.exp()); + assert_approx_eq!(2.718282, 1.0f32.exp(), APPROX_DELTA); + assert_approx_eq!(148.413162, 5.0f32.exp(), APPROX_DELTA); let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; @@ -43,7 +48,7 @@ fn test_exp() { #[test] fn test_exp2() { - assert_eq!(32.0, 5.0f32.exp2()); + assert_approx_eq!(32.0, 5.0f32.exp2(), APPROX_DELTA); assert_eq!(1.0, 0.0f32.exp2()); let inf: f32 = f32::INFINITY; @@ -66,7 +71,7 @@ fn test_ln() { assert!((-2.3f32).ln().is_nan()); assert_eq!((-0.0f32).ln(), neg_inf); assert_eq!(0.0f32.ln(), neg_inf); - assert_approx_eq!(4.0f32.ln(), 1.386294); + assert_approx_eq!(4.0f32.ln(), 1.386294, APPROX_DELTA); } #[test] @@ -74,9 +79,9 @@ fn test_log() { let nan: f32 = f32::NAN; let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(10.0f32.log(10.0), 1.0); + assert_approx_eq!(10.0f32.log(10.0), 1.0); assert_approx_eq!(2.3f32.log(3.5), 0.664858); - assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0); + assert_approx_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0, APPROX_DELTA); assert!(1.0f32.log(1.0).is_nan()); assert!(1.0f32.log(-13.9).is_nan()); assert!(nan.log(2.3).is_nan()); @@ -92,9 +97,9 @@ fn test_log2() { let nan: f32 = f32::NAN; let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(10.0f32.log2(), 3.321928); + assert_approx_eq!(10.0f32.log2(), 3.321928, APPROX_DELTA); assert_approx_eq!(2.3f32.log2(), 1.201634); - assert_approx_eq!(1.0f32.exp().log2(), 1.442695); + assert_approx_eq!(1.0f32.exp().log2(), 1.442695, APPROX_DELTA); assert!(nan.log2().is_nan()); assert_eq!(inf.log2(), inf); assert!(neg_inf.log2().is_nan()); @@ -108,7 +113,7 @@ fn test_log10() { let nan: f32 = f32::NAN; let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(10.0f32.log10(), 1.0); + assert_approx_eq!(10.0f32.log10(), 1.0); assert_approx_eq!(2.3f32.log10(), 0.361728); assert_approx_eq!(1.0f32.exp().log10(), 0.434294); assert_eq!(1.0f32.log10(), 0.0); @@ -158,7 +163,7 @@ fn test_acosh() { assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); // test for low accuracy from issue 104548 - assert_approx_eq!(60.0f32, 60.0f32.cosh().acosh()); + assert_approx_eq!(60.0f32, 60.0f32.cosh().acosh(), APPROX_DELTA); } #[test] @@ -237,7 +242,7 @@ fn test_real_consts() { let ln_10: f32 = consts::LN_10; assert_approx_eq!(frac_pi_2, pi / 2f32); - assert_approx_eq!(frac_pi_3, pi / 3f32); + assert_approx_eq!(frac_pi_3, pi / 3f32, APPROX_DELTA); assert_approx_eq!(frac_pi_4, pi / 4f32); assert_approx_eq!(frac_pi_6, pi / 6f32); assert_approx_eq!(frac_pi_8, pi / 8f32); @@ -249,5 +254,5 @@ fn test_real_consts() { assert_approx_eq!(log2_e, e.log2()); assert_approx_eq!(log10_e, e.log10()); assert_approx_eq!(ln_2, 2f32.ln()); - assert_approx_eq!(ln_10, 10f32.ln()); + assert_approx_eq!(ln_10, 10f32.ln(), APPROX_DELTA); } diff --git a/library/std/tests/floats/f64.rs b/library/std/tests/floats/f64.rs index 2d8dd1cf0915b..fccf20097278b 100644 --- a/library/std/tests/floats/f64.rs +++ b/library/std/tests/floats/f64.rs @@ -43,7 +43,7 @@ fn test_exp() { #[test] fn test_exp2() { - assert_eq!(32.0, 5.0f64.exp2()); + assert_approx_eq!(32.0, 5.0f64.exp2()); assert_eq!(1.0, 0.0f64.exp2()); let inf: f64 = f64::INFINITY; @@ -74,9 +74,9 @@ fn test_log() { let nan: f64 = f64::NAN; let inf: f64 = f64::INFINITY; let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(10.0f64.log(10.0), 1.0); + assert_approx_eq!(10.0f64.log(10.0), 1.0); assert_approx_eq!(2.3f64.log(3.5), 0.664858); - assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); + assert_approx_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); assert!(1.0f64.log(1.0).is_nan()); assert!(1.0f64.log(-13.9).is_nan()); assert!(nan.log(2.3).is_nan()); @@ -108,7 +108,7 @@ fn test_log10() { let nan: f64 = f64::NAN; let inf: f64 = f64::INFINITY; let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(10.0f64.log10(), 1.0); + assert_approx_eq!(10.0f64.log10(), 1.0); assert_approx_eq!(2.3f64.log10(), 0.361728); assert_approx_eq!(1.0f64.exp().log10(), 0.434294); assert_eq!(1.0f64.log10(), 0.0); diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index df43e6ae80fb0..0db3f7450f179 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -37,4 +37,4 @@ system-llvm-libunwind = [] [lints.rust.unexpected_cfgs] level = "warn" -check-cfg = ['cfg(emscripten_wasm_eh)'] +check-cfg = ['cfg(emscripten_wasm_eh)', 'cfg(target_arch, values("loongarch32"))'] diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 12582569a573b..b350003cbb198 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -81,7 +81,7 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(all(target_arch = "hexagon", target_os = "linux"))] pub const unwinder_private_data_size: usize = 35; -#[cfg(target_arch = "loongarch64")] +#[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] pub const unwinder_private_data_size: usize = 2; #[repr(C)] diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c60c6b8db6404..d8c6be7824770 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -394,6 +394,7 @@ def default_build_triple(verbose): "i686": "i686", "i686-AT386": "i686", "i786": "i686", + "loongarch32": "loongarch32", "loongarch64": "loongarch64", "m68k": "m68k", "csky": "csky", diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index af4ec679d080d..59ae303e21e81 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -34,6 +34,8 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined + "loongarch32-unknown-none", + "loongarch32-unknown-none-softfloat", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index e7dfaaf4fd5d8..e2e2ad9ac3b5b 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -324,6 +324,8 @@ target | std | host | notes [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] [^win32-msvc-alignment] [`i686-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [^x86_32-floats-return-ABI] [`loongarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | LoongArch64 OpenHarmony +[`loongarch32-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch32 Bare-metal (ILP32D ABI) +[`loongarch32-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch32 Bare-metal (ILP32S ABI) [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? | | Motorola 680x0 Linux [`m68k-unknown-none-elf`](platform-support/m68k-unknown-none-elf.md) | | | Motorola 680x0 `mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23) diff --git a/src/doc/rustc/src/platform-support/loongarch-none.md b/src/doc/rustc/src/platform-support/loongarch-none.md index a2bd6e5734cd4..fd90b0a27638a 100644 --- a/src/doc/rustc/src/platform-support/loongarch-none.md +++ b/src/doc/rustc/src/platform-support/loongarch-none.md @@ -1,18 +1,18 @@ # `loongarch*-unknown-none*` -**Tier: 2** +Freestanding/bare-metal LoongArch binaries in ELF format: firmware, kernels, etc. -Freestanding/bare-metal LoongArch64 binaries in ELF format: firmware, kernels, etc. - -| Target | Description | -|--------|-------------| -| `loongarch64-unknown-none` | LoongArch 64-bit, LP64D ABI (freestanding, hard-float) | -| `loongarch64-unknown-none-softfloat` | LoongArch 64-bit, LP64S ABI (freestanding, soft-float) | +| Target | Description | Tier | +|--------|-------------|------| +| `loongarch32-unknown-none` | LoongArch 32-bit, ILP32D ABI (freestanding, hard-float) | Tier 3 | +| `loongarch32-unknown-none-softfloat` | LoongArch 32-bit, ILP32S ABI (freestanding, soft-float) | Tier 3 | +| `loongarch64-unknown-none` | LoongArch 64-bit, LP64D ABI (freestanding, hard-float) | Tier 2 | +| `loongarch64-unknown-none-softfloat` | LoongArch 64-bit, LP64S ABI (freestanding, soft-float) | Tier 2 | ## Target maintainers -[@heiher](https://github.com/heiher) -[@xen0n](https://github.com/xen0n) +- [@heiher](https://github.com/heiher) +- [@xen0n](https://github.com/xen0n) ## Requirements @@ -29,13 +29,13 @@ additional CPU features via the `-C target-feature=` codegen options to rustc, o via the `#[target_feature]` mechanism within Rust code. By default, code generated with the soft-float target should run on any -LoongArch64 hardware, with the hard-float target additionally requiring an FPU; +LoongArch hardware, with the hard-float target additionally requiring an FPU; enabling additional target features may raise this baseline. Code generated with the targets will use the `medium` code model by default. You can change this using the `-C code-model=` option to rustc. -On `loongarch64-unknown-none*`, `extern "C"` uses the [architecture's standard calling convention][lapcs]. +On `loongarch*-unknown-none*`, `extern "C"` uses the [architecture's standard calling convention][lapcs]. [lapcs]: https://github.com/loongson/la-abi-specs/blob/release/lapcs.adoc @@ -52,6 +52,8 @@ list in `bootstrap.toml`: [build] build-stage = 1 target = [ + "loongarch32-unknown-none", + "loongarch32-unknown-none-softfloat", "loongarch64-unknown-none", "loongarch64-unknown-none-softfloat", ] @@ -64,13 +66,28 @@ As the targets support a variety of different environments and do not support ## Building Rust programs +### loongarch32-unknown-none* + +The `loongarch32-unknown-none*` targets are Tier 3, so you must build the Rust +compiler from source to use them. + +```sh +# target flag may be used with any cargo or rustc command +cargo build --target loongarch32-unknown-none +cargo build --target loongarch32-unknown-none-softfloat +``` + +### loongarch64-unknown-none* + Starting with Rust 1.74, precompiled artifacts are provided via `rustup`: ```sh # install cross-compile toolchain rustup target add loongarch64-unknown-none +rustup target add loongarch64-unknown-none-softfloat # target flag may be used with any cargo or rustc command cargo build --target loongarch64-unknown-none +cargo build --target loongarch64-unknown-none-softfloat ``` ## Cross-compilation toolchains and C code @@ -79,10 +96,10 @@ For cross builds, you will need an appropriate LoongArch C/C++ toolchain for linking, or if you want to compile C code along with Rust (such as for Rust crates with C dependencies). -Rust *may* be able to use an `loongarch64-unknown-linux-gnu-` toolchain with +Rust *may* be able to use an `loongarch{32,64}-unknown-linux-{gnu,musl}-` toolchain with appropriate standalone flags to build for this toolchain (depending on the assumptions of that toolchain, see below), or you may wish to use a separate -`loongarch64-unknown-none` toolchain. +`loongarch{32,64}-unknown-none` toolchain. On some LoongArch hosts that use ELF binaries, you *may* be able to use the host C toolchain, if it does not introduce assumptions about the host environment diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index 6ec93d1746c8f..65e6b41742730 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -143,15 +143,6 @@ But if you include this: it will not. -### `test(attr(...))` - -This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For -example, if you want your doctests to fail if they have dead code, you could add this: - -```rust,no_run -#![doc(test(attr(deny(dead_code))))] -``` - ## At the item level These forms of the `#[doc]` attribute are used on individual items, to control how @@ -283,3 +274,26 @@ To get around this limitation, we just add `#[doc(alias = "lib_name_do_something on the `do_something` method and then it's all good! Users can now look for `lib_name_do_something` in our crate directly and find `Obj::do_something`. + +### `test(attr(...))` + +This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For +example, if you want your doctests to fail if they have dead code, you could add this: + +```rust,no_run +#![doc(test(attr(deny(dead_code))))] + +mod my_mod { + #![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module +} +``` + +`test(attr(..))` attributes are appended to the parent module's, they do not replace the current +list of attributes. In the previous example, both attributes would be present: + +```rust,no_run +// For every doctest in `my_mod` + +#![deny(dead_code)] // from the crate-root +#![allow(dead_code)] // from `my_mod` +``` diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index ebc276b38fbfa..a3762e4117d18 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -508,6 +508,7 @@ impl fmt::Display for Display<'_> { (sym::target_arch, Some(arch)) => match arch.as_str() { "aarch64" => "AArch64", "arm" => "ARM", + "loongarch32" => "LoongArch LA32", "loongarch64" => "LoongArch LA64", "m68k" => "M68k", "csky" => "CSKY", diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index b2fe24db0a2eb..a81d6020f7143 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -5,6 +5,7 @@ mod runner; mod rust; use std::fs::File; +use std::hash::{Hash, Hasher}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; @@ -14,7 +15,7 @@ use std::{panic, str}; pub(crate) use make::{BuildDocTestBuilder, DocTestBuilder}; pub(crate) use markdown::test as test_markdown; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHasher, FxIndexMap, FxIndexSet}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagCtxtHandle}; use rustc_hir as hir; @@ -45,8 +46,6 @@ pub(crate) struct GlobalTestOptions { /// Whether inserting extra indent spaces in code block, /// default is `false`, only `true` for generating code link of Rust playground pub(crate) insert_indent_space: bool, - /// Additional crate-level attributes to add to doctests. - pub(crate) attrs: Vec, /// Path to file containing arguments for the invocation of rustc. pub(crate) args_file: PathBuf, } @@ -283,7 +282,7 @@ pub(crate) fn run_tests( rustdoc_options: &Arc, unused_extern_reports: &Arc>>, mut standalone_tests: Vec, - mergeable_tests: FxIndexMap>, + mergeable_tests: FxIndexMap>, // We pass this argument so we can drop it manually before using `exit`. mut temp_dir: Option, ) { @@ -298,7 +297,7 @@ pub(crate) fn run_tests( let mut ran_edition_tests = 0; let target_str = rustdoc_options.target.to_string(); - for (edition, mut doctests) in mergeable_tests { + for (MergeableTestKey { edition, global_crate_attrs_hash }, mut doctests) in mergeable_tests { if doctests.is_empty() { continue; } @@ -308,8 +307,8 @@ pub(crate) fn run_tests( let rustdoc_test_options = IndividualTestOptions::new( rustdoc_options, - &Some(format!("merged_doctest_{edition}")), - PathBuf::from(format!("doctest_{edition}.rs")), + &Some(format!("merged_doctest_{edition}_{global_crate_attrs_hash}")), + PathBuf::from(format!("doctest_{edition}_{global_crate_attrs_hash}.rs")), ); for (doctest, scraped_test) in &doctests { @@ -371,12 +370,9 @@ fn scrape_test_config( attrs: &[hir::Attribute], args_file: PathBuf, ) -> GlobalTestOptions { - use rustc_ast_pretty::pprust; - let mut opts = GlobalTestOptions { crate_name, no_crate_inject: false, - attrs: Vec::new(), insert_indent_space: false, args_file, }; @@ -393,13 +389,7 @@ fn scrape_test_config( if attr.has_name(sym::no_crate_inject) { opts.no_crate_inject = true; } - if attr.has_name(sym::attr) - && let Some(l) = attr.meta_item_list() - { - for item in l { - opts.attrs.push(pprust::meta_list_item_to_string(item)); - } - } + // NOTE: `test(attr(..))` is handled when discovering the individual tests } opts @@ -848,6 +838,7 @@ pub(crate) struct ScrapedDocTest { text: String, name: String, span: Span, + global_crate_attrs: Vec, } impl ScrapedDocTest { @@ -858,6 +849,7 @@ impl ScrapedDocTest { langstr: LangString, text: String, span: Span, + global_crate_attrs: Vec, ) -> Self { let mut item_path = logical_path.join("::"); item_path.retain(|c| c != ' '); @@ -867,7 +859,7 @@ impl ScrapedDocTest { let name = format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionaly()); - Self { filename, line, langstr, text, name, span } + Self { filename, line, langstr, text, name, span, global_crate_attrs } } fn edition(&self, opts: &RustdocOptions) -> Edition { self.langstr.edition.unwrap_or(opts.edition) @@ -896,9 +888,15 @@ pub(crate) trait DocTestVisitor { fn visit_header(&mut self, _name: &str, _level: u32) {} } +#[derive(Clone, Debug, Hash, Eq, PartialEq)] +pub(crate) struct MergeableTestKey { + edition: Edition, + global_crate_attrs_hash: u64, +} + struct CreateRunnableDocTests { standalone_tests: Vec, - mergeable_tests: FxIndexMap>, + mergeable_tests: FxIndexMap>, rustdoc_options: Arc, opts: GlobalTestOptions, @@ -949,6 +947,7 @@ impl CreateRunnableDocTests { let edition = scraped_test.edition(&self.rustdoc_options); let doctest = BuildDocTestBuilder::new(&scraped_test.text) .crate_name(&self.opts.crate_name) + .global_crate_attrs(scraped_test.global_crate_attrs.clone()) .edition(edition) .can_merge_doctests(self.can_merge_doctests) .test_id(test_id) @@ -965,7 +964,17 @@ impl CreateRunnableDocTests { let test_desc = self.generate_test_desc_and_fn(doctest, scraped_test); self.standalone_tests.push(test_desc); } else { - self.mergeable_tests.entry(edition).or_default().push((doctest, scraped_test)); + self.mergeable_tests + .entry(MergeableTestKey { + edition, + global_crate_attrs_hash: { + let mut hasher = FxHasher::default(); + scraped_test.global_crate_attrs.hash(&mut hasher); + hasher.finish() + }, + }) + .or_default() + .push((doctest, scraped_test)); } } diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs index 3b17ccc78c712..ebe6bfd22ba10 100644 --- a/src/librustdoc/doctest/extracted.rs +++ b/src/librustdoc/doctest/extracted.rs @@ -35,13 +35,16 @@ impl ExtractedDocTests { ) { let edition = scraped_test.edition(options); - let ScrapedDocTest { filename, line, langstr, text, name, .. } = scraped_test; + let ScrapedDocTest { filename, line, langstr, text, name, global_crate_attrs, .. } = + scraped_test; let doctest = BuildDocTestBuilder::new(&text) .crate_name(&opts.crate_name) + .global_crate_attrs(global_crate_attrs) .edition(edition) .lang_str(&langstr) .build(None); + let (full_test_code, size) = doctest.generate_unique_doctest( &text, langstr.test_harness, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 66647b880186d..5e571613d6ff6 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -45,6 +45,7 @@ pub(crate) struct BuildDocTestBuilder<'a> { test_id: Option, lang_str: Option<&'a LangString>, span: Span, + global_crate_attrs: Vec, } impl<'a> BuildDocTestBuilder<'a> { @@ -57,6 +58,7 @@ impl<'a> BuildDocTestBuilder<'a> { test_id: None, lang_str: None, span: DUMMY_SP, + global_crate_attrs: Vec::new(), } } @@ -96,6 +98,12 @@ impl<'a> BuildDocTestBuilder<'a> { self } + #[inline] + pub(crate) fn global_crate_attrs(mut self, global_crate_attrs: Vec) -> Self { + self.global_crate_attrs = global_crate_attrs; + self + } + pub(crate) fn build(self, dcx: Option>) -> DocTestBuilder { let BuildDocTestBuilder { source, @@ -106,6 +114,7 @@ impl<'a> BuildDocTestBuilder<'a> { test_id, lang_str, span, + global_crate_attrs, } = self; let can_merge_doctests = can_merge_doctests && lang_str.is_some_and(|lang_str| { @@ -133,6 +142,7 @@ impl<'a> BuildDocTestBuilder<'a> { // If the AST returned an error, we don't want this doctest to be merged with the // others. return DocTestBuilder::invalid( + Vec::new(), String::new(), String::new(), String::new(), @@ -155,6 +165,7 @@ impl<'a> BuildDocTestBuilder<'a> { DocTestBuilder { supports_color, has_main_fn, + global_crate_attrs, crate_attrs, maybe_crate_attrs, crates, @@ -173,6 +184,7 @@ pub(crate) struct DocTestBuilder { pub(crate) supports_color: bool, pub(crate) already_has_extern_crate: bool, pub(crate) has_main_fn: bool, + pub(crate) global_crate_attrs: Vec, pub(crate) crate_attrs: String, /// If this is a merged doctest, it will be put into `everything_else`, otherwise it will /// put into `crate_attrs`. @@ -186,6 +198,7 @@ pub(crate) struct DocTestBuilder { impl DocTestBuilder { fn invalid( + global_crate_attrs: Vec, crate_attrs: String, maybe_crate_attrs: String, crates: String, @@ -195,6 +208,7 @@ impl DocTestBuilder { Self { supports_color: false, has_main_fn: false, + global_crate_attrs, crate_attrs, maybe_crate_attrs, crates, @@ -224,7 +238,8 @@ impl DocTestBuilder { let mut line_offset = 0; let mut prog = String::new(); let everything_else = self.everything_else.trim(); - if opts.attrs.is_empty() { + + if self.global_crate_attrs.is_empty() { // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some // lints that are commonly triggered in doctests. The crate-level test attributes are // commonly used to make tests fail in case they trigger warnings, so having this there in @@ -233,8 +248,8 @@ impl DocTestBuilder { line_offset += 1; } - // Next, any attributes that came from the crate root via #![doc(test(attr(...)))]. - for attr in &opts.attrs { + // Next, any attributes that came from #![doc(test(attr(...)))]. + for attr in &self.global_crate_attrs { prog.push_str(&format!("#![{attr}]\n")); line_offset += 1; } diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs index e358a7e44e515..7f26605f2562c 100644 --- a/src/librustdoc/doctest/markdown.rs +++ b/src/librustdoc/doctest/markdown.rs @@ -31,6 +31,7 @@ impl DocTestVisitor for MdCollector { config, test, DUMMY_SP, + Vec::new(), )); } @@ -96,7 +97,6 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> { crate_name, no_crate_inject: true, insert_indent_space: false, - attrs: vec![], args_file, }; diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 39a4f23560a7e..f0914474c7934 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -12,6 +12,7 @@ use crate::html::markdown::{Ignore, LangString}; /// Convenient type to merge compatible doctests into one. pub(crate) struct DocTestRunner { crate_attrs: FxIndexSet, + global_crate_attrs: FxIndexSet, ids: String, output: String, output_merged_tests: String, @@ -23,6 +24,7 @@ impl DocTestRunner { pub(crate) fn new() -> Self { Self { crate_attrs: FxIndexSet::default(), + global_crate_attrs: FxIndexSet::default(), ids: String::new(), output: String::new(), output_merged_tests: String::new(), @@ -46,6 +48,9 @@ impl DocTestRunner { for line in doctest.crate_attrs.split('\n') { self.crate_attrs.insert(line.to_string()); } + for line in &doctest.global_crate_attrs { + self.global_crate_attrs.insert(line.to_string()); + } } self.ids.push_str(&format!( "tests.push({}::TEST);\n", @@ -85,7 +90,7 @@ impl DocTestRunner { code_prefix.push('\n'); } - if opts.attrs.is_empty() { + if self.global_crate_attrs.is_empty() { // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some // lints that are commonly triggered in doctests. The crate-level test attributes are // commonly used to make tests fail in case they trigger warnings, so having this there in @@ -93,8 +98,8 @@ impl DocTestRunner { code_prefix.push_str("#![allow(unused)]\n"); } - // Next, any attributes that came from the crate root via #![doc(test(attr(...)))]. - for attr in &opts.attrs { + // Next, any attributes that came from #![doc(test(attr(...)))]. + for attr in &self.global_crate_attrs { code_prefix.push_str(&format!("#![{attr}]\n")); } diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index f9d2aa3d3b4bd..96975105ac507 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -4,6 +4,7 @@ use std::cell::Cell; use std::env; use std::sync::Arc; +use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, intravisit}; @@ -11,7 +12,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_resolve::rustdoc::span_of_fragments; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span}; +use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span, sym}; use super::{DocTestVisitor, ScrapedDocTest}; use crate::clean::{Attributes, extract_cfg_from_attrs}; @@ -22,6 +23,7 @@ struct RustCollector { tests: Vec, cur_path: Vec, position: Span, + global_crate_attrs: Vec, } impl RustCollector { @@ -75,6 +77,7 @@ impl DocTestVisitor for RustCollector { config, test, span, + self.global_crate_attrs.clone(), )); } @@ -94,6 +97,7 @@ impl<'tcx> HirCollector<'tcx> { cur_path: vec![], position: DUMMY_SP, tests: vec![], + global_crate_attrs: Vec::new(), }; Self { codes, tcx, collector } } @@ -123,6 +127,26 @@ impl HirCollector<'_> { return; } + // Try collecting `#[doc(test(attr(...)))]` + let old_global_crate_attrs_len = self.collector.global_crate_attrs.len(); + for doc_test_attrs in ast_attrs + .iter() + .filter(|a| a.has_name(sym::doc)) + .flat_map(|a| a.meta_item_list().unwrap_or_default()) + .filter(|a| a.has_name(sym::test)) + { + let Some(doc_test_attrs) = doc_test_attrs.meta_item_list() else { continue }; + for attr in doc_test_attrs + .iter() + .filter(|a| a.has_name(sym::attr)) + .flat_map(|a| a.meta_item_list().unwrap_or_default()) + .map(|i| pprust::meta_list_item_to_string(i)) + { + // Add the additional attributes to the global_crate_attrs vector + self.collector.global_crate_attrs.push(attr); + } + } + let mut has_name = false; if let Some(name) = name { self.collector.cur_path.push(name); @@ -157,6 +181,9 @@ impl HirCollector<'_> { nested(self); + // Restore global_crate_attrs to it's previous size/content + self.collector.global_crate_attrs.truncate(old_global_crate_attrs_len); + if has_name { self.collector.cur_path.pop(); } diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 08248fdf39bbe..ce2984ced7904 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -7,9 +7,11 @@ fn make_test( crate_name: Option<&str>, dont_insert_main: bool, opts: &GlobalTestOptions, + global_crate_attrs: Vec<&str>, test_id: Option<&str>, ) -> (String, usize) { - let mut builder = BuildDocTestBuilder::new(test_code); + let mut builder = BuildDocTestBuilder::new(test_code) + .global_crate_attrs(global_crate_attrs.into_iter().map(|a| a.to_string()).collect()); if let Some(crate_name) = crate_name { builder = builder.crate_name(crate_name); } @@ -28,7 +30,6 @@ fn default_global_opts(crate_name: impl Into) -> GlobalTestOptions { crate_name: crate_name.into(), no_crate_inject: false, insert_indent_space: false, - attrs: vec![], args_file: PathBuf::new(), } } @@ -43,7 +44,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -58,7 +59,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -77,7 +78,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 3)); } @@ -94,7 +95,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -112,7 +113,7 @@ use std::*; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("std"), false, &opts, None); + let (output, len) = make_test(input, Some("std"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -131,7 +132,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -148,7 +149,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -156,8 +157,7 @@ assert_eq!(2+2, 4); fn make_test_opts_attrs() { // If you supplied some doctest attributes with `#![doc(test(attr(...)))]`, it will use // those instead of the stock `#![allow(unused)]`. - let mut opts = default_global_opts("asdf"); - opts.attrs.push("feature(sick_rad)".to_string()); + let opts = default_global_opts("asdf"); let input = "use asdf::qwop; assert_eq!(2+2, 4);"; let expected = "#![feature(sick_rad)] @@ -168,11 +168,10 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = + make_test(input, Some("asdf"), false, &opts, vec!["feature(sick_rad)"], None); assert_eq!((output, len), (expected, 3)); - // Adding more will also bump the returned line offset. - opts.attrs.push("feature(hella_dope)".to_string()); let expected = "#![feature(sick_rad)] #![feature(hella_dope)] #[allow(unused_extern_crates)] @@ -182,7 +181,18 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test( + input, + Some("asdf"), + false, + &opts, + vec![ + "feature(sick_rad)", + // Adding more will also bump the returned line offset. + "feature(hella_dope)", + ], + None, + ); assert_eq!((output, len), (expected, 4)); } @@ -200,7 +210,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -216,7 +226,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -232,7 +242,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -246,7 +256,7 @@ assert_eq!(2+2, 4);"; //Ceci n'est pas une `fn main` assert_eq!(2+2, 4);" .to_string(); - let (output, len) = make_test(input, None, true, &opts, None); + let (output, len) = make_test(input, None, true, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -264,7 +274,7 @@ assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -284,7 +294,7 @@ assert_eq!(asdf::foo, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 3)); } @@ -302,7 +312,7 @@ test_wrapper! { }" .to_string(); - let (output, len) = make_test(input, Some("my_crate"), false, &opts, None); + let (output, len) = make_test(input, Some("my_crate"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -322,7 +332,7 @@ io::stdin().read_line(&mut input)?; Ok::<(), io:Error>(()) } _inner().unwrap() }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -336,7 +346,7 @@ fn main() { #[allow(non_snake_case)] fn _doctest_main__some_unique_name() { assert_eq!(2+2, 4); } _doctest_main__some_unique_name() }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, Some("_some_unique_name")); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), Some("_some_unique_name")); assert_eq!((output, len), (expected, 2)); } @@ -355,7 +365,7 @@ fn main() { eprintln!(\"hello anan\"); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -375,7 +385,7 @@ fn main() { eprintln!(\"hello anan\"); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -400,7 +410,7 @@ fn main() { }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); // And same, if there is a `main` function provided by the user, we ensure that it's @@ -420,7 +430,7 @@ fn main() {}"; fn main() {}" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -448,6 +458,6 @@ pub mod outer_module { } }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 68ba1245520de..d3701784f9dff 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -300,7 +300,6 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { crate_name: krate.map(String::from).unwrap_or_default(), no_crate_inject: false, insert_indent_space: true, - attrs: vec![], args_file: PathBuf::new(), }; let mut builder = doctest::BuildDocTestBuilder::new(&test).edition(edition); diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index f8209f2c8cd29..4c53ea42793cd 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -113,6 +113,8 @@ static TARGETS: &[&str] = &[ "i686-unknown-uefi", "loongarch64-unknown-linux-gnu", "loongarch64-unknown-linux-musl", + "loongarch32-unknown-none", + "loongarch32-unknown-none-softfloat", "loongarch64-unknown-none", "loongarch64-unknown-none-softfloat", "m68k-unknown-linux-gnu", diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 4f93b49874134..9b9d94bbead09 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -495,6 +495,7 @@ impl Config { "arm64ec", "riscv32", "riscv64", + "loongarch32", "loongarch64", "s390x", // These targets require an additional asm_experimental_arch feature. diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 5757e422ae21e..1406553c9ea7b 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -73,6 +73,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-linux", "ignore-lldb", "ignore-llvm-version", + "ignore-loongarch32", "ignore-loongarch64", "ignore-macabi", "ignore-macos", @@ -196,6 +197,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-i686-unknown-linux-gnu", "only-ios", "only-linux", + "only-loongarch32", "only-loongarch64", "only-loongarch64-unknown-linux-gnu", "only-macos", diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index a4882a201481c..9957e351ff105 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -3,17 +3,20 @@ mod atomic; mod simd; +use std::ops::Neg; + use rand::Rng; use rustc_abi::Size; -use rustc_apfloat::{Float, Round}; +use rustc_apfloat::ieee::{IeeeFloat, Semantics}; +use rustc_apfloat::{self, Float, Round}; use rustc_middle::mir; -use rustc_middle::ty::{self, FloatTy}; +use rustc_middle::ty::{self, FloatTy, ScalarInt}; use rustc_span::{Symbol, sym}; use self::atomic::EvalContextExt as _; use self::helpers::{ToHost, ToSoft, check_intrinsic_arg_count}; use self::simd::EvalContextExt as _; -use crate::math::apply_random_float_error_to_imm; +use crate::math::{IeeeExt, apply_random_float_error_ulp}; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -187,31 +190,39 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { => { let [f] = check_intrinsic_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; - // Using host floats (but it's fine, these operations do not have - // guaranteed precision). - let host = f.to_host(); - let res = match intrinsic_name { - "sinf32" => host.sin(), - "cosf32" => host.cos(), - "expf32" => host.exp(), - "exp2f32" => host.exp2(), - "logf32" => host.ln(), - "log10f32" => host.log10(), - "log2f32" => host.log2(), - _ => bug!(), - }; - let res = res.to_soft(); - // Apply a relative error of 16ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - // FIXME: temporarily disabled as it breaks std tests. - // let res = apply_random_float_error_ulp( - // this, - // res, - // 4, // log2(16) - // ); + + let res = fixed_float_value(intrinsic_name, &[f]).unwrap_or_else(||{ + // Using host floats (but it's fine, these operations do not have + // guaranteed precision). + let host = f.to_host(); + let res = match intrinsic_name { + "sinf32" => host.sin(), + "cosf32" => host.cos(), + "expf32" => host.exp(), + "exp2f32" => host.exp2(), + "logf32" => host.ln(), + "log10f32" => host.log10(), + "log2f32" => host.log2(), + _ => bug!(), + }; + let res = res.to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = apply_random_float_error_ulp( + this, + res, + 2, // log2(4) + ); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + clamp_float_value(intrinsic_name, res) + }); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; } + #[rustfmt::skip] | "sinf64" | "cosf64" @@ -223,28 +234,35 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { => { let [f] = check_intrinsic_arg_count(args)?; let f = this.read_scalar(f)?.to_f64()?; - // Using host floats (but it's fine, these operations do not have - // guaranteed precision). - let host = f.to_host(); - let res = match intrinsic_name { - "sinf64" => host.sin(), - "cosf64" => host.cos(), - "expf64" => host.exp(), - "exp2f64" => host.exp2(), - "logf64" => host.ln(), - "log10f64" => host.log10(), - "log2f64" => host.log2(), - _ => bug!(), - }; - let res = res.to_soft(); - // Apply a relative error of 16ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - // FIXME: temporarily disabled as it breaks std tests. - // let res = apply_random_float_error_ulp( - // this, - // res, - // 4, // log2(16) - // ); + + let res = fixed_float_value(intrinsic_name, &[f]).unwrap_or_else(||{ + // Using host floats (but it's fine, these operations do not have + // guaranteed precision). + let host = f.to_host(); + let res = match intrinsic_name { + "sinf64" => host.sin(), + "cosf64" => host.cos(), + "expf64" => host.exp(), + "exp2f64" => host.exp2(), + "logf64" => host.ln(), + "log10f64" => host.log10(), + "log2f64" => host.log2(), + _ => bug!(), + }; + let res = res.to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = apply_random_float_error_ulp( + this, + res, + 2, // log2(4) + ); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + clamp_float_value(intrinsic_name, res) + }); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; } @@ -302,43 +320,75 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "powf32" => { - // FIXME: apply random relative error but without altering behaviour of powf let [f1, f2] = check_intrinsic_arg_count(args)?; let f1 = this.read_scalar(f1)?.to_f32()?; let f2 = this.read_scalar(f2)?.to_f32()?; - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f1.to_host().powf(f2.to_host()).to_soft(); + + let res = fixed_float_value(intrinsic_name, &[f1, f2]).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f1.to_host().powf(f2.to_host()).to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + apply_random_float_error_ulp( + this, res, 2, // log2(4) + ) + }); let res = this.adjust_nan(res, &[f1, f2]); this.write_scalar(res, dest)?; } "powf64" => { - // FIXME: apply random relative error but without altering behaviour of powf let [f1, f2] = check_intrinsic_arg_count(args)?; let f1 = this.read_scalar(f1)?.to_f64()?; let f2 = this.read_scalar(f2)?.to_f64()?; - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f1.to_host().powf(f2.to_host()).to_soft(); + + let res = fixed_float_value(intrinsic_name, &[f1, f2]).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f1.to_host().powf(f2.to_host()).to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + apply_random_float_error_ulp( + this, res, 2, // log2(4) + ) + }); let res = this.adjust_nan(res, &[f1, f2]); this.write_scalar(res, dest)?; } "powif32" => { - // FIXME: apply random relative error but without altering behaviour of powi let [f, i] = check_intrinsic_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; let i = this.read_scalar(i)?.to_i32()?; - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f.to_host().powi(i).to_soft(); + + let res = fixed_powi_float_value(f, i).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f.to_host().powi(i).to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + apply_random_float_error_ulp( + this, res, 2, // log2(4) + ) + }); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; } "powif64" => { - // FIXME: apply random relative error but without altering behaviour of powi let [f, i] = check_intrinsic_arg_count(args)?; let f = this.read_scalar(f)?.to_f64()?; let i = this.read_scalar(i)?.to_i32()?; - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f.to_host().powi(i).to_soft(); + + let res = fixed_powi_float_value(f, i).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f.to_host().powi(i).to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + apply_random_float_error_ulp( + this, res, 2, // log2(4) + ) + }); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; } @@ -425,3 +475,97 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(EmulateItemResult::NeedsReturn) } } + +/// Applies a random ULP floating point error to `val` and returns the new value. +/// So if you want an X ULP error, `ulp_exponent` should be log2(X). +/// +/// Will fail if `val` is not a floating point number. +fn apply_random_float_error_to_imm<'tcx>( + ecx: &mut MiriInterpCx<'tcx>, + val: ImmTy<'tcx>, + ulp_exponent: u32, +) -> InterpResult<'tcx, ImmTy<'tcx>> { + let scalar = val.to_scalar_int()?; + let res: ScalarInt = match val.layout.ty.kind() { + ty::Float(FloatTy::F16) => + apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(), + ty::Float(FloatTy::F32) => + apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(), + ty::Float(FloatTy::F64) => + apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(), + ty::Float(FloatTy::F128) => + apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(), + _ => bug!("intrinsic called with non-float input type"), + }; + + interp_ok(ImmTy::from_scalar_int(res, val.layout)) +} + +/// For the intrinsics: +/// - sinf32, sinf64 +/// - cosf32, cosf64 +/// - expf32, expf64, exp2f32, exp2f64 +/// - logf32, logf64, log2f32, log2f64, log10f32, log10f64 +/// - powf32, powf64 +/// +/// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard +/// (specifically, C23 annex F.10) when given `args` as arguments. Outputs that are unaffected by a relative error +/// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying +/// implementation. Returns `None` if no specific value is guaranteed. +fn fixed_float_value( + intrinsic_name: &str, + args: &[IeeeFloat], +) -> Option> { + let one = IeeeFloat::::one(); + match (intrinsic_name, args) { + // cos(+- 0) = 1 + ("cosf32" | "cosf64", [input]) if input.is_zero() => Some(one), + + // e^0 = 1 + ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => Some(one), + + // 1^y = 1 for any y, even a NaN. + ("powf32" | "powf64", [base, _]) if *base == one => Some(one), + + // (-1)^(±INF) = 1 + ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => Some(one), + + // FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate + // the NaN. We should return either 1 or the NaN non-deterministically here. + // But for now, just handle them all the same. + // x^(±0) = 1 for any x, even a NaN + ("powf32" | "powf64", [_, exp]) if exp.is_zero() => Some(one), + + // There are a lot of cases for fixed outputs according to the C Standard, but these are mainly INF or zero + // which are not affected by the applied error. + _ => None, + } +} + +/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the C standard +/// (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`. +fn fixed_powi_float_value(base: IeeeFloat, exp: i32) -> Option> { + match (base.category(), exp) { + // x^0 = 1, if x is not a Signaling NaN + // FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate + // the NaN. We should return either 1 or the NaN non-deterministically here. + // But for now, just handle them all the same. + (_, 0) => Some(IeeeFloat::::one()), + + _ => None, + } +} + +/// Given an floating-point operation and a floating-point value, clamps the result to the output +/// range of the given operation. +fn clamp_float_value(intrinsic_name: &str, val: IeeeFloat) -> IeeeFloat { + match intrinsic_name { + // sin and cos: [-1, 1] + "sinf32" | "cosf32" | "sinf64" | "cosf64" => + val.clamp(IeeeFloat::::one().neg(), IeeeFloat::::one()), + // exp: [0, +INF] + "expf32" | "exp2f32" | "expf64" | "exp2f64" => + IeeeFloat::::maximum(val, IeeeFloat::::ZERO), + _ => val, + } +} diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index 2ff29c7ac1aad..d1355a2168470 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -151,6 +151,20 @@ pub(crate) fn sqrt(x: IeeeFloat) -> IeeeFl } } +/// Extend functionality of rustc_apfloat softfloats +pub trait IeeeExt: rustc_apfloat::Float { + #[inline] + fn one() -> Self { + Self::from_u128(1).value + } + + #[inline] + fn clamp(self, min: Self, max: Self) -> Self { + self.maximum(min).minimum(max) + } +} +impl IeeeExt for IeeeFloat {} + #[cfg(test)] mod tests { use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS}; diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index 323b95d5f5f23..d7bb16f0858d8 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -13,10 +13,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // alignment requirement and size less than or equal to the size requested." // So first we need to figure out what the limits are for "fundamental alignment". // This is given by `alignof(max_align_t)`. The following list is taken from - // `library/std/src/sys/pal/common/alloc.rs` (where this is called `MIN_ALIGN`) and should + // `library/std/src/sys/alloc/mod.rs` (where this is called `MIN_ALIGN`) and should // be kept in sync. let max_fundamental_align = match this.tcx.sess.target.arch.as_ref() { - "x86" | "arm" | "mips" | "mips32r6" | "powerpc" | "powerpc64" | "wasm32" => 8, + "x86" | "arm" | "loongarch32" | "mips" | "mips32r6" | "powerpc" | "powerpc64" + | "wasm32" => 8, "x86_64" | "aarch64" | "mips64" | "mips64r6" | "s390x" | "sparc64" | "loongarch64" => 16, arch => bug!("unsupported target architecture for malloc: `{}`", arch), diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index 2feed5a835228..a2ea3dbd88b11 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -45,10 +45,6 @@ impl<'tcx> MiriMachine<'tcx> { /// Sets up the "extern statics" for this machine. pub fn init_extern_statics(ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> { - // "__rust_no_alloc_shim_is_unstable" - let val = ImmTy::from_int(0, ecx.machine.layouts.u8); // always 0, value does not matter - Self::alloc_extern_static(ecx, "__rust_no_alloc_shim_is_unstable", val)?; - // "__rust_alloc_error_handler_should_panic" let val = ecx.tcx.sess.opts.unstable_opts.oom.should_panic(); let val = ImmTy::from_int(val, ecx.machine.layouts.u8); diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index ae04ca018ab29..5d163828b051d 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -611,6 +611,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(new_ptr, dest) }); } + name if name == this.mangle_internal_symbol("__rust_no_alloc_shim_is_unstable_v2") => { + // This is a no-op shim that only exists to prevent making the allocator shims instantly stable. + let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; + } // C memory handling functions "memcmp" => { diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 98a88cfd62dc8..7ce0bc88517e1 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -45,6 +45,31 @@ macro_rules! assert_approx_eq { }; } + +/// From IEEE 754 a Signaling NaN for single precision has the following representation: +/// ``` +/// s | 1111 1111 | 0x..x +/// ```` +/// Were at least one `x` is a 1. +/// +/// This sNaN has the following representation and is used for testing purposes.: +/// ``` +/// 0 | 1111111 | 01..0 +/// ``` +const SNAN_F32: f32 = f32::from_bits(0x7fa00000); + +/// From IEEE 754 a Signaling NaN for double precision has the following representation: +/// ``` +/// s | 1111 1111 111 | 0x..x +/// ```` +/// Were at least one `x` is a 1. +/// +/// This sNaN has the following representation and is used for testing purposes.: +/// ``` +/// 0 | 1111 1111 111 | 01..0 +/// ``` +const SNAN_F64: f64 = f64::from_bits(0x7ff4000000000000); + fn main() { basic(); casts(); @@ -1008,17 +1033,84 @@ pub fn libm() { assert_approx_eq!(25f32.powf(-2f32), 0.0016f32); assert_approx_eq!(400f64.powf(0.5f64), 20f64); + // Some inputs to powf and powi result in fixed outputs + // and thus must be exactly equal to that value. + // C standard says: + // 1^y = 1 for any y, even a NaN. + assert_eq!(1f32.powf(10.0), 1.0); + assert_eq!(1f64.powf(100.0), 1.0); + assert_eq!(1f32.powf(f32::INFINITY), 1.0); + assert_eq!(1f64.powf(f64::INFINITY), 1.0); + assert_eq!(1f32.powf(f32::NAN), 1.0); + assert_eq!(1f64.powf(f64::NAN), 1.0); + + // f*::NAN is a quiet NAN and should return 1 as well. + assert_eq!(f32::NAN.powf(0.0), 1.0); + assert_eq!(f64::NAN.powf(0.0), 1.0); + + assert_eq!(42f32.powf(0.0), 1.0); + assert_eq!(42f64.powf(0.0), 1.0); + assert_eq!(f32::INFINITY.powf(0.0), 1.0); + assert_eq!(f64::INFINITY.powf(0.0), 1.0); + + // f*::NAN is a quiet NAN and should return 1 as well. + assert_eq!(f32::NAN.powi(0), 1.0); + assert_eq!(f64::NAN.powi(0), 1.0); + + assert_eq!(10.0f32.powi(0), 1.0); + assert_eq!(10.0f64.powi(0), 1.0); + assert_eq!(f32::INFINITY.powi(0), 1.0); + assert_eq!(f64::INFINITY.powi(0), 1.0); + + assert_eq!((-1f32).powf(f32::INFINITY), 1.0); + assert_eq!((-1f64).powf(f64::INFINITY), 1.0); + assert_eq!((-1f32).powf(f32::NEG_INFINITY), 1.0); + assert_eq!((-1f64).powf(f64::NEG_INFINITY), 1.0); + + // For pow (powf in rust) the C standard says: + // x^0 = 1 for all x even a sNaN + // FIXME(#4286): this does not match the behavior of all implementations. + assert_eq!(SNAN_F32.powf(0.0), 1.0); + assert_eq!(SNAN_F64.powf(0.0), 1.0); + + // For pown (powi in rust) the C standard says: + // x^0 = 1 for all x even a sNaN + // FIXME(#4286): this does not match the behavior of all implementations. + assert_eq!(SNAN_F32.powi(0), 1.0); + assert_eq!(SNAN_F64.powi(0), 1.0); + + assert_eq!(0f32.powi(10), 0.0); + assert_eq!(0f64.powi(100), 0.0); + assert_eq!(0f32.powi(9), 0.0); + assert_eq!(0f64.powi(99), 0.0); + + assert_biteq((-0f32).powf(10.0), 0.0, "-0^x = +0 where x is positive"); + assert_biteq((-0f64).powf(100.0), 0.0, "-0^x = +0 where x is positive"); + assert_biteq((-0f32).powf(9.0), -0.0, "-0^x = -0 where x is negative"); + assert_biteq((-0f64).powf(99.0), -0.0, "-0^x = -0 where x is negative"); + + assert_biteq((-0f32).powi(10), 0.0, "-0^x = +0 where x is positive"); + assert_biteq((-0f64).powi(100), 0.0, "-0^x = +0 where x is positive"); + assert_biteq((-0f32).powi(9), -0.0, "-0^x = -0 where x is negative"); + assert_biteq((-0f64).powi(99), -0.0, "-0^x = -0 where x is negative"); + assert_approx_eq!(1f32.exp(), f32::consts::E); assert_approx_eq!(1f64.exp(), f64::consts::E); + assert_eq!(0f32.exp(), 1.0); + assert_eq!(0f64.exp(), 1.0); assert_approx_eq!(1f32.exp_m1(), f32::consts::E - 1.0); assert_approx_eq!(1f64.exp_m1(), f64::consts::E - 1.0); assert_approx_eq!(10f32.exp2(), 1024f32); assert_approx_eq!(50f64.exp2(), 1125899906842624f64); + assert_eq!(0f32.exp2(), 1.0); + assert_eq!(0f64.exp2(), 1.0); assert_approx_eq!(f32::consts::E.ln(), 1f32); - assert_approx_eq!(1f64.ln(), 0f64); + assert_approx_eq!(f64::consts::E.ln(), 1f64); + assert_eq!(1f32.ln(), 0.0); + assert_eq!(1f64.ln(), 0.0); assert_approx_eq!(0f32.ln_1p(), 0f32); assert_approx_eq!(0f64.ln_1p(), 0f64); @@ -1047,7 +1139,8 @@ pub fn libm() { // Trigonometric functions. - assert_approx_eq!(0f32.sin(), 0f32); + assert_eq!(0f32.sin(), 0f32); + assert_eq!(0f64.sin(), 0f64); assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64); assert_approx_eq!(f32::consts::FRAC_PI_6.sin(), 0.5); assert_approx_eq!(f64::consts::FRAC_PI_6.sin(), 0.5); @@ -1059,7 +1152,23 @@ pub fn libm() { assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); - assert_approx_eq!(0f32.cos(), 1f32); + // Ensure `sin` always returns something that is a valid input for `asin`, and same for + // `cos` and `acos`. + let halve_pi_f32 = std::f32::consts::FRAC_PI_2; + let halve_pi_f64 = std::f64::consts::FRAC_PI_2; + let pi_f32 = std::f32::consts::PI; + let pi_f64 = std::f64::consts::PI; + for _ in 0..64 { + // sin() should be clamped to [-1, 1] so asin() can never return NaN + assert!(!halve_pi_f32.sin().asin().is_nan()); + assert!(!halve_pi_f64.sin().asin().is_nan()); + // cos() should be clamped to [-1, 1] so acos() can never return NaN + assert!(!pi_f32.cos().acos().is_nan()); + assert!(!pi_f64.cos().acos().is_nan()); + } + + assert_eq!(0f32.cos(), 1f32); + assert_eq!(0f64.cos(), 1f64); assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64); assert_approx_eq!(f32::consts::FRAC_PI_3.cos(), 0.5); assert_approx_eq!(f64::consts::FRAC_PI_3.cos(), 0.5); diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 3255591119498..edf16548e7de0 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -259,6 +259,12 @@ //@ revisions: i686_wrs_vxworks //@ [i686_wrs_vxworks] compile-flags: --target i686-wrs-vxworks //@ [i686_wrs_vxworks] needs-llvm-components: x86 +//@ revisions: loongarch32_unknown_none +//@ [loongarch32_unknown_none] compile-flags: --target loongarch32-unknown-none +//@ [loongarch32_unknown_none] needs-llvm-components: loongarch +//@ revisions: loongarch32_unknown_none_softfloat +//@ [loongarch32_unknown_none_softfloat] compile-flags: --target loongarch32-unknown-none-softfloat +//@ [loongarch32_unknown_none_softfloat] needs-llvm-components: loongarch //@ revisions: loongarch64_unknown_linux_gnu //@ [loongarch64_unknown_linux_gnu] compile-flags: --target loongarch64-unknown-linux-gnu //@ [loongarch64_unknown_linux_gnu] needs-llvm-components: loongarch diff --git a/tests/codegen/alloc-optimisation.rs b/tests/codegen/alloc-optimisation.rs index 19f14647c1d7d..3735860d510fb 100644 --- a/tests/codegen/alloc-optimisation.rs +++ b/tests/codegen/alloc-optimisation.rs @@ -5,7 +5,8 @@ pub fn alloc_test(data: u32) { // CHECK-LABEL: @alloc_test // CHECK-NEXT: start: - // CHECK-NEXT: {{.*}} load volatile i8, ptr @{{.*}}__rust_no_alloc_shim_is_unstable, align 1 + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() // CHECK-NEXT: ret void let x = Box::new(data); drop(x); diff --git a/tests/codegen/unwind-landingpad-inline.rs b/tests/codegen/unwind-landingpad-inline.rs index 920774b340240..1cf606279e623 100644 --- a/tests/codegen/unwind-landingpad-inline.rs +++ b/tests/codegen/unwind-landingpad-inline.rs @@ -10,8 +10,10 @@ // See https://github.com/rust-lang/rust/issues/46515 // CHECK-LABEL: @check_no_escape_in_landingpad // CHECK: start: -// CHECK-NEXT: __rust_no_alloc_shim_is_unstable -// CHECK-NEXT: __rust_no_alloc_shim_is_unstable +// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 +// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM:_R.+__rust_no_alloc_shim_is_unstable_v2]]() +// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 +// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM]]() // CHECK-NEXT: ret void #[no_mangle] pub fn check_no_escape_in_landingpad(f: fn()) { diff --git a/tests/codegen/vec-iter-collect-len.rs b/tests/codegen/vec-iter-collect-len.rs index a88573522d4d8..807548ef883f5 100644 --- a/tests/codegen/vec-iter-collect-len.rs +++ b/tests/codegen/vec-iter-collect-len.rs @@ -4,7 +4,9 @@ #[no_mangle] pub fn get_len() -> usize { // CHECK-LABEL: @get_len - // CHECK-NOT: call - // CHECK-NOT: invoke + // CHECK-NEXT: start: + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() + // CHECK-NEXT: ret i{{[0-9]+}} 3 [1, 2, 3].iter().collect::>().len() } diff --git a/tests/codegen/vec-optimizes-away.rs b/tests/codegen/vec-optimizes-away.rs index f6ed2898bdaaa..93b55454b108c 100644 --- a/tests/codegen/vec-optimizes-away.rs +++ b/tests/codegen/vec-optimizes-away.rs @@ -5,7 +5,8 @@ pub fn sum_me() -> i32 { // CHECK-LABEL: @sum_me // CHECK-NEXT: {{^.*:$}} - // CHECK-NEXT: {{.*}} load volatile i8, ptr @{{.*}}__rust_no_alloc_shim_is_unstable, align 1 + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() // CHECK-NEXT: ret i32 6 vec![1, 2, 3].iter().sum::() } diff --git a/tests/run-make/doctests-keep-binaries-2024/rmake.rs b/tests/run-make/doctests-keep-binaries-2024/rmake.rs index 3e8ffcbf24457..97324e1dcbc8e 100644 --- a/tests/run-make/doctests-keep-binaries-2024/rmake.rs +++ b/tests/run-make/doctests-keep-binaries-2024/rmake.rs @@ -16,7 +16,22 @@ fn setup_test_env(callback: F) { } fn check_generated_binaries() { - run("doctests/merged_doctest_2024/rust_out"); + let mut found_merged_doctest = false; + rfs::read_dir_entries("doctests/", |path| { + if path + .file_name() + .and_then(|name| name.to_str()) + .is_some_and(|name| name.starts_with("merged_doctest_2024")) + { + found_merged_doctest = true; + let rust_out = path.join("rust_out"); + let rust_out = rust_out.to_string_lossy(); + run(&*rust_out); + } + }); + if !found_merged_doctest { + panic!("no directory starting with `merged_doctest_2024` found under `doctests/`"); + } } fn main() { diff --git a/tests/run-make/no-alloc-shim/foo.rs b/tests/run-make/no-alloc-shim/foo.rs index 42606961f8bb2..b5d0d394d2b9f 100644 --- a/tests/run-make/no-alloc-shim/foo.rs +++ b/tests/run-make/no-alloc-shim/foo.rs @@ -1,4 +1,4 @@ -#![feature(default_alloc_error_handler)] +#![feature(rustc_attrs)] #![no_std] #![no_main] @@ -31,8 +31,8 @@ unsafe impl GlobalAlloc for Alloc { } #[cfg(not(check_feature_gate))] -#[no_mangle] -static __rust_no_alloc_shim_is_unstable: u8 = 0; +#[rustc_std_internal_symbol] +fn __rust_no_alloc_shim_is_unstable_v2() {} #[no_mangle] extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const i8) -> i32 { diff --git a/tests/run-make/no-alloc-shim/rmake.rs b/tests/run-make/no-alloc-shim/rmake.rs index d61ef5de8c56c..47cabfc208c77 100644 --- a/tests/run-make/no-alloc-shim/rmake.rs +++ b/tests/run-make/no-alloc-shim/rmake.rs @@ -7,12 +7,6 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -//@ ignore-msvc -//FIXME(Oneirical): Getting this to work on MSVC requires passing libcmt.lib to CC, -// which is not trivial to do. -// Tracking issue: https://github.com/rust-lang/rust/issues/128602 -// Discussion: https://github.com/rust-lang/rust/pull/128407#discussion_r1702439172 - use run_make_support::{cc, has_extension, has_prefix, run, rustc, shallow_find_files}; fn main() { @@ -30,15 +24,28 @@ fn main() { has_prefix(path, "libcompiler_builtins") && has_extension(path, "rlib") }); + #[allow(unused_mut)] + let mut platform_args = Vec::::new(); + #[cfg(target_env = "msvc")] + { + platform_args.push("-MD".to_string()); + + // `/link` tells MSVC that the remaining arguments are linker options. + platform_args.push("/link".to_string()); + platform_args.push("vcruntime.lib".to_string()); + platform_args.push("msvcrt.lib".to_string()); + } + cc().input("foo.o") .out_exe("foo") + .args(&platform_args) .args(&alloc_libs) .args(&core_libs) .args(&compiler_builtins_libs) .run(); run("foo"); - // Check that linking without __rust_no_alloc_shim_is_unstable defined fails + // Check that linking without __rust_no_alloc_shim_is_unstable_v2 defined fails rustc() .input("foo.rs") .crate_type("bin") @@ -48,6 +55,7 @@ fn main() { .run(); cc().input("foo.o") .out_exe("foo") + .args(&platform_args) .args(&alloc_libs) .args(&core_libs) .args(&compiler_builtins_libs) diff --git a/tests/run-make/symbols-all-mangled/rmake.rs b/tests/run-make/symbols-all-mangled/rmake.rs index 79ddd06bb94be..2cf579758002a 100644 --- a/tests/run-make/symbols-all-mangled/rmake.rs +++ b/tests/run-make/symbols-all-mangled/rmake.rs @@ -35,10 +35,6 @@ fn symbols_check_archive(path: &str) { continue; // All compiler-builtins symbols must remain unmangled } - if name == "__rust_no_alloc_shim_is_unstable" { - continue; // FIXME remove exception once we mangle this symbol - } - if name.contains("rust_eh_personality") { continue; // Unfortunately LLVM doesn't allow us to mangle this symbol } @@ -75,10 +71,6 @@ fn symbols_check(path: &str) { continue; } - if name == "__rust_no_alloc_shim_is_unstable" { - continue; // FIXME remove exception once we mangle this symbol - } - if name.contains("rust_eh_personality") { continue; // Unfortunately LLVM doesn't allow us to mangle this symbol } diff --git a/tests/rustdoc-ui/doctest/dead-code-items.rs b/tests/rustdoc-ui/doctest/dead-code-items.rs new file mode 100644 index 0000000000000..015504cbcedbc --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-items.rs @@ -0,0 +1,116 @@ +// Same test as dead-code-module but with 2 doc(test(attr())) at different levels. + +//@ edition: 2024 +//@ compile-flags:--test --test-args=--test-threads=1 +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(deny(warnings))))] + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarning { fn no_deny_warnings(); } +/// ``` +static S: u32 = 5; + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// let unused_error = 5; +/// +/// fn dead_code_but_no_error() {} +/// ``` +const C: u32 = 5; + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarningAtA { fn no_deny_warnings(); } +/// ``` +struct A { + #[doc(test(attr(deny(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait DeadCodeInField {} + /// ``` + field: u32 +} + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarningAtU { fn no_deny_warnings(); } +/// ``` +union U { + #[doc(test(attr(deny(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait DeadCodeInUnionField {} + /// ``` + field: u32, + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeInUnionField {} + /// ``` + field2: u64, +} + +#[doc(test(attr(deny(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// let not_dead_code_but_unused = 5; +/// ``` +enum Enum { + #[doc(test(attr(allow(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeInVariant {} + /// + /// fn main() { let unused_in_variant = 5; } + /// ``` + Variant1, +} + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarningAtImplA { fn no_deny_warnings(); } +/// ``` +impl A { + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeInImplMethod {} + /// ``` + fn method() {} +} + +#[doc(test(attr(deny(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait StillDeadCodeAtMyTrait { } +/// ``` +trait MyTrait { + #[doc(test(attr(allow(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeAtImplFn {} + /// + /// fn main() { let unused_in_impl = 5; } + /// ``` + fn my_trait_fn(); +} diff --git a/tests/rustdoc-ui/doctest/dead-code-items.stdout b/tests/rustdoc-ui/doctest/dead-code-items.stdout new file mode 100644 index 0000000000000..4b9d8be94dd3c --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-items.stdout @@ -0,0 +1,146 @@ + +running 13 tests +test $DIR/dead-code-items.rs - A (line 32) - compile ... ok +test $DIR/dead-code-items.rs - A (line 88) - compile ... ok +test $DIR/dead-code-items.rs - A::field (line 39) - compile ... FAILED +test $DIR/dead-code-items.rs - A::method (line 94) - compile ... ok +test $DIR/dead-code-items.rs - C (line 22) - compile ... FAILED +test $DIR/dead-code-items.rs - Enum (line 70) - compile ... FAILED +test $DIR/dead-code-items.rs - Enum::Variant1 (line 77) - compile ... FAILED +test $DIR/dead-code-items.rs - MyTrait (line 103) - compile ... FAILED +test $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) - compile ... FAILED +test $DIR/dead-code-items.rs - S (line 14) - compile ... ok +test $DIR/dead-code-items.rs - U (line 48) - compile ... ok +test $DIR/dead-code-items.rs - U::field (line 55) - compile ... FAILED +test $DIR/dead-code-items.rs - U::field2 (line 61) - compile ... ok + +failures: + +---- $DIR/dead-code-items.rs - A::field (line 39) stdout ---- +error: trait `DeadCodeInField` is never used + --> $DIR/dead-code-items.rs:40:7 + | +LL | trait DeadCodeInField {} + | ^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:38:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - C (line 22) stdout ---- +error: unused variable: `unused_error` + --> $DIR/dead-code-items.rs:23:5 + | +LL | let unused_error = 5; + | ^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_error` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:20:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - Enum (line 70) stdout ---- +error: unused variable: `not_dead_code_but_unused` + --> $DIR/dead-code-items.rs:71:5 + | +LL | let not_dead_code_but_unused = 5; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_not_dead_code_but_unused` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:68:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - Enum::Variant1 (line 77) stdout ---- +error: unused variable: `unused_in_variant` + --> $DIR/dead-code-items.rs:80:17 + | +LL | fn main() { let unused_in_variant = 5; } + | ^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_in_variant` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:75:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - MyTrait (line 103) stdout ---- +error: trait `StillDeadCodeAtMyTrait` is never used + --> $DIR/dead-code-items.rs:104:7 + | +LL | trait StillDeadCodeAtMyTrait { } + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:102:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) stdout ---- +error: unused variable: `unused_in_impl` + --> $DIR/dead-code-items.rs:113:17 + | +LL | fn main() { let unused_in_impl = 5; } + | ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_in_impl` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:108:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - U::field (line 55) stdout ---- +error: trait `DeadCodeInUnionField` is never used + --> $DIR/dead-code-items.rs:56:7 + | +LL | trait DeadCodeInUnionField {} + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:54:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-items.rs - A::field (line 39) + $DIR/dead-code-items.rs - C (line 22) + $DIR/dead-code-items.rs - Enum (line 70) + $DIR/dead-code-items.rs - Enum::Variant1 (line 77) + $DIR/dead-code-items.rs - MyTrait (line 103) + $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) + $DIR/dead-code-items.rs - U::field (line 55) + +test result: FAILED. 6 passed; 7 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/dead-code-module-2.rs b/tests/rustdoc-ui/doctest/dead-code-module-2.rs new file mode 100644 index 0000000000000..de7b11b91ec57 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module-2.rs @@ -0,0 +1,27 @@ +// Same test as dead-code-module but with 2 doc(test(attr())) at different levels. + +//@ edition: 2024 +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(allow(unused_variables))))] + +mod my_mod { + #![doc(test(attr(deny(warnings))))] + + /// Example + /// + /// ```rust,no_run + /// trait T { fn f(); } + /// ``` + pub fn f() {} +} + +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarning { fn no_deny_warnings(); } +/// ``` +pub fn g() {} diff --git a/tests/rustdoc-ui/doctest/dead-code-module-2.stdout b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout new file mode 100644 index 0000000000000..d44068dcbf5d7 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout @@ -0,0 +1,35 @@ + +running 1 test +test $DIR/dead-code-module-2.rs - g (line 24) - compile ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + + +running 1 test +test $DIR/dead-code-module-2.rs - my_mod::f (line 16) - compile ... FAILED + +failures: + +---- $DIR/dead-code-module-2.rs - my_mod::f (line 16) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code-module-2.rs:17:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code-module-2.rs:15:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-module-2.rs - my_mod::f (line 16) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/dead-code-module.rs b/tests/rustdoc-ui/doctest/dead-code-module.rs new file mode 100644 index 0000000000000..f825749a6a25a --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module.rs @@ -0,0 +1,18 @@ +// Same test as dead-code but inside a module. + +//@ edition: 2024 +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +mod my_mod { + #![doc(test(attr(allow(unused_variables), deny(warnings))))] + + /// Example + /// + /// ```rust,no_run + /// trait T { fn f(); } + /// ``` + pub fn f() {} +} diff --git a/tests/rustdoc-ui/doctest/dead-code-module.stdout b/tests/rustdoc-ui/doctest/dead-code-module.stdout new file mode 100644 index 0000000000000..b5ccf225d25c7 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module.stdout @@ -0,0 +1,29 @@ + +running 1 test +test $DIR/dead-code-module.rs - my_mod::f (line 14) - compile ... FAILED + +failures: + +---- $DIR/dead-code-module.rs - my_mod::f (line 14) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code-module.rs:15:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code-module.rs:13:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-module.rs - my_mod::f (line 14) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/doc-test-attr-pass-module.rs b/tests/rustdoc-ui/doctest/doc-test-attr-pass-module.rs new file mode 100644 index 0000000000000..e916ca41ea0eb --- /dev/null +++ b/tests/rustdoc-ui/doctest/doc-test-attr-pass-module.rs @@ -0,0 +1,11 @@ +//@ check-pass + +#![crate_type = "lib"] +#![deny(invalid_doc_attributes)] +#![doc(test(no_crate_inject))] + +mod my_mod { + #![doc(test(attr(deny(warnings))))] + + pub fn foo() {} +} diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 7cda6c2eaa529..532c1ab13d118 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -138,7 +138,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_arch = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_arch` are: `aarch64`, `amdgpu`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`, and `xtensa` + = note: expected values for `target_arch` are: `aarch64`, `amdgpu`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch32`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`, and `xtensa` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/future-incompatible-lint-group.rs b/tests/ui/future-incompatible-lint-group.rs index c84538318f70f..ed2c47bb60907 100644 --- a/tests/ui/future-incompatible-lint-group.rs +++ b/tests/ui/future-incompatible-lint-group.rs @@ -2,16 +2,14 @@ // lints for changes that are not tied to an edition #![deny(future_incompatible)] +// Error since this is a `future_incompatible` lint +macro_rules! m { ($i) => {} } //~ ERROR missing fragment specifier + //~| WARN this was previously accepted + trait Tr { // Warn only since this is not a `future_incompatible` lint fn f(u8) {} //~ WARN anonymous parameters are deprecated //~| WARN this is accepted in the current edition } -pub mod submodule { - // Error since this is a `future_incompatible` lint - #![doc(test(some_test))] - //~^ ERROR this attribute can only be applied at the crate level -} - fn main() {} diff --git a/tests/ui/future-incompatible-lint-group.stderr b/tests/ui/future-incompatible-lint-group.stderr index 4e6c434fa29b2..4c867e0aab3cb 100644 --- a/tests/ui/future-incompatible-lint-group.stderr +++ b/tests/ui/future-incompatible-lint-group.stderr @@ -1,5 +1,20 @@ +error: missing fragment specifier + --> $DIR/future-incompatible-lint-group.rs:6:19 + | +LL | macro_rules! m { ($i) => {} } + | ^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 +note: the lint level is defined here + --> $DIR/future-incompatible-lint-group.rs:3:9 + | +LL | #![deny(future_incompatible)] + | ^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` + warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/future-incompatible-lint-group.rs:7:10 + --> $DIR/future-incompatible-lint-group.rs:11:10 | LL | fn f(u8) {} | ^^ help: try naming the parameter or explicitly ignoring it: `_: u8` @@ -8,14 +23,21 @@ LL | fn f(u8) {} = note: for more information, see issue #41686 = note: `#[warn(anonymous_parameters)]` on by default -error: this attribute can only be applied at the crate level - --> $DIR/future-incompatible-lint-group.rs:13:12 +error: aborting due to 1 previous error; 1 warning emitted + +Future incompatibility report: Future breakage diagnostic: +error: missing fragment specifier + --> $DIR/future-incompatible-lint-group.rs:6:19 | -LL | #![doc(test(some_test))] - | ^^^^^^^^^^^^^^^ +LL | macro_rules! m { ($i) => {} } + | ^^ | - = note: read for more information - = note: `#[deny(invalid_doc_attributes)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 +note: the lint level is defined here + --> $DIR/future-incompatible-lint-group.rs:3:9 + | +LL | #![deny(future_incompatible)] + | ^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` diff --git a/tests/ui/lint/force-warn/ice-free.rs b/tests/ui/lint/force-warn/ice-free.rs new file mode 100644 index 0000000000000..99b79f44648b2 --- /dev/null +++ b/tests/ui/lint/force-warn/ice-free.rs @@ -0,0 +1,9 @@ +//@ compile-flags: --force-warn pub_use_of_private_extern_crate +//@ check-pass + +extern crate core; +pub use core as reexported_core; +//~^ warning: extern crate `core` is private +//~| warning: this was previously accepted by the compiler + +fn main() {} diff --git a/tests/ui/lint/force-warn/ice-free.stderr b/tests/ui/lint/force-warn/ice-free.stderr new file mode 100644 index 0000000000000..b64e3b138a265 --- /dev/null +++ b/tests/ui/lint/force-warn/ice-free.stderr @@ -0,0 +1,32 @@ +warning[E0365]: extern crate `core` is private and cannot be re-exported + --> $DIR/ice-free.rs:5:9 + | +LL | pub use core as reexported_core; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #127909 + = note: requested on the command line with `--force-warn pub-use-of-private-extern-crate` +help: consider making the `extern crate` item publicly accessible + | +LL | pub extern crate core; + | +++ + +warning: 1 warning emitted + +For more information about this error, try `rustc --explain E0365`. +Future incompatibility report: Future breakage diagnostic: +warning[E0365]: extern crate `core` is private and cannot be re-exported + --> $DIR/ice-free.rs:5:9 + | +LL | pub use core as reexported_core; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #127909 + = note: requested on the command line with `--force-warn pub-use-of-private-extern-crate` +help: consider making the `extern crate` item publicly accessible + | +LL | pub extern crate core; + | +++ + diff --git a/tests/ui/lint/unused/useless-comment.rs b/tests/ui/lint/unused/useless-comment.rs index 4ec52f20747da..898665278e39c 100644 --- a/tests/ui/lint/unused/useless-comment.rs +++ b/tests/ui/lint/unused/useless-comment.rs @@ -9,8 +9,13 @@ macro_rules! mac { /// foo //~ ERROR unused doc comment mac!(); +/// a //~ ERROR unused doc comment +#[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment +unsafe extern "C" { } + fn foo() { /// a //~ ERROR unused doc comment + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment let x = 12; /// multi-line //~ ERROR unused doc comment @@ -19,6 +24,7 @@ fn foo() { match x { /// c //~ ERROR unused doc comment 1 => {}, + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment _ => {} } @@ -32,6 +38,7 @@ fn foo() { /// bar //~ ERROR unused doc comment mac!(); + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment let x = /** comment */ 47; //~ ERROR unused doc comment /// dox //~ ERROR unused doc comment diff --git a/tests/ui/lint/unused/useless-comment.stderr b/tests/ui/lint/unused/useless-comment.stderr index 8bb5bdaeb250f..39873b82b7575 100644 --- a/tests/ui/lint/unused/useless-comment.stderr +++ b/tests/ui/lint/unused/useless-comment.stderr @@ -12,7 +12,28 @@ LL | #![deny(unused_doc_comments)] | ^^^^^^^^^^^^^^^^^^^ error: unused doc comment - --> $DIR/useless-comment.rs:32:5 + --> $DIR/useless-comment.rs:12:1 + | +LL | /// a + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[doc(test(attr(allow(dead_code))))] +LL | unsafe extern "C" { } + | --------------------- rustdoc does not generate documentation for extern blocks + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:13:1 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe extern "C" { } + | --------------------- rustdoc does not generate documentation for extern blocks + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:38:5 | LL | /// bar | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations @@ -20,17 +41,28 @@ LL | /// bar = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion error: unused doc comment - --> $DIR/useless-comment.rs:13:5 + --> $DIR/useless-comment.rs:17:5 | LL | /// a | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[doc(test(attr(allow(dead_code))))] LL | let x = 12; | ----------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:16:5 + --> $DIR/useless-comment.rs:18:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = 12; + | ----------- rustdoc does not generate documentation for statements + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:21:5 | LL | / /// multi-line LL | | /// doc comment @@ -39,6 +71,7 @@ LL | | /// that is unused LL | / match x { LL | | /// c LL | | 1 => {}, +LL | | #[doc(test(attr(allow(dead_code))))] LL | | _ => {} LL | | } | |_____- rustdoc does not generate documentation for expressions @@ -46,7 +79,7 @@ LL | | } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:20:9 + --> $DIR/useless-comment.rs:25:9 | LL | /// c | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +89,17 @@ LL | 1 => {}, = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:25:5 + --> $DIR/useless-comment.rs:27:9 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | _ => {} + | ------- rustdoc does not generate documentation for match arms + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:31:5 | LL | /// foo | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +109,7 @@ LL | unsafe {} = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:28:5 + --> $DIR/useless-comment.rs:34:5 | LL | #[doc = "foo"] | ^^^^^^^^^^^^^^ @@ -77,7 +120,7 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:29:5 + --> $DIR/useless-comment.rs:35:5 | LL | #[doc = "bar"] | ^^^^^^^^^^^^^^ @@ -87,7 +130,17 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:35:13 + --> $DIR/useless-comment.rs:41:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = /** comment */ 47; + | -------------------------- rustdoc does not generate documentation for statements + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:42:13 | LL | let x = /** comment */ 47; | ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions @@ -95,7 +148,7 @@ LL | let x = /** comment */ 47; = help: use `/* */` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:37:5 + --> $DIR/useless-comment.rs:44:5 | LL | /// dox | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,5 +159,5 @@ LL | | } | = help: use `//` for a plain comment -error: aborting due to 10 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/rustdoc/doc-test-attr-pass.rs b/tests/ui/rustdoc/doc-test-attr-pass.rs index f0120b7c2d0b4..60d1e3722bdff 100644 --- a/tests/ui/rustdoc/doc-test-attr-pass.rs +++ b/tests/ui/rustdoc/doc-test-attr-pass.rs @@ -6,4 +6,46 @@ #![doc(test(attr(deny(warnings))))] #![doc(test())] +mod test { + #![doc(test(attr(allow(warnings))))] +} + +#[doc(test(attr(allow(dead_code))))] +static S: u32 = 5; + +#[doc(test(attr(allow(dead_code))))] +const C: u32 = 5; + +#[doc(test(attr(deny(dead_code))))] +struct A { + #[doc(test(attr(allow(dead_code))))] + field: u32 +} + +#[doc(test(attr(deny(dead_code))))] +union U { + #[doc(test(attr(allow(dead_code))))] + field: u32, + field2: u64, +} + +#[doc(test(attr(deny(dead_code))))] +enum Enum { + #[doc(test(attr(allow(dead_code))))] + Variant1, +} + +#[doc(test(attr(deny(dead_code))))] +impl A { + #[doc(test(attr(deny(dead_code))))] + fn method() {} +} + +#[doc(test(attr(deny(dead_code))))] +trait MyTrait { + #[doc(test(attr(deny(dead_code))))] + fn my_trait_fn(); +} + +#[doc(test(attr(deny(dead_code))))] pub fn foo() {} diff --git a/tests/crashes/140571.rs b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs similarity index 54% rename from tests/crashes/140571.rs rename to tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs index 97fa1d8432dd9..f4cde1d62b2c9 100644 --- a/tests/crashes/140571.rs +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs @@ -1,14 +1,21 @@ -//@ known-bug: #140571 +// Regression test for #140571. The compiler used to ICE + +#![feature(associated_const_equality, specialization)] +//~^ WARN the feature `specialization` is incomplete + pub trait IsVoid { const IS_VOID: bool; } impl IsVoid for T { default const IS_VOID: bool = false; } -impl Maybe for () where T: NotVoid + ?Sized {} pub trait NotVoid {} impl NotVoid for T where T: IsVoid + ?Sized {} pub trait Maybe {} impl Maybe for T {} +impl Maybe for () where T: NotVoid + ?Sized {} +//~^ ERROR conflicting implementations of trait `Maybe<()>` for type `()` + +fn main() {} diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr new file mode 100644 index 0000000000000..a26b30fbb633c --- /dev/null +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr @@ -0,0 +1,21 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:39 + | +LL | #![feature(associated_const_equality, specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0119]: conflicting implementations of trait `Maybe<()>` for type `()` + --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:18:1 + | +LL | impl Maybe for T {} + | ---------------------- first implementation here +LL | impl Maybe for () where T: NotVoid + ?Sized {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0119`.