diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 34ff4eb623917..846ae9ca314de 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -956,6 +956,12 @@ # want to enable this right now. #rust.wasm-proc-macros = false +# Enables wasm targets to be built with `-Cpanic=unwind` by default instead of +# the current `-Cpanic=abort`. This is currently used in testing the Rust +# compiler itself and is only intended for local development/testing at this +# time. +#rust.wasm-panic-unwind-default = false + # ============================================================================= # Distribution options # diff --git a/compiler/rustc_codegen_llvm/src/back/llvm_backend.rs b/compiler/rustc_codegen_llvm/src/back/llvm_backend.rs index 8780af2f6d595..7aa1920ccf81d 100644 --- a/compiler/rustc_codegen_llvm/src/back/llvm_backend.rs +++ b/compiler/rustc_codegen_llvm/src/back/llvm_backend.rs @@ -3,8 +3,11 @@ use std::any::Any; use std::ffi::CStr; +use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::path::PathBuf; +use std::ptr; +use std::sync::OnceLock; use rustc_ast::expand::allocator::AllocatorMethod; use rustc_codegen_ssa::back::lto::ThinModule; @@ -59,11 +62,10 @@ impl ExtraBackendMethods for LlvmCodegenBackend { methods: &[AllocatorMethod], ) -> ModuleLlvm { let module_llvm = ModuleLlvm::new_metadata(tcx, module_name); - let cx = - SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size()); - unsafe { - allocator::codegen(tcx, cx, module_name, methods); - } + module_llvm.with_module_refs(|ModuleRefs { llcx, llmod, .. }| { + let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size()); + unsafe { allocator::codegen(tcx, cx, module_name, methods) }; + }); module_llvm } fn compile_codegen_unit( @@ -141,7 +143,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { module: &mut ModuleCodegen, config: &ModuleConfig, ) { - back::write::optimize(cgcx, prof, shared_emitter, module, config) + back::write::optimize(cgcx, prof, shared_emitter, module, config); } fn optimize_and_codegen_thin( cgcx: &CodegenContext, @@ -162,7 +164,9 @@ impl WriteBackendMethods for LlvmCodegenBackend { back::write::codegen(cgcx, prof, shared_emitter, module, config) } fn serialize_module(module: Self::Module, is_thin: bool) -> Self::ModuleBuffer { - back::lto::ModuleBuffer::new(module.llmod(), is_thin) + module.with_module_refs(|ModuleRefs { llmod, .. }| { + back::lto::ModuleBuffer::new(llmod, is_thin) + }) } } @@ -421,40 +425,56 @@ impl CodegenBackend for LlvmCodegenBackend { } pub struct ModuleLlvm { - pub(crate) llcx: &'static mut llvm::Context, + llcx_raw: ptr::NonNull, llmod_raw: *const llvm::Module, // This field is `ManuallyDrop` because it is important that the `TargetMachine` // is disposed prior to the `Context` being disposed otherwise UAFs can occur. - pub(crate) tm: ManuallyDrop, + tm: ManuallyDrop, + + /// Saved ThinLTO buffer for embedding in the object file. + /// + /// This is currently a `OnceLock` to avoid aliasing problems when writing to it + /// from code that also wants to pass around a shared ref to `ModuleCodegen`. + pub(crate) thin_lto_buffer: OnceLock>, } unsafe impl Send for ModuleLlvm {} unsafe impl Sync for ModuleLlvm {} +/// Shared helper to call [`llvm::LLVMContextCreate`] and then configure +/// [`llvm::LLVMContextSetDiscardValueNames`]. +fn create_context_and_set_fewer_names(fewer_names: bool) -> ptr::NonNull { + unsafe { + let llcx_raw = llvm::LLVMContextCreate(); + llvm::LLVMContextSetDiscardValueNames(llcx_raw.as_ref(), fewer_names.to_llvm_bool()); + llcx_raw + } +} + impl ModuleLlvm { pub(crate) fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self { unsafe { - let llcx = llvm::LLVMContextCreate(); - llvm::LLVMContextSetDiscardValueNames(llcx, tcx.sess.fewer_names().to_llvm_bool()); - let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; + let llcx_raw = create_context_and_set_fewer_names(tcx.sess.fewer_names()); + let llmod_raw = context::create_module(tcx, llcx_raw.as_ref(), mod_name); ModuleLlvm { llmod_raw, - llcx, + llcx_raw, tm: ManuallyDrop::new(create_target_machine(tcx, mod_name)), + thin_lto_buffer: OnceLock::new(), } } } pub(crate) fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self { unsafe { - let llcx = llvm::LLVMContextCreate(); - llvm::LLVMContextSetDiscardValueNames(llcx, tcx.sess.fewer_names().to_llvm_bool()); - let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; + let llcx_raw = create_context_and_set_fewer_names(tcx.sess.fewer_names()); + let llmod_raw = context::create_module(tcx, llcx_raw.as_ref(), mod_name); ModuleLlvm { llmod_raw, - llcx, + llcx_raw, tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)), + thin_lto_buffer: OnceLock::new(), } } } @@ -467,17 +487,34 @@ impl ModuleLlvm { dcx: DiagCtxtHandle<'_>, ) -> Self { unsafe { - let llcx = llvm::LLVMContextCreate(); - llvm::LLVMContextSetDiscardValueNames(llcx, cgcx.fewer_names.to_llvm_bool()); - let llmod_raw = back::lto::parse_module(llcx, name, buffer, dcx); + let llcx_raw = create_context_and_set_fewer_names(cgcx.fewer_names); + let llmod_raw = back::lto::parse_module(llcx_raw.as_ref(), name, buffer, dcx); let tm = tm_factory(dcx, TargetMachineFactoryConfig::new(cgcx, name.to_str().unwrap())); - ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) } + ModuleLlvm { + llmod_raw, + llcx_raw, + tm: ManuallyDrop::new(tm), + thin_lto_buffer: OnceLock::new(), + } } } - pub(crate) fn llmod(&self) -> &llvm::Module { - unsafe { &*self.llmod_raw } + /// Passes a [`ModuleRefs`] struct to a callback function, giving it scoped + /// access to the resources owned by this module. + /// + /// Passing the references to a callback ensures that they have coherent + /// `'ll` lifetimes, and that they can't escape the callback. + pub(crate) fn with_module_refs( + &self, + inner_fn: impl for<'ll> FnOnce(ModuleRefs<'ll>) -> R, + ) -> R { + inner_fn(ModuleRefs { + llcx: unsafe { self.llcx_raw.as_ref() }, + llmod: unsafe { &*self.llmod_raw }, + tm: self.tm.raw(), + _ph: PhantomData, + }) } } @@ -485,7 +522,20 @@ impl Drop for ModuleLlvm { fn drop(&mut self) { unsafe { ManuallyDrop::drop(&mut self.tm); - llvm::LLVMContextDispose(&mut *(self.llcx as *mut _)); + llvm::LLVMContextDispose(self.llcx_raw); } } } + +/// Bundle of references provided by [`ModuleLlvm::with_module_refs`]. +#[derive(Clone, Copy)] +pub(crate) struct ModuleRefs<'ll> { + pub(crate) llcx: &'ll llvm::Context, + pub(crate) llmod: &'ll llvm::Module, + pub(crate) tm: &'ll llvm::TargetMachine, + /// Make sure `'ll` is invariant, even if no fields happen to require that. + /// + /// FIXME(Zalathar): Consider using `PhantomInvariantLifetime` when the API + /// for that is settled. + _ph: PhantomData &'ll ()>, +} diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index b171424b46245..6d7c406946127 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -24,6 +24,7 @@ use rustc_span::bug; use rustc_structures::SanitizerSet; use tracing::{debug, info}; +use crate::back::llvm_backend::ModuleRefs; use crate::back::write::{ self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, codegen, save_temp_bitcode, @@ -249,7 +250,9 @@ fn fat_lto( .enumerate() .filter(|&(_, module)| module.kind == ModuleKind::Regular) .map(|(i, module)| { - let cost = unsafe { llvm::LLVMRustModuleCost(module.module_llvm.llmod()) }; + let cost = module.module_llvm.with_module_refs(|ModuleRefs { llmod, .. }| unsafe { + llvm::LLVMRustModuleCost(llmod) + }); (cost, i) }) .max(); @@ -269,11 +272,7 @@ fn fat_lto( ModuleCodegen::new_regular(name.into_string().unwrap(), llvm_module) } }; - { - let (llcx, llmod) = { - let llvm = &module.module_llvm; - (&llvm.llcx, llvm.llmod()) - }; + module.module_llvm.with_module_refs(|ModuleRefs { llcx, llmod, .. }| { info!("using {:?} as a base module", module.name); // The linking steps below may produce errors and diagnostics within LLVM @@ -293,7 +292,9 @@ fn fat_lto( // way we know of to do that is to serialize them to a string and them parse // them later. Not great but hey, that's why it's "fat" LTO, right? for module in in_memory { - let buffer = ModuleBuffer::new(module.module_llvm.llmod(), false); + let buffer = module + .module_llvm + .with_module_refs(|ModuleRefs { llmod, .. }| ModuleBuffer::new(llmod, false)); let llmod_id = CString::new(&module.name[..]).unwrap(); serialized_modules.push((SerializedModule::Local(buffer), llmod_id)); } @@ -330,7 +331,7 @@ fn fat_lto( ); } save_temp_bitcode(cgcx, &module, "lto.after-restriction"); - } + }); module } @@ -584,7 +585,7 @@ pub(crate) fn run_pass_manager( cgcx: &CodegenContext, prof: &SelfProfilerRef, dcx: DiagCtxtHandle<'_>, - module: &mut ModuleCodegen, + module: &ModuleCodegen, thin: bool, ) { let _timer = prof.generic_activity_with_arg("LLVM_lto_optimize", &*module.name); @@ -612,11 +613,24 @@ pub(crate) fn run_pass_manager( if enable_ad { write::AutodiffStage::DuringAD } else { write::AutodiffStage::PostAD } }; - unsafe { - write::llvm_optimize( - cgcx, prof, dcx, module, None, None, config, opt_level, opt_stage, stage, - ); - } + let llvm_optimize = |opt_stage, stage| { + module.module_llvm.with_module_refs(|module_refs| unsafe { + write::llvm_optimize( + cgcx, + prof, + dcx, + module_refs, + None, + None, + config, + opt_level, + opt_stage, + stage, + ) + }); + }; + + llvm_optimize(opt_stage, stage); if enable_ad && !thin { let opt_stage = llvm::OptStage::FatLTO; @@ -624,17 +638,15 @@ pub(crate) fn run_pass_manager( if !config.autodiff.contains(&config::AutoDiff::NoPostopt) && config.autodiff_post_passes.as_deref() != Some("") { - unsafe { - write::llvm_optimize( - cgcx, prof, dcx, module, None, None, config, opt_level, opt_stage, stage, - ); - } + llvm_optimize(opt_stage, stage); } // This is the final IR, so people should be able to inspect the optimized autodiff output, // for manual inspection. if config.autodiff.contains(&config::AutoDiff::PrintModFinal) { - unsafe { llvm::LLVMDumpModule(module.module_llvm.llmod()) }; + module.module_llvm.with_module_refs(|ModuleRefs { llmod, .. }| unsafe { + llvm::LLVMDumpModule(llmod) + }); } } @@ -715,14 +727,16 @@ pub(crate) fn optimize_and_codegen_thin_module( // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. let module_llvm = ModuleLlvm::parse(cgcx, tm_factory, module_name, thin_module.data(), dcx); - let mut module = ModuleCodegen::new_regular(thin_module.name(), module_llvm); + let module = ModuleCodegen::new_regular(thin_module.name(), module_llvm); // Given that the newly created module lacks a thinlto buffer for embedding, we need to re-add it here. if cgcx.module_config.embed_bitcode() { - module.thin_lto_buffer = Some(thin_module.data().to_vec()); + module + .module_llvm + .thin_lto_buffer + .set(thin_module.data().to_vec()) + .expect("thin_lto_buffer should be unset"); } - { - let target = &*module.module_llvm.tm; - let llmod = module.module_llvm.llmod(); + module.module_llvm.with_module_refs(|ModuleRefs { llmod, tm, .. }| { save_temp_bitcode(cgcx, &module, "thin-lto-input"); // Up next comes the per-module local analyses that we do for Thin LTO. @@ -735,9 +749,7 @@ pub(crate) fn optimize_and_codegen_thin_module( // bindings we've got (currently `PassWrapper.cpp`) { let _timer = prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name()); - unsafe { - llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target.raw()) - }; + unsafe { llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, tm) }; save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); } @@ -763,9 +775,8 @@ pub(crate) fn optimize_and_codegen_thin_module( { let _timer = prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name()); - if unsafe { - !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target.raw()) - } { + if unsafe { !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, tm) } + { write::llvm_err(dcx, LlvmError::PrepareThinLtoModule); } save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); @@ -778,10 +789,10 @@ pub(crate) fn optimize_and_codegen_thin_module( // little differently. { info!("running thin lto passes over {}", module.name); - run_pass_manager(cgcx, prof, dcx, &mut module, true); + run_pass_manager(cgcx, prof, dcx, &module, true); save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); } - } + }); codegen(cgcx, prof, shared_emitter, module, &cgcx.module_config) } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index b7e400567b1f3..41a04c637b231 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -26,6 +26,7 @@ use rustc_span::{BytePos, DUMMY_SP, InnerSpan, Pos, RemapPathScopeComponents}; use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel}; use tracing::{debug, trace}; +use crate::back::llvm_backend::ModuleRefs; use crate::back::lto::{Buffer, ModuleBuffer}; use crate::back::owned_target_machine::OwnedTargetMachine; use crate::back::profiling::{ @@ -302,11 +303,10 @@ pub(crate) fn save_temp_bitcode( } fn write_bitcode_to_file(module: &ModuleLlvm, path: &Path) { - unsafe { - let path = path_to_c_string(&path); - let llmod = module.llmod(); - llvm::LLVMWriteBitcodeToFile(llmod, path.as_ptr()); - } + let path = path_to_c_string(&path); + module.with_module_refs(|ModuleRefs { llmod, .. }| { + unsafe { llvm::LLVMWriteBitcodeToFile(llmod, path.as_ptr()) }; + }); } /// In what context is a diagnostic handler being attached to a codegen unit? @@ -540,11 +540,11 @@ pub(crate) enum AutodiffStage { PostAD, } -pub(crate) unsafe fn llvm_optimize( +pub(crate) unsafe fn llvm_optimize<'ll>( cgcx: &CodegenContext, prof: &SelfProfilerRef, dcx: DiagCtxtHandle<'_>, - module: &ModuleCodegen, + module_refs: ModuleRefs<'ll>, thin_lto_buffer: Option<&mut Option>, thin_lto_summary_buffer: Option<&mut Option>, config: &ModuleConfig, @@ -552,6 +552,8 @@ pub(crate) unsafe fn llvm_optimize( opt_stage: llvm::OptStage, autodiff_stage: AutodiffStage, ) { + let ModuleRefs { llcx, llmod, tm, .. } = module_refs; + // Enzyme: // The whole point of compiler based AD is to differentiate optimized IR instead of unoptimized // source code. However, benchmarks show that optimizations increasing the code size @@ -747,8 +749,7 @@ pub(crate) unsafe fn llvm_optimize( if cgcx.target_is_like_gpu && config.offload.iter().any(|o| matches!(o, config::Offload::Device(_))) { - let cx = - SimpleCx::new(module.module_llvm.llmod(), module.module_llvm.llcx, cgcx.pointer_size); + let cx = SimpleCx::new(llmod, llcx, cgcx.pointer_size); for func in cx.get_functions() { let offload_kernel = "offload-kernel"; if attributes::has_string_attr(func, offload_kernel) { @@ -778,8 +779,8 @@ pub(crate) unsafe fn llvm_optimize( let result = unsafe { llvm::LLVMRustOptimize( - module.module_llvm.llmod(), - &*module.module_llvm.tm.raw(), + llmod, + tm, to_pass_builder_opt_level(opt_level), opt_stage, cgcx.use_linker_plugin_lto, @@ -827,8 +828,8 @@ pub(crate) unsafe fn llvm_optimize( // 1) Bundle device module into offload image device.bin (device TM) let ok = unsafe { llvm::RustOffloadWrapper::get_instance().llvm_rust_bundle_images( - module.module_llvm.llmod(), - module.module_llvm.tm.raw(), + llmod, + tm, device_out_c.as_c_str(), ) }; @@ -860,10 +861,8 @@ pub(crate) unsafe fn llvm_optimize( } let device_bin_c = path_to_c_string(device_pathbuf.as_path()); let ok = unsafe { - llvm::RustOffloadWrapper::get_instance().llvm_rust_offload_wrap_images( - module.module_llvm.llmod(), - device_bin_c.as_c_str(), - ) + llvm::RustOffloadWrapper::get_instance() + .llvm_rust_offload_wrap_images(llmod, device_bin_c.as_c_str()) }; if !ok { dcx.emit_err(crate::diagnostics::OffloadWrapImagesFailed); @@ -873,12 +872,28 @@ pub(crate) unsafe fn llvm_optimize( result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::RunLlvmPasses)) } -// Unsafe due to LLVM calls. pub(crate) fn optimize( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, - module: &mut ModuleCodegen, + module: &ModuleCodegen, + config: &ModuleConfig, +) { + // Pass `module_refs` to an inner function to avoid having to indent the whole thing. + // + // It feels a bit odd to be passing both `module` and `module_refs` here, but it's + // unclear whether trying to avoid that would actually be an improvement. + module.module_llvm.with_module_refs(|module_refs| { + optimize_inner(cgcx, prof, shared_emitter, module, module_refs, config); + }); +} + +fn optimize_inner<'ll>( + cgcx: &CodegenContext, + prof: &SelfProfilerRef, + shared_emitter: &SharedEmitter, + module: &ModuleCodegen, + module_refs: ModuleRefs<'ll>, // Should be the refs from `module.module_llvm` config: &ModuleConfig, ) { let _timer = prof.generic_activity_with_arg("LLVM_module_optimize", &*module.name); @@ -886,9 +901,13 @@ pub(crate) fn optimize( let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); - let llcx = &*module.module_llvm.llcx; - let _handlers = - DiagnosticHandlers::new(cgcx, shared_emitter, llcx, module, CodegenDiagnosticsStage::Opt); + let _handlers = DiagnosticHandlers::new( + cgcx, + shared_emitter, + module_refs.llcx, + module, + CodegenDiagnosticsStage::Opt, + ); if module.kind == ModuleKind::Regular { save_temp_bitcode(cgcx, module, "no-opt"); @@ -926,7 +945,7 @@ pub(crate) fn optimize( cgcx, prof, dcx, - module, + module_refs, thin_lto_buffer.as_mut(), thin_lto_summary_buffer.as_mut(), config, @@ -937,7 +956,11 @@ pub(crate) fn optimize( }; if let Some(thin_lto_buffer) = thin_lto_buffer { let thin_lto_buffer = thin_lto_buffer.unwrap(); - module.thin_lto_buffer = Some(thin_lto_buffer.data().to_vec()); + module + .module_llvm + .thin_lto_buffer + .set(thin_lto_buffer.data().to_vec()) + .expect("thin_lto_buffer should be unset"); let bc_summary_out = cgcx.output_filenames.temp_path_for_cgu(OutputType::ThinLinkBitcode, &module.name); if let Some(thin_lto_summary_buffer) = thin_lto_summary_buffer @@ -974,10 +997,7 @@ pub(crate) fn codegen( let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); - { - let llmod = module.module_llvm.llmod(); - let llcx = &*module.module_llvm.llcx; - let tm = &*module.module_llvm.tm; + module.module_llvm.with_module_refs(|ModuleRefs { llcx, llmod, tm, .. }| { let _handlers = DiagnosticHandlers::new( cgcx, shared_emitter, @@ -1025,7 +1045,7 @@ pub(crate) fn codegen( let _timer = prof .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name); let thin_bc = - module.thin_lto_buffer.as_deref().expect("cannot find embedded bitcode"); + module.module_llvm.thin_lto_buffer.get().expect("cannot find embedded bitcode"); embed_bitcode(cgcx, llcx, llmod, &thin_bc); } } @@ -1091,7 +1111,7 @@ pub(crate) fn codegen( }; write_output_file( dcx, - tm.raw(), + tm, config.no_builtins, llmod, &path, @@ -1124,7 +1144,7 @@ pub(crate) fn codegen( write_output_file( dcx, - tm.raw(), + tm, config.no_builtins, llmod, &obj_out, @@ -1151,7 +1171,7 @@ pub(crate) fn codegen( } record_llvm_cgu_instructions_stats(prof, &module.name, llmod); - } + }); // `.dwo` files are only emitted if: // diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 77cb37edec770..87eb157a8892f 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -93,8 +93,8 @@ pub(crate) fn compile_codegen_unit( }); // Instantiate monomorphizations without filling out definitions yet... let llvm_module = ModuleLlvm::new(tcx, cgu_name.as_str()); - { - let mut cx = CodegenCx::new(tcx, cgu, &llvm_module, needs_bitcode); + llvm_module.with_module_refs(|module_refs| { + let mut cx = CodegenCx::new(tcx, cgu, module_refs, needs_bitcode); // Declare and store globals shared by all offload kernels // @@ -213,7 +213,7 @@ pub(crate) fn compile_codegen_unit( if cx.sess().opts.debuginfo != DebugInfo::None { cx.debuginfo_finalize(); } - } + }); ModuleCodegen::new_regular(cgu_name.to_string(), llvm_module) } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 46196ab7d360f..6e0681e203f1d 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,6 +34,7 @@ use rustc_target::spec::{ use smallvec::SmallVec; use crate::abi::to_llvm_calling_convention; +use crate::back::llvm_backend::ModuleRefs; use crate::back::write::to_llvm_code_model; use crate::builder::gpu_offload::{OffloadGlobals, OffloadKernelGlobals}; use crate::callee::get_fn; @@ -185,11 +186,16 @@ pub(crate) unsafe fn create_module<'ll>( tcx: TyCtxt<'_>, llcx: &'ll llvm::Context, mod_name: &str, -) -> &'ll llvm::Module { - let sess = tcx.sess; - let mod_name = SmallCStr::new(mod_name); - let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) }; +) -> *const llvm::Module { + let mod_name_cstr = SmallCStr::new(mod_name); + let llmod_raw = + unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name_cstr.as_ptr(), llcx) }; + init_module(tcx, llcx, unsafe { &*llmod_raw }); + llmod_raw +} +fn init_module<'ll, 'tcx>(tcx: TyCtxt<'tcx>, llcx: &'ll llvm::Context, llmod: &'ll llvm::Module) { + let sess = tcx.sess; let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size()); let mut target_data_layout = sess.target.data_layout.to_string(); @@ -592,15 +598,13 @@ pub(crate) unsafe fn create_module<'ll>( }; llvm::add_module_flag_u32(llmod, merge_behavior, key, *value); } - - llmod } impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { pub(crate) fn new( tcx: TyCtxt<'tcx>, codegen_unit: &'tcx CodegenUnit<'tcx>, - llvm_module: &'ll crate::ModuleLlvm, + module_refs: ModuleRefs<'ll>, bitcode_needed: bool, ) -> Self { // An interesting part of Windows which MSVC forces our hand on (and @@ -659,7 +663,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { let tls_model = to_llvm_tls_model(tcx.sess.tls_model()); - let (llcx, llmod) = (&*llvm_module.llcx, llvm_module.llmod()); + let ModuleRefs { llcx, llmod, .. } = module_refs; let coverage_cx = tcx.sess.instrument_coverage().then(coverageinfo::CguCoverageContext::new); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 1a1af50c2c025..a8ededf305a29 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -887,8 +887,8 @@ pub(crate) type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> unsafe extern "C" { // Create and destroy contexts. - pub(crate) fn LLVMContextCreate() -> &'static mut Context; - pub(crate) fn LLVMContextDispose(C: &'static mut Context); + pub(crate) fn LLVMContextCreate() -> ptr::NonNull; + pub(crate) fn LLVMContextDispose(C: ptr::NonNull); pub(crate) fn LLVMContextSetDiscardValueNames(C: &Context, Discard: Bool); pub(crate) fn LLVMGetMDKindIDInContext( C: &Context, @@ -908,7 +908,7 @@ unsafe extern "C" { pub(crate) fn LLVMModuleCreateWithNameInContext( ModuleID: *const c_char, C: &Context, - ) -> &Module; + ) -> *const Module; pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module; /// Data layout. See Module::getDataLayout. diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index af37694136d24..1ac9564db0149 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -65,27 +65,15 @@ pub struct ModuleCodegen { pub name: String, pub module_llvm: M, pub kind: ModuleKind, - /// Saving the ThinLTO buffer for embedding in the object file. - pub thin_lto_buffer: Option>, } impl ModuleCodegen { pub fn new_regular(name: impl Into, module: M) -> Self { - Self { - name: name.into(), - module_llvm: module, - kind: ModuleKind::Regular, - thin_lto_buffer: None, - } + Self { name: name.into(), module_llvm: module, kind: ModuleKind::Regular } } pub fn new_allocator(name: impl Into, module: M) -> Self { - Self { - name: name.into(), - module_llvm: module, - kind: ModuleKind::Allocator, - thin_lto_buffer: None, - } + Self { name: name.into(), module_llvm: module, kind: ModuleKind::Allocator } } pub fn into_compiled_module( diff --git a/compiler/rustc_hir_typeck/src/diagnostics.rs b/compiler/rustc_hir_typeck/src/diagnostics.rs index 0b4a88500aaaa..3f06ce69b7c87 100644 --- a/compiler/rustc_hir_typeck/src/diagnostics.rs +++ b/compiler/rustc_hir_typeck/src/diagnostics.rs @@ -894,7 +894,7 @@ pub(crate) struct NoAssociatedItem<'tcx> { )] pub(crate) struct CandidateTraitNote { #[primary_span] - pub span: Span, + pub span: MultiSpan, pub trait_name: String, pub item_name: Ident, pub action_or_ty: String, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 26362c6eeed56..77850ad2a24b4 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -4743,8 +4743,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if impls_trait(trait_info.def_id) { self.suggest_valid_traits(err, item_name, vec![trait_info.def_id], false); } else { + let mut span: MultiSpan = self.tcx.def_span(trait_info.def_id).into(); + for assoc in self + .tcx + .associated_items(trait_info.def_id) + .filter_by_name_unhygienic(item_name.name) + { + span.push_span_context(self.tcx.def_span(assoc.def_id).shrink_to_lo()); + } err.subdiagnostic(CandidateTraitNote { - span: self.tcx.def_span(trait_info.def_id), + span, trait_name: self.tcx.def_path_str(trait_info.def_id), item_name, action_or_ty: if trait_missing_method { diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index 18a02666cfc4a..7270763f924ae 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -1433,6 +1433,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ResolutionError::BindingInNeverPattern => { self.dcx().create_err(diagnostics::BindingInNeverPattern { span }) } + ResolutionError::CannotUseInnerLocalInMoveExpr { + move_expr_span, + ident, + scope_span, + } => self.dcx().create_err(diagnostics::CannotUseInnerLocalInMoveExpr { + span, + ident, + binding_span: ident.span, + move_expr_span, + scope_span, + }), } } diff --git a/compiler/rustc_resolve/src/diagnostics/mod.rs b/compiler/rustc_resolve/src/diagnostics/mod.rs index a629af5d690bc..65ef919e9d0c7 100644 --- a/compiler/rustc_resolve/src/diagnostics/mod.rs +++ b/compiler/rustc_resolve/src/diagnostics/mod.rs @@ -525,6 +525,20 @@ pub(crate) struct BindingInNeverPattern { pub(crate) span: Span, } +#[derive(Diagnostic)] +#[diag("cannot use `{$ident}` in this move expression")] +pub(crate) struct CannotUseInnerLocalInMoveExpr { + #[primary_span] + pub(crate) span: Span, + pub(crate) ident: Ident, + #[label("`{$ident}` is defined here")] + pub(crate) binding_span: Span, + #[label("this expression is evaluated outside that scope")] + pub(crate) move_expr_span: Span, + #[label("`{$ident}` is defined within this scope")] + pub(crate) scope_span: Span, +} + #[derive(Diagnostic)] #[diag("duplicate definitions with name `{$name}`:", code = E0201)] pub(crate) struct TraitImplDuplicate { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 6a5a73715c840..6b460195b9b5b 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1511,9 +1511,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for rib in ribs { match rib.kind { + // `first_rib` marks the start of the closure or coroutine scope. + // The initializer is evaluated outside that scope, so bindings defined + // inside it are unavailable, while outer bindings remain accessible. + RibKind::MoveExpr { first_rib, move_expr_span, scope_span } + if rib_index >= first_rib => + { + if let Some(span) = finalize { + self.report_error( + span, + CannotUseInnerLocalInMoveExpr { + move_expr_span, + ident: original_rib_ident_def, + scope_span, + }, + ); + } + return Res::Err; + } RibKind::Normal | RibKind::Block(..) | RibKind::FnOrCoroutine + | RibKind::MoveExpr { .. } | RibKind::Module(..) | RibKind::MacroDefinition(..) | RibKind::ForwardGenericParamBan(_) => { @@ -1610,6 +1629,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { RibKind::Normal | RibKind::Block(..) | RibKind::FnOrCoroutine + | RibKind::MoveExpr { .. } | RibKind::Module(..) | RibKind::MacroDefinition(..) | RibKind::InlineAsmSym @@ -1717,6 +1737,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { RibKind::Normal | RibKind::Block(..) | RibKind::FnOrCoroutine + | RibKind::MoveExpr { .. } | RibKind::Module(..) | RibKind::MacroDefinition(..) | RibKind::InlineAsmSym diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 417b875297ce4..315ace9c0d4cf 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -219,6 +219,12 @@ pub(crate) enum RibKind<'ra> { /// We passed through a function, closure or coroutine signature. Disallow labels. FnOrCoroutine, + MoveExpr { + first_rib: usize, + move_expr_span: Span, + scope_span: Span, + }, + /// We passed through an item scope. Disallow upvars. Item(HasGenericParams, DefKind), @@ -264,6 +270,7 @@ impl RibKind<'_> { RibKind::Normal | RibKind::Block(..) | RibKind::FnOrCoroutine + | RibKind::MoveExpr { .. } | RibKind::ConstantItem(..) | RibKind::Module(_) | RibKind::MacroDefinition(_) @@ -840,6 +847,8 @@ struct LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// The current set of local scopes for types and values. ribs: PerNS>>, + move_expr_scopes: Vec>, + /// Previous popped `rib`, only used for diagnostic. last_block_rib: Option>, @@ -901,7 +910,9 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc // Always report errors in items we just entered. let old_ignore = replace(&mut self.in_func_body, false); with_owner(self, item.id, |this| { - this.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item)) + this.with_move_expr_scope(None, |this| { + this.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item)) + }) }); self.in_func_body = old_ignore; self.diag_metadata.current_item = prev; @@ -1617,6 +1628,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { type_ns: vec![Rib::new(start_rib_kind)], macro_ns: vec![Rib::new(start_rib_kind)], }, + move_expr_scopes: Vec::new(), last_block_rib: None, label_ribs: Vec::new(), lifetime_ribs: Vec::new(), @@ -1728,6 +1740,39 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } + fn with_move_expr_scope( + &mut self, + scope_span: Option, + work: impl FnOnce(&mut Self) -> T, + ) -> T { + if !self.r.features.move_expr() { + return work(self); + } + let scope = scope_span.map(|span| (self.ribs[ValueNS].len(), span)); + self.move_expr_scopes.push(scope); + let result = work(self); + self.move_expr_scopes.pop(); + result + } + + fn with_move_expr_initializer( + &mut self, + move_expr_span: Span, + work: impl FnOnce(&mut Self) -> T, + ) -> T { + let Some(Some((first_rib, scope_span))) = self.move_expr_scopes.last().copied() else { + return work(self); + }; + self.move_expr_scopes.pop(); + let result = self.with_rib( + ValueNS, + RibKind::MoveExpr { first_rib, move_expr_span, scope_span }, + work, + ); + self.move_expr_scopes.push(Some((first_rib, scope_span))); + result + } + fn visit_generic_params(&mut self, params: &'ast [GenericParam], add_self_upper: bool) { // For type parameter defaults, we have to ban access // to following type parameters, as the GenericArgs can only @@ -5566,30 +5611,46 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ExprKind::Type(ref _type_expr, ref _ty) => { visit::walk_expr(self, expr); } + ExprKind::Move(..) => { + self.with_move_expr_initializer(expr.span, |this| visit::walk_expr(this, expr)); + } // For closures, RibKind::FnOrCoroutine is added in visit_fn ExprKind::Closure(ast::Closure { binder: ClosureBinder::For { ref generic_params, span }, + fn_decl_span, .. }) => { - self.with_generic_param_rib( - generic_params, - RibKind::Normal, - expr.id, - LifetimeBinderKind::Closure, - span, - |this| visit::walk_expr(this, expr), - ); + self.with_move_expr_scope(Some(fn_decl_span), |this| { + this.with_generic_param_rib( + generic_params, + RibKind::Normal, + expr.id, + LifetimeBinderKind::Closure, + span, + |this| visit::walk_expr(this, expr), + ); + }); + } + ExprKind::Closure(ref closure) => { + self.with_move_expr_scope(Some(closure.fn_decl_span), |this| { + visit::walk_expr(this, expr) + }); } - ExprKind::Closure(..) => visit::walk_expr(self, expr), - ExprKind::Gen(..) => { - self.with_label_rib(RibKind::FnOrCoroutine, |this| visit::walk_expr(this, expr)); + ExprKind::Gen(_, _, _, decl_span) => { + self.with_move_expr_scope(Some(decl_span), |this| { + this.with_label_rib(RibKind::FnOrCoroutine, |this| { + visit::walk_expr(this, expr) + }); + }); } ExprKind::Repeat(ref elem, ref ct) => { self.visit_expr(elem); self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes)); } ExprKind::ConstBlock(ref ct) => { - self.resolve_anon_const(ct, AnonConstKind::InlineConst); + self.with_move_expr_scope(None, |this| { + this.resolve_anon_const(ct, AnonConstKind::InlineConst); + }); } ExprKind::Index(ref elem, ref idx, _) => { self.resolve_expr(elem, Some(expr)); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 6182f64f63efd..7a7078deaadc4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -262,7 +262,10 @@ enum ResolutionError<'ra> { /// Error E0416: identifier is bound more than once in the same pattern. IdentifierBoundMoreThanOnceInSamePattern(Ident), /// Error E0426: use of undeclared label. - UndeclaredLabel { name: Symbol, suggestion: Option }, + UndeclaredLabel { + name: Symbol, + suggestion: Option, + }, /// Error E0433: failed to resolve. FailedToResolve { segment: Symbol, @@ -273,7 +276,9 @@ enum ResolutionError<'ra> { message: String, }, /// Error E0434: can't capture dynamic environment in a fn item. - CannotCaptureDynamicEnvironmentInFnItem { suggest_closure: bool }, + CannotCaptureDynamicEnvironmentInFnItem { + suggest_closure: bool, + }, /// Error E0435: attempt to use a non-constant value in a constant. AttemptToUseNonConstantValueInConstant { ident: Ident, @@ -296,7 +301,9 @@ enum ResolutionError<'ra> { // FIXME(generic_const_parameter_types): This should give custom output specifying it's only // problematic to use *forward declared* parameters when the feature is enabled. /// ERROR E0770: the type of const parameters must not depend on other generic parameters. - ParamInTyOfConstParam { name: Symbol }, + ParamInTyOfConstParam { + name: Symbol, + }, /// cannot use self in const param SelfInConstParam, /// generic parameters must not be used inside const evaluations. @@ -310,11 +317,18 @@ enum ResolutionError<'ra> { /// generic parameters must not be used inside enum discriminants. /// /// This error is emitted even with `generic_const_exprs`. - ParamInEnumDiscriminant { name: Symbol, param_kind: ParamKindInEnumDiscriminant }, + ParamInEnumDiscriminant { + name: Symbol, + param_kind: ParamKindInEnumDiscriminant, + }, /// Error E0735: generic parameters with a default cannot use `Self` ForwardDeclaredSelf(ForwardGenericParamBanReason), /// Error E0767: use of unreachable label - UnreachableLabel { name: Symbol, definition_span: Span, suggestion: Option }, + UnreachableLabel { + name: Symbol, + definition_span: Span, + suggestion: Option, + }, /// Error E0323, E0324, E0325: mismatch between trait item and impl item. TraitImplMismatch { name: Ident, @@ -339,6 +353,11 @@ enum ResolutionError<'ra> { LowercaseSelf, /// A never pattern has a binding. BindingInNeverPattern, + CannotUseInnerLocalInMoveExpr { + move_expr_span: Span, + ident: Ident, + scope_span: Span, + }, } #[derive(Debug)] diff --git a/compiler/rustc_target/src/spec/base/wasm.rs b/compiler/rustc_target/src/spec/base/wasm.rs index 1596100e629d7..dd5bcff87cde1 100644 --- a/compiler/rustc_target/src/spec/base/wasm.rs +++ b/compiler/rustc_target/src/spec/base/wasm.rs @@ -60,12 +60,23 @@ pub(crate) fn options() -> TargetOptions { max_atomic_width: Some(64), - // Unwinding doesn't work right now, so the whole target unconditionally - // defaults to panic=abort. Note that this is guaranteed to change in - // the future once unwinding is implemented. Don't rely on this as we're - // basically guaranteed to change it once WebAssembly supports - // exceptions. - panic_strategy: PanicStrategy::Abort, + // WebAssembly targets all started out originally as `-Cpanic=abort` + // since that was all that worked. Since then, however, the WebAssembly + // exception-handling proposal has been finalized/implemented and is now + // supported in both LLVM & rustc & libstd & co. The default still + // remains at `-Cpanic=abort` for now for historical compatibility, + // but `bootstrap.toml` can be used to configure a local build to + // use `-Cpanic=unwind` instead. This is used in CI, for example, to + // test wasm targets with `-Cpanic=unwind`. + // + // In the future this might change where preexisting targets migrate, + // but that's not going to be as easy as just changing this, so for now + // this is just a local build configuration option. + panic_strategy: if option_env!("CFG_WASM_PANIC_UNWIND_DEFAULT") == Some("1") { + PanicStrategy::Unwind + } else { + PanicStrategy::Abort + }, // Wasm doesn't have atomics yet, so tell LLVM that we're in a single // threaded model which will legalize atomics to normal operations. diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d5e01be7fe2c6..fb51dfabbef62 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -57,6 +57,35 @@ use crate::traits::{ }; impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + /// Checks for an explicit `Self: Trait` bound on an associated type impl. + fn is_explicit_self_trait_bound_on_impl_assoc_type( + &self, + body_def_id: LocalDefId, + cause_code: &ObligationCauseCode<'tcx>, + trait_def_id: DefId, + ) -> bool { + let ObligationCauseCode::WhereClause(item_def_id, span) = *cause_code.peel_derives() else { + return false; + }; + // Continue only if there is an impl associated type corresponding to the expected trait item. + if !self.tcx.opt_associated_item(body_def_id.to_def_id()).is_some_and(|assoc_item| { + assoc_item.trait_item_def_id().is_some_and(|trait_item_def_id| { + trait_item_def_id == item_def_id + && matches!(assoc_item.kind, ty::AssocKind::Type { .. }) + }) + }) { + return false; + } + + self.tcx.clauses_of(item_def_id).instantiate_own_identity().any(|(clause, clause_span)| { + clause_span == span + && clause.skip_norm_wip().as_trait_clause().is_some_and(|trait_pred| { + trait_pred.def_id() == trait_def_id + && trait_pred.skip_binder().self_ty().is_self_param() + }) + }) + } + /// The `root_obligation` parameter should be the `root_obligation` field /// from a `FulfillmentError`. If no `FulfillmentError` is available, /// then it should be the same as `obligation`. @@ -175,6 +204,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Err(guar) = leaf_trait_predicate.error_reported() { return guar; } + if self.is_explicit_self_trait_bound_on_impl_assoc_type( + obligation.cause.body_def_id, + obligation.cause.code(), + leaf_trait_predicate.def_id(), + ) && let ty::Param(param_ty) = + *leaf_trait_predicate.skip_binder().self_ty().kind() + { + span = param_ty.span_from_generics( + self.tcx, + obligation.cause.body_def_id.to_def_id(), + ); + } // Silence redundant errors on binding access that are already // reported on the binding definition (#56607). if let Err(guar) = self.fn_arg_obligation(&obligation) { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index bc39af3dc1c6e..5e8708c17a37a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4030,6 +4030,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && !bounds.iter() .filter_map(|bound| bound.trait_ref()) .any(|tr| tr.trait_def_id().is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Sized))) + // Only suggest relaxing the implicit `Sized` restriction if the + // failing obligation is that restriction. Relaxing it cannot + // satisfy an explicit where clause of the item, e.g. + // `type Assoc where Self: Sized;`. + && !generics.predicates.iter().any(|pred| { + pred.kind.in_where_clause() && pred.span.contains(span) + }) { let (span, separator) = if let [.., last] = bounds { (last.span().shrink_to_hi(), " +") diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 992c521261b5c..634a17dc372ef 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -350,19 +350,42 @@ impl<'tcx> BestObligation<'tcx> { alias: ty::AliasTerm<'tcx>, ) -> ControlFlow> { let tcx = goal.infcx().tcx; - let obligation = Obligation::new( - tcx, - self.obligation.cause.clone(), - goal.goal().param_env, - alias.trait_ref(tcx), - ); + + let trait_ref = alias.trait_ref(tcx); + let obligation = + Obligation::new(tcx, self.obligation.cause.clone(), goal.goal().param_env, trait_ref); + self.with_derived_obligation(obligation, |this| { goal.infcx().visit_proof_tree_at_depth( - goal.goal().with(tcx, alias.trait_ref(tcx)), + goal.goal().with(tcx, trait_ref), goal.depth() + 1, this, ) - }) + })?; + + let def_id = alias.expect_projection_def_id(); + + for (clause, span) in tcx.clauses_of(def_id).instantiate_own(tcx, alias.args) { + let clause = clause.skip_norm_wip(); + + let cause = ObligationCause::new( + self.obligation.cause.span, + self.obligation.cause.body_def_id, + ObligationCauseCode::WhereClause(def_id, span), + ); + + let obligation = Obligation::new(tcx, cause, goal.goal().param_env, clause); + + self.with_derived_obligation(obligation, |this| { + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(tcx, clause), + goal.depth() + 1, + this, + ) + })?; + } + + ControlFlow::Continue(()) } /// If we have no candidates, then it's likely that there is a diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs index a51af6345e205..1fe63070f1a15 100644 --- a/library/alloc/src/collections/linked_list/tests.rs +++ b/library/alloc/src/collections/linked_list/tests.rs @@ -304,6 +304,7 @@ fn test_clone_from() { #[test] #[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(target_os = "wasi", ignore)] fn test_send() { let n = list_from(&[1, 2, 3]); thread::spawn(move || { diff --git a/library/alloc/src/rcs/arc.rs b/library/alloc/src/rcs/arc.rs index b852891076e29..3ad02c09b428a 100644 --- a/library/alloc/src/rcs/arc.rs +++ b/library/alloc/src/rcs/arc.rs @@ -213,7 +213,7 @@ macro_rules! acquire { /// /// Sharing some immutable data between threads: /// -/// ``` +/// ```ignore-wasm /// use std::sync::Arc; /// use std::thread; /// @@ -232,7 +232,7 @@ macro_rules! acquire { /// /// [`AtomicUsize`]: core::sync::atomic::AtomicUsize "sync::atomic::AtomicUsize" /// -/// ``` +/// ```ignore-wasm /// use std::sync::Arc; /// use std::sync::atomic::{AtomicUsize, Ordering}; /// use std::thread; @@ -1091,7 +1091,7 @@ impl Arc { /// # Examples /// /// Minimal example demonstrating the guarantee that `Arc::into_inner` gives. - /// ``` + /// ```ignore-wasm /// use std::sync::Arc; /// /// let x = Arc::new(3); @@ -1114,7 +1114,7 @@ impl Arc { /// ``` /// /// A more practical example demonstrating the need for `Arc::into_inner`: - /// ``` + /// ```ignore-wasm /// use std::sync::Arc; /// /// // Definition of a simple singly linked list using `Arc`: diff --git a/library/alloctests/tests/sync.rs b/library/alloctests/tests/sync.rs index 5742855768c70..05f90a1a78cce 100644 --- a/library/alloctests/tests/sync.rs +++ b/library/alloctests/tests/sync.rs @@ -58,6 +58,7 @@ impl Drop for AllocCanary<'_> { #[test] #[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(target_os = "wasi", ignore)] fn manually_share_arc() { let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let arc_v = Arc::new(v); @@ -454,6 +455,7 @@ fn test_ptr_eq() { #[test] #[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(target_os = "wasi", ignore)] fn test_weak_count_locked() { let mut a = Arc::new(atomic::AtomicBool::new(false)); let a2 = a.clone(); diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 9e0238714da41..eea136c450121 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -616,10 +616,11 @@ pub fn run_test( ) -> Option> { let TestDescAndFn { desc, testfn } = test; - // Emscripten can catch panics but other wasm targets cannot + // Emscripten can catch panics, and test for `panic=unwind` on other wasm + // targets to see if they can catch panics. let ignore_because_no_process_support = desc.should_panic != ShouldPanic::No && (cfg!(target_family = "wasm") || cfg!(target_os = "zkvm")) - && !cfg!(target_os = "emscripten"); + && !(cfg!(target_os = "emscripten") || cfg!(panic = "unwind")); if force_ignore || desc.ignore || ignore_because_no_process_support { let message = CompletedTest::new(id, desc, TrIgnored, None, Vec::new()); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 3aded58123525..47d7056ad84f7 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1421,6 +1421,12 @@ fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelec cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "14"); } } + + // Plumb the `rust.wasm-panic-unwind-default` configuration option into the + // `rustc_target` crate. + if builder.config.wasm_panic_unwind_default { + cargo.env("CFG_WASM_PANIC_UNWIND_DEFAULT", "1"); + } } /// Pass down configuration from the LLVM build into the build of diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 1e58d86024874..3d03cc547ab75 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -348,6 +348,8 @@ pub(crate) struct Config { pub exec_ctx: ExecutionContext, pub wasm_proc_macros: bool, + + pub wasm_panic_unwind_default: bool, } impl Config { @@ -624,6 +626,7 @@ impl Config { rustflags: rust_rustflags, stdlib_semver_baseline: rust_stdlib_semver_baseline, wasm_proc_macros, + wasm_panic_unwind_default, } = toml_rust.unwrap_or_default(); let Llvm { @@ -1612,6 +1615,7 @@ NOTE: Please add `--stage 2` to your command line, or if you're sure you want to .unwrap_or(rust_debug == Some(true)), vendor, verbose_tests, + wasm_panic_unwind_default: wasm_panic_unwind_default.unwrap_or(false), wasm_proc_macros: wasm_proc_macros.unwrap_or(false), windows_rc: build_windows_rc.map(PathBuf::from), yarn: build_yarn.map(PathBuf::from), diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index 0c88a3d8d0172..7360d8553fb55 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -81,6 +81,7 @@ define_config! { parallel_frontend_threads: Option = "parallel-frontend-threads", stdlib_semver_baseline: Option = "stdlib-semver-baseline", wasm_proc_macros: Option = "wasm-proc-macros", + wasm_panic_unwind_default: Option = "wasm-panic-unwind-default", } } @@ -400,6 +401,7 @@ pub fn check_incompatible_options_for_ci_rustc( rustflags: _, stdlib_semver_baseline: _, wasm_proc_macros: _, + wasm_panic_unwind_default: _, } = ci_rust_config; // There are two kinds of checks for CI rustc incompatible options: diff --git a/src/bootstrap/src/core/session.rs b/src/bootstrap/src/core/session.rs index 1808f1b8855bc..df6c8b3958736 100644 --- a/src/bootstrap/src/core/session.rs +++ b/src/bootstrap/src/core/session.rs @@ -1197,7 +1197,7 @@ impl Session { } if target.starts_with("wasm") && target.contains("wasi") { - self.default_wasi_runner(target) + self.default_wasi_runner() } else { None } @@ -1206,7 +1206,7 @@ impl Session { /// When a `runner` configuration is not provided and a WASI-looking target /// is being tested this is consulted to prove the environment to see if /// there's a runtime already lying around that seems reasonable to use. - fn default_wasi_runner(&self, target: TargetSelection) -> Option { + fn default_wasi_runner(&self) -> Option { let mut finder = crate::core::sanity::Finder::new(); // Look for Wasmtime, and for its default options be sure to disable @@ -1215,19 +1215,10 @@ impl Session { if let Some(path) = finder.maybe_have("wasmtime") && let Ok(mut path) = path.into_os_string().into_string() { - path.push_str(" run -Wexceptions -C cache=n --dir ."); - // Make sure that tests have access to RUSTC_BOOTSTRAP. This (for example) is - // required for libtest to work on beta/stable channels. - // - // NB: with Wasmtime 20 this can change to `-S inherit-env` to - // inherit the entire environment rather than just this single - // environment variable. - path.push_str(" --env RUSTC_BOOTSTRAP"); - - if target.contains("wasip2") { - path.push_str(" --wasi inherit-network --wasi allow-ip-name-lookup"); - } - + path.push_str( + " run -C cache=n --dir . \ + --wasi inherit-env,inherit-network,allow-ip-name-lookup", + ); return Some(path); } diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index d753d16aff66c..6be97366544cf 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -79,7 +79,7 @@ RUN /tmp/build-fuchsia-toolchain.sh COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/ RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh -RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-34/wasi-sdk-34.0-x86_64-linux.tar.gz | \ +RUN curl -L https://ci-mirrors.rust-lang.org/rustc/wasi-sdk-34.0-x86_64-linux.tar.gz | \ tar -xz ENV WASI_SDK_PATH=/tmp/wasi-sdk-34.0-x86_64-linux diff --git a/src/ci/docker/host-x86_64/test-pr-check-2/Dockerfile b/src/ci/docker/host-x86_64/test-pr-check-2/Dockerfile index 0a9b6f0fda91c..ac690d0bbdc08 100644 --- a/src/ci/docker/host-x86_64/test-pr-check-2/Dockerfile +++ b/src/ci/docker/host-x86_64/test-pr-check-2/Dockerfile @@ -21,7 +21,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ mingw-w64 \ && rm -rf /var/lib/apt/lists/* -RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-34/wasi-sdk-34.0-x86_64-linux.tar.gz | \ +RUN curl -L https://ci-mirrors.rust-lang.org/rustc/wasi-sdk-34.0-x86_64-linux.tar.gz | \ tar -xz ENV WASI_SDK_PATH=/wasi-sdk-34.0-x86_64-linux @@ -34,9 +34,9 @@ ENV SCRIPT="python3 ../x.py check && \ python3 ../x.py clippy ci --stage 2 && \ python3 ../x.py test --stage 1 core alloc std test proc_macro && \ # Elsewhere, we run all tests for the host. A number of codegen tests are sensitive to the target pointer - # width, for example because they mention a usize. wasm32-wasip1 in test-various, so using it here can't make + # width, for example because they mention a usize. wasm32-wasip3 in test-various, so using it here can't make # PR CI more strict than full CI. - python3 ../x.py test --stage 1 tests/codegen-llvm --target wasm32-wasip1 && \ + python3 ../x.py test --stage 1 tests/codegen-llvm --target wasm32-wasip3 && \ python3 ../x.py test --stage 1 src/tools/compiletest && \ python3 ../x.py doc bootstrap --stage 1 && \ # Build both public and internal documentation. diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index 6034f3d1d883c..3136e38da5a43 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -43,12 +43,13 @@ WORKDIR / COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-34/wasi-sdk-34.0-x86_64-linux.tar.gz | \ +RUN curl -L https://ci-mirrors.rust-lang.org/rustc/wasi-sdk-34.0-x86_64-linux.tar.gz | \ tar -xz ENV WASI_SDK_PATH=/wasi-sdk-34.0-x86_64-linux ENV RUST_CONFIGURE_ARGS="--musl-root-x86_64=/usr/local/x86_64-linux-musl \ - --set rust.lld" + --set rust.lld \ + --set rust.wasm-panic-unwind-default" # Some run-make tests have assertions about code size, and enabling debug # assertions in libstd causes the binary to be much bigger than it would @@ -57,11 +58,11 @@ ENV RUST_CONFIGURE_ARGS="--musl-root-x86_64=/usr/local/x86_64-linux-musl \ ENV NO_DEBUG_ASSERTIONS=1 ENV NO_OVERFLOW_CHECKS=1 -RUN curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v44.0.1/wasmtime-v44.0.1-x86_64-linux.tar.xz | \ +RUN curl -L https://ci-mirrors.rust-lang.org/rustc/wasmtime-v48.0.2-x86_64-linux.tar.xz | \ tar -xJ -ENV PATH="$PATH:/wasmtime-v44.0.1-x86_64-linux" +ENV PATH="$PATH:/wasmtime-v48.0.2-x86_64-linux" -ENV WASM_WASIP_TARGET=wasm32-wasip1 +ENV WASM_WASIP_TARGET=wasm32-wasip3 ENV WASM_WASIP_SCRIPT="python3 /checkout/x.py --stage 2 test --host= --target $WASM_WASIP_TARGET \ tests/run-make \ tests/run-make-cargo \ @@ -70,7 +71,8 @@ ENV WASM_WASIP_SCRIPT="python3 /checkout/x.py --stage 2 test --host= --target $W tests/codegen-units \ tests/codegen-llvm \ tests/assembly-llvm \ - library/core" + library/core \ + library/alloc" ENV NVPTX_TARGETS=nvptx64-nvidia-cuda ENV NVPTX_SCRIPT="python3 /checkout/x.py --stage 2 test --host= --target $NVPTX_TARGETS \ diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 556a922f7044c..d23e9a8ca456a 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -17,7 +17,7 @@ use rustc_hir_pretty::PpAnn; use rustc_metadata::rendered_const; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::ModId; -use rustc_span::{Pos, Symbol, bug, kw, sym}; +use rustc_span::{Pos, RemapPathScopeComponents, Symbol, bug, kw, sym}; use rustdoc_json_types::*; use crate::clean::{self, ItemId}; @@ -191,17 +191,14 @@ impl FromClean for Option { fn from_clean(span: &clean::Span, renderer: &JsonRenderer<'_>) -> Self { match span.filename(renderer.sess()) { rustc_span::FileName::Real(name) => { - if let Some(local_path) = name.into_local_path() { - let hi = span.hi(renderer.sess()); - let lo = span.lo(renderer.sess()); - Some(Span { - filename: local_path, - begin: (lo.line, lo.col.to_usize() + 1), - end: (hi.line, hi.col.to_usize() + 1), - }) - } else { - None - } + let filename = name.path(RemapPathScopeComponents::DOCUMENTATION); + let hi = span.hi(renderer.sess()); + let lo = span.lo(renderer.sess()); + Some(Span { + filename: filename.to_path_buf(), + begin: (lo.line, lo.col.to_usize() + 1), + end: (hi.line, hi.col.to_usize() + 1), + }) } _ => None, } diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 732f4ab275dd7..520a5468e45f0 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -273,7 +273,6 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-wasm32", "only-wasm32-unknown-emscripten", "only-wasm32-unknown-unknown", - "only-wasm32-wasip1", "only-watchos", "only-windows", "only-windows-gnu", diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 0e1310862589d..2f503aaec5f92 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -18,7 +18,7 @@ regex = "1.11" serde_json = "1.0" similar = "2.7" tempfile = "3" -wasmparser = { version = "0.247", default-features = false, features = ["std", "features", "validate"] } +wasmparser = { version = "0.247", default-features = false, features = ["std", "features", "validate", "component-model"] } # tidy-alphabetical-end # Shared with bootstrap and compiletest diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index b9717bda1e2c7..f800dd61e47d6 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -22,6 +22,7 @@ pub mod scoped_run; pub mod string; pub mod symbols; pub mod targets; +pub mod wasm; // Internally we call our fs-related support module as `fs`, but re-export its content as `rfs` // to tests to avoid colliding with commonly used `use std::fs;`. diff --git a/src/tools/run-make-support/src/wasm.rs b/src/tools/run-make-support/src/wasm.rs new file mode 100644 index 0000000000000..16395ab6c90b1 --- /dev/null +++ b/src/tools/run-make-support/src/wasm.rs @@ -0,0 +1,52 @@ +//! Wasm-specific helpers for various tests + +use wasmparser::{Parser, Payload}; + +use crate::{Rustc, target}; + +/// Returns whether the current compilation target will emit a WebAssembly +/// component. +pub fn target_emits_components() -> bool { + let target = target(); + if target.contains("wasi") { + return !target.contains("wasip1"); + } + if target.contains("component") { + return true; + } + return false; +} + +/// Helper methods for the `Rustc` type. +impl Rustc { + /// Helper to emit a core module for this wasm target, skipping the + /// component output part of compilation. + pub fn emit_wasm_core_module(&mut self) -> &mut Self { + if target_emits_components() { + self.arg("-Clink-arg=--skip-wit-component"); + } + self + } +} + +/// Returns the size, in bytes, of the wasm module in `bytes`. +/// +/// This excludes custom sections to avoid counting easily strippable sections +/// such as debuginfo. +pub fn wasm_binary_size(bytes: &[u8]) -> usize { + let mut size = 0; + for payload in Parser::new(0).parse_all(bytes) { + let payload = payload.unwrap(); + match payload { + // Don't count the size of custom sections as they're easily + // stripped, and don't double-count modules since this'll recurse + // into module. + Payload::CustomSection { .. } | Payload::ModuleSection { .. } => continue, + _ => {} + } + if let Some((_, range)) = payload.as_section() { + size += range.len(); + } + } + size +} diff --git a/tests/assembly-llvm/wasm_exceptions.rs b/tests/assembly-llvm/wasm_exceptions.rs index 910e508b86f65..89ff390f3c082 100644 --- a/tests/assembly-llvm/wasm_exceptions.rs +++ b/tests/assembly-llvm/wasm_exceptions.rs @@ -32,7 +32,6 @@ pub fn test_cleanup() { may_panic(); } - // CHECK-NOT: call // CHECK: try_table (catch_all_ref 0) // CHECK: call may_panic // CHECK: end_try_table @@ -56,7 +55,6 @@ pub fn test_rtry() { ); } - // CHECK-NOT: call // CHECK: try_table (catch __cpp_exception 0) // CHECK: call may_panic // CHECK: end_try_table diff --git a/tests/assembly-llvm/wasm_legacy_eh.rs b/tests/assembly-llvm/wasm_legacy_eh.rs index 89388bfec1d5f..fd5b84eee7c9b 100644 --- a/tests/assembly-llvm/wasm_legacy_eh.rs +++ b/tests/assembly-llvm/wasm_legacy_eh.rs @@ -42,7 +42,6 @@ pub fn test_cleanup() { // CHECK-NOT: try_table // CHECK-NOT: catch_all_ref // CHECK-NOT: throw_ref - // CHECK-NOT: call // CHECK: try // CHECK: call may_panic // CHECK: catch_all @@ -69,7 +68,6 @@ pub fn test_rtry() { // CHECK-NOT: try_table // CHECK-NOT: catch_all_ref // CHECK-NOT: throw_ref - // CHECK-NOT: call // CHECK: try // CHECK: call may_panic // CHECK: catch diff --git a/tests/codegen-llvm/double_panic_wasm.rs b/tests/codegen-llvm/double_panic_wasm.rs index 1eafe60503809..e69066b8ddece 100644 --- a/tests/codegen-llvm/double_panic_wasm.rs +++ b/tests/codegen-llvm/double_panic_wasm.rs @@ -21,7 +21,7 @@ impl Drop for PanicOnDrop { // CHECK-LABEL: @double_panic // CHECK: invoke void @may_panic() -// CHECK: invoke void @{{.+}}drop_in_place{{.+}} +// CHECK: invoke void @{{.+}}drop_glue{{.+}} // CHECK: unwind label %[[TERMINATE:.*]] // // CHECK: [[TERMINATE]]: diff --git a/tests/codegen-llvm/personality_lifetimes.rs b/tests/codegen-llvm/personality_lifetimes.rs index cd81db6395349..9d587961cbeef 100644 --- a/tests/codegen-llvm/personality_lifetimes.rs +++ b/tests/codegen-llvm/personality_lifetimes.rs @@ -1,4 +1,5 @@ //@ ignore-msvc +//@ ignore-wasm //@ needs-unwind //@ compile-flags: -Copt-level=3 -C no-prepopulate-passes diff --git a/tests/codegen-llvm/wasm_custom_section.rs b/tests/codegen-llvm/wasm_custom_section.rs index 7e111c6acc352..4e9bed0ec66d7 100644 --- a/tests/codegen-llvm/wasm_custom_section.rs +++ b/tests/codegen-llvm/wasm_custom_section.rs @@ -11,9 +11,9 @@ static FOO: [u8; 22] = *b"custom section content"; // Data segment in foo section -// CHECK: @FOO = dso_local constant [22 x i8] c"custom section content", section "foo" +// CHECK: @FOO = {{.*}}constant [22 x i8] c"custom section content", section "foo" // CHECK: @llvm.used = appending global [1 x ptr] [ptr @FOO], section "llvm.metadata" // Custom section -// CHECK: !wasm.custom_sections = !{!3} -// CHECK: !3 = !{!"foo", !"custom section content"} +// CHECK: !wasm.custom_sections = !{![[ID:[0-9]+]]} +// CHECK: ![[ID]] = !{!"foo", !"custom section content"} diff --git a/tests/codegen-llvm/wasm_exceptions.rs b/tests/codegen-llvm/wasm_exceptions.rs index b4c024e4ed0e6..e586f5b111253 100644 --- a/tests/codegen-llvm/wasm_exceptions.rs +++ b/tests/codegen-llvm/wasm_exceptions.rs @@ -1,5 +1,6 @@ //@ only-wasm32 //@ revisions: WASM WASMEXN +//@ [WASM] compile-flags: -C panic=abort //@ [WASMEXN] compile-flags: -C panic=unwind #![crate_type = "lib"] diff --git a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs index 420cf0e48e402..308733f0b4333 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs @@ -11,14 +11,21 @@ // FIXME: Once GCC backend is fixed, remove this `ignore-backends`. //@ ignore-backends: gcc -use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name}; +use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name, target}; fn main() { rustc().edition("2021").input("checkrust.rs").run(); - cc().input("test.c") - .input(static_lib_name("checkrust")) - .out_exe("test") - .args(extra_c_flags()) - .run(); + let mut cmd = cc(); + cmd.input("test.c").input(static_lib_name("checkrust")).out_exe("test").args(extra_c_flags()); + + // Wasm targets with `-Cpanic=unwind` are a bit nonstandard right now and + // require some extra flags. + if target().contains("wasm") + && !rustc().arg("--print=cfg").run().stdout_utf8().contains("abort") + { + cmd.arg("-lunwind").arg("-fwasm-exceptions").arg("-Wl,--export-if-defined=cabi_realloc"); + } + cmd.run(); + run("test"); } diff --git a/tests/run-make/complex-abi/rmake.rs b/tests/run-make/complex-abi/rmake.rs index 4836e72717513..175cd47e1300b 100644 --- a/tests/run-make/complex-abi/rmake.rs +++ b/tests/run-make/complex-abi/rmake.rs @@ -5,10 +5,14 @@ //@ ignore-pauthtest: (it requires non-trivial compilation of c sources, and only supports dynamic // linking, ignore the test). -use run_make_support::{bin_name, build_native_static_lib, env_var, run, rustc}; +use run_make_support::{bin_name, build_native_static_lib, env_var, run, rustc, target}; fn main() { build_native_static_lib("test"); - rustc().linker(&env_var("CC")).input("main.rs").run(); + let mut cmd = rustc(); + if !target().contains("wasm") { + cmd.linker(&env_var("CC")); + } + cmd.input("main.rs").run(); run(&bin_name("main")); } diff --git a/tests/run-make/remap-path-prefix-doctest-panic/rmake.rs b/tests/run-make/remap-path-prefix-doctest-panic/rmake.rs new file mode 100644 index 0000000000000..31088dc5fe7a3 --- /dev/null +++ b/tests/run-make/remap-path-prefix-doctest-panic/rmake.rs @@ -0,0 +1,59 @@ +// Checks that the location printed by a panicking doctest is remapped +// according to `--remap-path-scope`. +// +// Only the lines between the start of the stack backtrace and the end are +// are inspected, so timings, temp dirs and backtraces can't leak into the check. + +//@ ignore-cross-compile + +use std::path::Path; + +use run_make_support::assertion_helpers::{assert_contains, assert_not_contains}; +use run_make_support::rustdoc; + +/// Runs the failing doctest and returns stdout. +fn panic_file(scope: Option<&str>) -> String { + let mut cmd = rustdoc(); + cmd.input("src/doctest.rs") + .arg("--test") + .arg("--remap-path-prefix=src=/REMAPPED") + .arg("-Cdebuginfo=1") + .arg("--edition=2015") + .env("RUST_BACKTRACE", "1"); + + if let Some(scope) = scope { + cmd.arg(format!("--remap-path-scope={scope}")).arg("-Zunstable-options"); + } + + let out = cmd.run_fail(); + out.assert_stdout_contains("explicit panic"); + + let stdout = out.stdout_utf8(); + let section: Vec<&str> = stdout + .lines() + .skip_while(|l| l.trim() != "stack backtrace:") + .skip(1) + .take_while(|l| l.trim() != "failures:") + .collect(); + + assert!(!section.is_empty(), "no backtrace found in output:\n{stdout}"); + section.join("\n") +} + +fn main() { + let expected_remapped = Path::new("/REMAPPED").join("doctest.rs").to_string_lossy().to_string(); + let expected_unremapped = Path::new("src").join("doctest.rs").to_string_lossy().to_string(); + + // Check that with debuginfo (and related) we get the remapped path + for scope in [Some("debuginfo"), Some("object"), Some("all"), None] { + let stdout = panic_file(scope); + assert_contains(&stdout, &expected_remapped); + assert_not_contains(&stdout, &expected_unremapped); + } + + for scope in ["diagnostics", "documentation", "macro"] { + let stdout = panic_file(Some(scope)); + assert_contains(&stdout, &expected_unremapped); + assert_not_contains(&stdout, &expected_remapped); + } +} diff --git a/tests/run-make/remap-path-prefix-doctest-panic/src/doctest.rs b/tests/run-make/remap-path-prefix-doctest-panic/src/doctest.rs new file mode 100644 index 0000000000000..2160cc21f6b42 --- /dev/null +++ b/tests/run-make/remap-path-prefix-doctest-panic/src/doctest.rs @@ -0,0 +1,4 @@ +/// ``` +/// panic!() +/// ``` +pub fn f() {} diff --git a/tests/run-make/wasm-custom-section/rmake.rs b/tests/run-make/wasm-custom-section/rmake.rs index ff4c29a9d3090..429b85e51e243 100644 --- a/tests/run-make/wasm-custom-section/rmake.rs +++ b/tests/run-make/wasm-custom-section/rmake.rs @@ -1,12 +1,12 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 use std::collections::HashMap; use run_make_support::{rfs, rustc, wasmparser}; fn main() { - rustc().input("foo.rs").target("wasm32-wasip1").run(); - rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); + rustc().input("foo.rs").run(); + rustc().input("bar.rs").arg("-Clto").opt().run(); let file = rfs::read("bar.wasm"); @@ -14,8 +14,7 @@ fn main() { for payload in wasmparser::Parser::new(0).parse_all(&file) { let payload = payload.unwrap(); if let wasmparser::Payload::CustomSection(s) = payload { - let prev = custom.insert(s.name(), s.data()); - assert!(prev.is_none()); + custom.insert(s.name(), s.data()); } } diff --git a/tests/run-make/wasm-custom-sections-opt/rmake.rs b/tests/run-make/wasm-custom-sections-opt/rmake.rs index 063a4f2257c80..c718ba0b7adbc 100644 --- a/tests/run-make/wasm-custom-sections-opt/rmake.rs +++ b/tests/run-make/wasm-custom-sections-opt/rmake.rs @@ -1,4 +1,4 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 use std::collections::HashMap; use std::path::Path; @@ -6,7 +6,7 @@ use std::path::Path; use run_make_support::{rfs, rustc, wasmparser}; fn main() { - rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); + rustc().input("foo.rs").opt().run(); verify(Path::new("foo.wasm")); } @@ -19,8 +19,7 @@ fn verify(path: &Path) { for payload in wasmparser::Parser::new(0).parse_all(&file) { let payload = payload.unwrap(); if let wasmparser::Payload::CustomSection(s) = payload { - let prev = custom.insert(s.name(), s.data()); - assert!(prev.is_none()); + custom.insert(s.name(), s.data()); } } diff --git a/tests/run-make/wasm-export-all-symbols/rmake.rs b/tests/run-make/wasm-export-all-symbols/rmake.rs index 58abfb996461e..3916c81363f9d 100644 --- a/tests/run-make/wasm-export-all-symbols/rmake.rs +++ b/tests/run-make/wasm-export-all-symbols/rmake.rs @@ -1,4 +1,4 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 use std::collections::HashMap; use std::path::Path; @@ -15,9 +15,9 @@ fn main() { fn test(args: &[&str]) { eprintln!("running with {args:?}"); - rustc().input("bar.rs").target("wasm32-wasip1").args(args).run(); - rustc().input("foo.rs").target("wasm32-wasip1").args(args).run(); - rustc().input("main.rs").target("wasm32-wasip1").args(args).run(); + rustc().input("bar.rs").args(args).run(); + rustc().input("foo.rs").args(args).emit_wasm_core_module().run(); + rustc().input("main.rs").args(args).emit_wasm_core_module().run(); verify_exports( Path::new("foo.wasm"), @@ -25,13 +25,7 @@ fn test(args: &[&str]) { ); verify_exports( Path::new("main.wasm"), - &[ - ("foo", Func), - ("FOO", Global), - ("_start", Func), - ("__main_void", Func), - ("memory", Memory), - ], + &[("foo", Func), ("FOO", Global), ("__main_void", Func), ("memory", Memory)], ); } @@ -44,7 +38,16 @@ fn verify_exports(path: &Path, exports: &[(&str, wasmparser::ExternalKind)]) { if let wasmparser::Payload::ExportSection(s) = payload { for export in s { let export = export.unwrap(); - wasm_exports.insert(export.name, export.kind); + match export.name { + "__wasm_task_hook" + | "cabi_realloc" + | "__indirect_function_table" + | "_start" => {} + name if name.starts_with("wasi:") => {} + other => { + wasm_exports.insert(other, export.kind); + } + } } } } diff --git a/tests/run-make/wasm-import-module/rmake.rs b/tests/run-make/wasm-import-module/rmake.rs index 77614ce1ceb86..8cafd0ad20d25 100644 --- a/tests/run-make/wasm-import-module/rmake.rs +++ b/tests/run-make/wasm-import-module/rmake.rs @@ -1,4 +1,4 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 use std::collections::HashMap; @@ -6,8 +6,8 @@ use run_make_support::{rfs, rustc, wasmparser}; use wasmparser::TypeRef::Func; fn main() { - rustc().input("foo.rs").target("wasm32-wasip1").run(); - rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); + rustc().input("foo.rs").run(); + rustc().input("bar.rs").emit_wasm_core_module().arg("-Clto").opt().run(); let file = rfs::read("bar.wasm"); diff --git a/tests/run-make/wasm-panic-small/rmake.rs b/tests/run-make/wasm-panic-small/rmake.rs index 64c17571437c5..946d6ca625b72 100644 --- a/tests/run-make/wasm-panic-small/rmake.rs +++ b/tests/run-make/wasm-panic-small/rmake.rs @@ -1,7 +1,7 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 #![deny(warnings)] -use run_make_support::{rfs, rustc}; +use run_make_support::{rfs, rustc, wasm}; fn main() { test("a"); @@ -15,18 +15,15 @@ fn test(cfg: &str) { rustc() .input("foo.rs") - .target("wasm32-wasip1") .arg("-Clto") + .arg("-Cpanic=abort") .arg("-Cstrip=debuginfo") .opt() .cfg(cfg) .run(); let bytes = rfs::read("foo.wasm"); - println!("{}", bytes.len()); - assert!( - bytes.len() < 50_000, - "wasm binary was larger than expected. size in bytes: {}", - bytes.len() - ); + let size = wasm::wasm_binary_size(&bytes); + println!("{size}"); + assert!(size < 60_000, "bytes len was: {size}"); } diff --git a/tests/run-make/wasm-spurious-import/main.rs b/tests/run-make/wasm-spurious-import/main.rs index fcbead5e28bd2..a83f3e2326e94 100644 --- a/tests/run-make/wasm-spurious-import/main.rs +++ b/tests/run-make/wasm-spurious-import/main.rs @@ -12,3 +12,12 @@ pub fn multer(a: i128, b: i128) -> i128 { // panic function in case of a bug. We verify that no imports exist in our verifier. a * b } + +#[cfg(target_env = "p3")] +#[no_mangle] +pub extern "C" fn __wasm_task_hook(_: u32) {} +#[cfg(target_env = "p3")] +#[no_mangle] +pub extern "C" fn cabi_realloc(_: *mut u8, _: usize, _: usize, _: usize) -> *mut u8 { + loop {} +} diff --git a/tests/run-make/wasm-spurious-import/rmake.rs b/tests/run-make/wasm-spurious-import/rmake.rs index 435c6219aa502..e6e8a4dfc4104 100644 --- a/tests/run-make/wasm-spurious-import/rmake.rs +++ b/tests/run-make/wasm-spurious-import/rmake.rs @@ -1,4 +1,4 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 use std::collections::HashMap; @@ -7,11 +7,11 @@ use run_make_support::{rfs, rustc, wasmparser}; fn main() { rustc() .input("main.rs") - .target("wasm32-wasip1") .arg("-Coverflow-checks") .arg("-Cpanic=abort") .arg("-Clto") .arg("-Copt-level=z") + .emit_wasm_core_module() .run(); let file = rfs::read("main.wasm"); @@ -22,6 +22,10 @@ fn main() { if let wasmparser::Payload::ImportSection(s) = payload { for i in s.into_imports() { let i = i.unwrap(); + // ignore intrinsics like `__wasm_{get,set}_stack_pointer` + if i.name.starts_with("__wasm_") { + continue; + } imports.entry(i.module).or_insert(Vec::new()).push((i.name, i.ty)); } } diff --git a/tests/run-make/wasm-stringify-ints-small/rmake.rs b/tests/run-make/wasm-stringify-ints-small/rmake.rs index c0448c59c037b..060fe578d5c2d 100644 --- a/tests/run-make/wasm-stringify-ints-small/rmake.rs +++ b/tests/run-make/wasm-stringify-ints-small/rmake.rs @@ -1,18 +1,13 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 #![deny(warnings)] -use run_make_support::{rfs, rustc}; +use run_make_support::{rfs, rustc, wasm}; fn main() { - rustc() - .input("foo.rs") - .target("wasm32-wasip1") - .arg("-Clto") - .arg("-Cstrip=debuginfo") - .opt() - .run(); + rustc().input("foo.rs").arg("-Clto").emit_wasm_core_module().opt().run(); let bytes = rfs::read("foo.wasm"); - println!("{}", bytes.len()); - assert!(bytes.len() < 50_000); + let size = wasm::wasm_binary_size(&bytes); + println!("{size}"); + assert!(size < 75_000); } diff --git a/tests/run-make/wasm-symbols-different-module/rmake.rs b/tests/run-make/wasm-symbols-different-module/rmake.rs index 0e7113c3df8f9..8c8b6f21b2014 100644 --- a/tests/run-make/wasm-symbols-different-module/rmake.rs +++ b/tests/run-make/wasm-symbols-different-module/rmake.rs @@ -1,4 +1,4 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 use std::collections::{HashMap, HashSet}; use std::path::Path; @@ -22,7 +22,7 @@ fn test_file(file: &str, expected_imports: &[(&str, &[&str])]) { fn test(file: &str, args: &[&str], expected_imports: &[(&str, &[&str])]) { println!("test {file:?} {args:?} for {expected_imports:?}"); - rustc().input(file).target("wasm32-wasip1").args(args).run(); + rustc().input(file).emit_wasm_core_module().args(args).run(); let file = rfs::read(Path::new(file).with_extension("wasm")); @@ -32,6 +32,11 @@ fn test(file: &str, args: &[&str], expected_imports: &[(&str, &[&str])]) { if let wasmparser::Payload::ImportSection(s) = payload { for i in s.into_imports() { let i = i.unwrap(); + // Ignore intrinsics like `__wasm_{get,set}_stack_pointer` as + // well as standard library dependencies + if i.name.starts_with("__wasm_") || i.module.starts_with("wasi:") { + continue; + } imports.entry(i.module).or_insert(HashSet::new()).insert(i.name); } } diff --git a/tests/run-make/wasm-symbols-not-exported/bar.rs b/tests/run-make/wasm-symbols-not-exported/bar.rs index dd4d14416e70e..79d0fb4bf0def 100644 --- a/tests/run-make/wasm-symbols-not-exported/bar.rs +++ b/tests/run-make/wasm-symbols-not-exported/bar.rs @@ -1,4 +1,4 @@ -#![feature(panic_handler, alloc_error_handler)] +#![feature(alloc_error_handler)] #![crate_type = "cdylib"] #![no_std] @@ -32,3 +32,12 @@ fn a(_: core::alloc::Layout) -> ! { fn b(_: &core::panic::PanicInfo) -> ! { loop {} } + +#[cfg(target_env = "p3")] +#[no_mangle] +pub extern "C" fn __wasm_task_hook(_: u32) {} +#[cfg(target_env = "p3")] +#[no_mangle] +pub extern "C" fn cabi_realloc(_: *mut u8, _: usize, _: usize, _: usize) -> *mut u8 { + loop {} +} diff --git a/tests/run-make/wasm-symbols-not-exported/rmake.rs b/tests/run-make/wasm-symbols-not-exported/rmake.rs index 62da63db26dbf..de8852439a00f 100644 --- a/tests/run-make/wasm-symbols-not-exported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-exported/rmake.rs @@ -1,18 +1,18 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 use std::path::Path; use run_make_support::{rfs, rustc, wasmparser}; fn main() { - rustc().input("foo.rs").target("wasm32-wasip1").run(); + rustc().input("foo.rs").emit_wasm_core_module().run(); verify_symbols(Path::new("foo.wasm")); - rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); + rustc().input("foo.rs").emit_wasm_core_module().opt().run(); verify_symbols(Path::new("foo.wasm")); - rustc().input("bar.rs").target("wasm32-wasip1").run(); + rustc().input("bar.rs").emit_wasm_core_module().arg("-Cpanic=abort").run(); verify_symbols(Path::new("bar.wasm")); - rustc().input("bar.rs").target("wasm32-wasip1").opt().run(); + rustc().input("bar.rs").emit_wasm_core_module().arg("-Cpanic=abort").opt().run(); verify_symbols(Path::new("bar.wasm")); } @@ -28,7 +28,11 @@ fn verify_symbols(path: &Path) { if e.kind != wasmparser::ExternalKind::Func { continue; } - if e.name == "foo" || e.name == "_initialize" { + if e.name == "foo" + || e.name == "_initialize" + || e.name == "__wasm_task_hook" + || e.name == "cabi_realloc" + { continue; } panic!("unexpected export {e:?}"); diff --git a/tests/run-make/wasm-symbols-not-imported/foo.rs b/tests/run-make/wasm-symbols-not-imported/foo.rs index 6af8d50a2ace2..187d8434b8572 100644 --- a/tests/run-make/wasm-symbols-not-imported/foo.rs +++ b/tests/run-make/wasm-symbols-not-imported/foo.rs @@ -12,3 +12,12 @@ pub extern "C" fn foo() { fn panic(_info: &PanicInfo) -> ! { loop {} } + +#[cfg(target_env = "p3")] +#[no_mangle] +pub extern "C" fn __wasm_task_hook(_: u32) {} +#[cfg(target_env = "p3")] +#[no_mangle] +pub extern "C" fn cabi_realloc(_: *mut u8, _: usize, _: usize, _: usize) -> *mut u8 { + loop {} +} diff --git a/tests/run-make/wasm-symbols-not-imported/rmake.rs b/tests/run-make/wasm-symbols-not-imported/rmake.rs index fc22e31356aaf..e2e06ed31abf4 100644 --- a/tests/run-make/wasm-symbols-not-imported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-imported/rmake.rs @@ -1,17 +1,17 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 use std::path::Path; use run_make_support::{rfs, rustc, wasmparser}; fn main() { - rustc().input("foo.rs").target("wasm32-wasip1").run(); + rustc().input("foo.rs").emit_wasm_core_module().arg("-Cpanic=abort").run(); verify_symbols(Path::new("foo.wasm")); - rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").run(); + rustc().input("foo.rs").emit_wasm_core_module().arg("-Cpanic=abort").arg("-Clto").run(); verify_symbols(Path::new("foo.wasm")); - rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); + rustc().input("foo.rs").emit_wasm_core_module().arg("-Cpanic=abort").opt().run(); verify_symbols(Path::new("foo.wasm")); - rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); + rustc().input("foo.rs").emit_wasm_core_module().arg("-Cpanic=abort").arg("-Clto").opt().run(); verify_symbols(Path::new("foo.wasm")); } @@ -21,8 +21,13 @@ fn verify_symbols(path: &Path) { for payload in wasmparser::Parser::new(0).parse_all(&file) { let payload = payload.unwrap(); - if let wasmparser::Payload::ImportSection(_) = payload { - panic!("import section found"); + if let wasmparser::Payload::ImportSection(i) = payload { + for import in i.into_imports() { + let import = import.unwrap(); + if !import.name.starts_with("__wasm_") { + panic!("unexpected import: {import:?}"); + } + } } } } diff --git a/tests/rustdoc-json/README.md b/tests/rustdoc-json/README.md new file mode 100644 index 0000000000000..875a149585010 --- /dev/null +++ b/tests/rustdoc-json/README.md @@ -0,0 +1,7 @@ +## `tests/rustdoc-json/remap-path-prefix` + +Tests for `--remap-path-prefix` and `--remap-path-scope` with rustdoc JSON: + - `remap-path-prefix`: only uses bare `--remap-path-prefix`, expects remapped paths + - `doc`: pass `--remap-path-prefix` and the `documentation` scope, expects remapped paths + - `object`: pass `--remap-path-prefix` and the `object` scope, expects un-remapped paths + - `debuginfo`: pass `--remap-path-prefix` and the `debuginfo` scope, expects un-remapped paths diff --git a/tests/rustdoc-json/remap-path-prefix/debuginfo.rs b/tests/rustdoc-json/remap-path-prefix/debuginfo.rs new file mode 100644 index 0000000000000..d378dca22be58 --- /dev/null +++ b/tests/rustdoc-json/remap-path-prefix/debuginfo.rs @@ -0,0 +1,5 @@ +//@ compile-flags: --remap-path-prefix={{src-base}}=/remapped +//@ compile-flags: --remap-path-scope=debuginfo -Zunstable-options + +//@ is "$.index[?(@.name=='StrLike')].span.filename" $FILE +pub trait StrLike {} diff --git a/tests/rustdoc-json/remap-path-prefix/diag.rs b/tests/rustdoc-json/remap-path-prefix/diag.rs new file mode 100644 index 0000000000000..79b469c40084e --- /dev/null +++ b/tests/rustdoc-json/remap-path-prefix/diag.rs @@ -0,0 +1,5 @@ +//@ compile-flags: --remap-path-prefix={{src-base}}=/remapped +//@ compile-flags: --remap-path-scope=diagnostics -Zunstable-options + +//@ is "$.index[?(@.name=='StrLike')].span.filename" $FILE +pub trait StrLike {} diff --git a/tests/rustdoc-json/remap-path-prefix/doc.rs b/tests/rustdoc-json/remap-path-prefix/doc.rs new file mode 100644 index 0000000000000..aa3d13255753e --- /dev/null +++ b/tests/rustdoc-json/remap-path-prefix/doc.rs @@ -0,0 +1,6 @@ +//@ ignore-windows +//@ compile-flags: --remap-path-prefix={{src-base}}=/remapped +//@ compile-flags: --remap-path-scope=documentation -Zunstable-options + +//@ is "$.index[?(@.name=='StrLike')].span.filename" \"/remapped/remap-path-prefix/doc.rs\" +pub trait StrLike {} diff --git a/tests/rustdoc-json/remap-path-prefix/object.rs b/tests/rustdoc-json/remap-path-prefix/object.rs new file mode 100644 index 0000000000000..052ad7651eeab --- /dev/null +++ b/tests/rustdoc-json/remap-path-prefix/object.rs @@ -0,0 +1,5 @@ +//@ compile-flags: --remap-path-prefix={{src-base}}=/remapped +//@ compile-flags: --remap-path-scope=object -Zunstable-options + +//@ is "$.index[?(@.name=='StrLike')].span.filename" $FILE +pub trait StrLike {} diff --git a/tests/rustdoc-json/remap-path-prefix/remap-path-prefix.rs b/tests/rustdoc-json/remap-path-prefix/remap-path-prefix.rs new file mode 100644 index 0000000000000..b3c2001ac5fb2 --- /dev/null +++ b/tests/rustdoc-json/remap-path-prefix/remap-path-prefix.rs @@ -0,0 +1,5 @@ +//@ ignore-windows +//@ compile-flags: --remap-path-prefix={{src-base}}=/remapped + +//@ is "$.index[?(@.name=='StrLike')].span.filename" \"/remapped/remap-path-prefix/remap-path-prefix.rs\" +pub trait StrLike {} diff --git a/tests/ui/associated-consts/associated-const-no-item.stderr b/tests/ui/associated-consts/associated-const-no-item.stderr index 40cd7791399b0..2cb3a0c33308f 100644 --- a/tests/ui/associated-consts/associated-const-no-item.stderr +++ b/tests/ui/associated-consts/associated-const-no-item.stderr @@ -10,6 +10,8 @@ note: `Foo` defines an item `ID`, perhaps you need to implement it | LL | trait Foo { | ^^^^^^^^^ +LL | const ID: i32; + | error: aborting due to 1 previous error diff --git a/tests/ui/backtrace/dylib-dep.rs b/tests/ui/backtrace/dylib-dep.rs index f3d0d2e6a76db..a51ce3d8d04cc 100644 --- a/tests/ui/backtrace/dylib-dep.rs +++ b/tests/ui/backtrace/dylib-dep.rs @@ -15,7 +15,7 @@ //@ needs-unwind //@ ignore-backends: gcc //@ compile-flags: -g -Copt-level=0 -Cstrip=none -Cforce-frame-pointers=yes -//@ ignore-emscripten Requires custom symbolization code +//@ ignore-wasm Requires custom symbolization code //@ aux-crate: dylib_dep_helper=dylib-dep-helper.rs //@ aux-crate: auxiliary=dylib-dep-helper-aux.rs //@ run-pass diff --git a/tests/ui/backtrace/line-tables-only.rs b/tests/ui/backtrace/line-tables-only.rs index 33d5774079d94..39577385e123e 100644 --- a/tests/ui/backtrace/line-tables-only.rs +++ b/tests/ui/backtrace/line-tables-only.rs @@ -11,7 +11,7 @@ //@ compile-flags: -Cstrip=none -Cdebuginfo=line-tables-only //@ ignore-android FIXME #17520 //@ ignore-fuchsia Backtraces not symbolized -//@ ignore-emscripten Requires custom symbolization code +//@ ignore-wasm Requires custom symbolization code //@ ignore-ios needs the `.dSYM` files to be moved to the device //@ ignore-tvos needs the `.dSYM` files to be moved to the device //@ ignore-watchos needs the `.dSYM` files to be moved to the device diff --git a/tests/ui/delegation/inherent-impls-self-replacement.stderr b/tests/ui/delegation/inherent-impls-self-replacement.stderr index eed46d97d557b..6ecbc01699da4 100644 --- a/tests/ui/delegation/inherent-impls-self-replacement.stderr +++ b/tests/ui/delegation/inherent-impls-self-replacement.stderr @@ -109,6 +109,8 @@ note: `Trait` defines an item `get_s`, perhaps you need to implement it | LL | trait Trait: Sized { | ^^^^^^^^^^^^^^^^^^ +LL | fn get_s(self) -> S<(), 123>; + | error[E0599]: no method named `get_s` found for struct `Rc` in the current scope --> $DIR/inherent-impls-self-replacement.rs:49:38 @@ -122,6 +124,8 @@ note: `Trait` defines an item `get_s`, perhaps you need to implement it | LL | trait Trait: Sized { | ^^^^^^^^^^^^^^^^^^ +LL | fn get_s(self) -> S<(), 123>; + | error[E0599]: no method named `get_s` found for struct `Pin>` in the current scope --> $DIR/inherent-impls-self-replacement.rs:51:39 @@ -135,6 +139,8 @@ note: `Trait` defines an item `get_s`, perhaps you need to implement it | LL | trait Trait: Sized { | ^^^^^^^^^^^^^^^^^^ +LL | fn get_s(self) -> S<(), 123>; + | error[E0507]: cannot move out of `*self` which is behind a shared reference --> $DIR/inherent-impls-self-replacement.rs:24:34 diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr index 1ba2c2e222dd0..1f34397c8a939 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr @@ -26,6 +26,8 @@ note: `ProviderExt` defines an item `request`, perhaps you need to implement it | LL | pub trait ProviderExt { | ^^^^^^^^^^^^^^^^^^^^^ +LL | fn request(&self) { + | error: aborting due to 1 previous error diff --git a/tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.stderr index 9eb4e5bf5ef05..d33536e57ebe5 100644 --- a/tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.stderr +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.stderr @@ -19,10 +19,6 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` LL - fn bop() { LL + fn bop() { | -help: consider relaxing the implicit `Sized` restriction - | -LL | type Bar: Default + ?Sized - | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/functions-closures/fn-help-with-err.stderr b/tests/ui/functions-closures/fn-help-with-err.stderr index 9dc56c3652ac0..0540104d35620 100644 --- a/tests/ui/functions-closures/fn-help-with-err.stderr +++ b/tests/ui/functions-closures/fn-help-with-err.stderr @@ -16,6 +16,9 @@ note: `Bar` defines an item `bar`, perhaps you need to implement it | LL | trait Bar { | ^^^^^^^^^ +LL | +LL | fn bar(&self) {} + | help: use parentheses to call this closure | LL | arc2().bar(); diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr index 61512dd46582d..24aabf2e8f898 100644 --- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr +++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr @@ -20,6 +20,8 @@ note: `M` defines an item `f`, perhaps you need to implement it | LL | trait M { | ^^^^^^^ +LL | fn f(&self) {} + | error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr b/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr index f9862b8ab13a4..a90cedea04081 100644 --- a/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr +++ b/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr @@ -10,6 +10,9 @@ note: `X` defines an item `make_g`, perhaps you need to implement it | LL | trait X { | ^^^^^^^ +LL | type G; +LL | fn make_g() -> Self::G; + | error: implementation of `X` is not general enough --> $DIR/hrtb-fn-ptr-impl-not-general-enough-57936.rs:26:5 diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr index 21dc5c66adf2b..d3b95365efced 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr @@ -21,6 +21,9 @@ note: `StreamExt` defines an item `filterx`, perhaps you need to implement it | LL | pub trait StreamExt | ^^^^^^^^^^^^^^^^^^^ +... +LL | fn filterx(self, func: F) -> Filter + | error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr index 91e65b2b07318..1b69dcb5788ec 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr @@ -21,6 +21,8 @@ note: `StreamExt` defines an item `countx`, perhaps you need to implement it | LL | pub trait StreamExt | ^^^^^^^^^^^^^^^^^^^ +... +LL | fn countx(mut self) -> usize = note: the full name for the type has been written to '$TEST_BUILD_DIR/hrtb-doesnt-borrow-self-2.long-type-$LONG_TYPE_HASH.txt' = note: consider using `--verbose` to print the full type name to the console diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr index 3822bb5c9729e..2b1aca253d173 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr @@ -10,6 +10,8 @@ note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it | LL | trait MyDebug { | ^^^^^^^^^^^^^ +LL | fn my_debug(&self); + | error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.current.stderr index f77c44118966b..6c3ed0efcd9f4 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.current.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.current.stderr @@ -13,6 +13,8 @@ note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it | LL | trait MyDebug { | ^^^^^^^^^^^^^ +LL | fn my_debug(&self); + | error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.next.stderr index 71c588cd3a62f..94985e5e60b4e 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.next.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.next.stderr @@ -13,6 +13,8 @@ note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it | LL | trait MyDebug { | ^^^^^^^^^^^^^ +LL | fn my_debug(&self); + | error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr b/tests/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr index e5d7183937387..7834db7c5ff3c 100644 --- a/tests/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr +++ b/tests/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr @@ -13,6 +13,8 @@ note: `Foo` defines an item `foo`, perhaps you need to implement it | LL | trait Foo { | ^^^^^^^^^^^^ +LL | fn foo(&self, a: A) -> A { + | error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/method/would-constrain-opaque.current.stderr b/tests/ui/impl-trait/method/would-constrain-opaque.current.stderr index e29297ceea024..1e9a34b381192 100644 --- a/tests/ui/impl-trait/method/would-constrain-opaque.current.stderr +++ b/tests/ui/impl-trait/method/would-constrain-opaque.current.stderr @@ -10,6 +10,8 @@ note: `Trait` defines an item `method`, perhaps you need to implement it | LL | trait Trait: Sized { | ^^^^^^^^^^^^^^^^^^ +LL | fn method(self) {} + | error[E0599]: no method named `method` found for reference `&impl Sized` in the current scope --> $DIR/would-constrain-opaque.rs:32:11 @@ -23,6 +25,8 @@ note: `Trait` defines an item `method`, perhaps you need to implement it | LL | trait Trait: Sized { | ^^^^^^^^^^^^^^^^^^ +LL | fn method(self) {} + | error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/no-method-suggested-traits.stderr b/tests/ui/impl-trait/no-method-suggested-traits.stderr index ca383523f9238..1524679f8ba34 100644 --- a/tests/ui/impl-trait/no-method-suggested-traits.stderr +++ b/tests/ui/impl-trait/no-method-suggested-traits.stderr @@ -147,6 +147,9 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it | LL | pub trait Bar { | ^^^^^^^^^^^^^ +... +LL | fn method2(&self) {} + | error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&u64>>` in the current scope --> $DIR/no-method-suggested-traits.rs:50:44 @@ -160,6 +163,9 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it | LL | pub trait Bar { | ^^^^^^^^^^^^^ +... +LL | fn method2(&self) {} + | error[E0599]: no method named `method2` found for struct `no_method_suggested_traits::Foo` in the current scope --> $DIR/no-method-suggested-traits.rs:53:37 @@ -173,6 +179,9 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it | LL | pub trait Bar { | ^^^^^^^^^^^^^ +... +LL | fn method2(&self) {} + | error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:55:71 @@ -186,6 +195,9 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it | LL | pub trait Bar { | ^^^^^^^^^^^^^ +... +LL | fn method2(&self) {} + | error[E0599]: no method named `method2` found for enum `no_method_suggested_traits::Bar` in the current scope --> $DIR/no-method-suggested-traits.rs:57:40 @@ -199,6 +211,9 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it | LL | pub trait Bar { | ^^^^^^^^^^^^^ +... +LL | fn method2(&self) {} + | error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope --> $DIR/no-method-suggested-traits.rs:59:74 @@ -212,6 +227,9 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it | LL | pub trait Bar { | ^^^^^^^^^^^^^ +... +LL | fn method2(&self) {} + | error[E0599]: no method named `method3` found for struct `Foo` in the current scope --> $DIR/no-method-suggested-traits.rs:62:9 diff --git a/tests/ui/internal/internal-unstable-asm-experimental-arch.rs b/tests/ui/internal/internal-unstable-asm-experimental-arch.rs index 6d97779ff911d..a073b397d9bd6 100644 --- a/tests/ui/internal/internal-unstable-asm-experimental-arch.rs +++ b/tests/ui/internal/internal-unstable-asm-experimental-arch.rs @@ -1,4 +1,4 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 //@ compile-flags: --crate-type=lib //@ build-pass //@ aux-build:internal_unstable.rs diff --git a/tests/ui/iterators/iterator-does-not-need-into-iter.stderr b/tests/ui/iterators/iterator-does-not-need-into-iter.stderr index 3d3861e959f82..79810f761ee83 100644 --- a/tests/ui/iterators/iterator-does-not-need-into-iter.stderr +++ b/tests/ui/iterators/iterator-does-not-need-into-iter.stderr @@ -22,6 +22,8 @@ note: `HasMethod` defines an item `foo`, perhaps you need to implement it | LL | trait HasMethod { | ^^^^^^^^^^^^^^^ +LL | fn foo(self); + | error: aborting due to 1 previous error diff --git a/tests/ui/methods/tuple-suggestions-issue-142488.stderr b/tests/ui/methods/tuple-suggestions-issue-142488.stderr index f9363bb216f43..2ef7483770bf5 100644 --- a/tests/ui/methods/tuple-suggestions-issue-142488.stderr +++ b/tests/ui/methods/tuple-suggestions-issue-142488.stderr @@ -33,6 +33,8 @@ note: `Trait` defines an item `meth`, perhaps you need to implement it | LL | trait Trait { | ^^^^^^^^^^^ +LL | fn meth(self); + | error[E0599]: the method `f` exists for tuple `(_,)`, but its trait bounds were not satisfied --> $DIR/tuple-suggestions-issue-142488.rs:46:16 @@ -54,6 +56,8 @@ note: `Tr` defines an item `f`, perhaps you need to implement it | LL | trait Tr { | ^^^^^^^^ +LL | fn f(self) -> (A,) + | error: aborting due to 4 previous errors diff --git a/tests/ui/methods/vec-autoderef-autoref.stderr b/tests/ui/methods/vec-autoderef-autoref.stderr index 61c3bcc5b3b37..ecebce9430fc5 100644 --- a/tests/ui/methods/vec-autoderef-autoref.stderr +++ b/tests/ui/methods/vec-autoderef-autoref.stderr @@ -10,6 +10,8 @@ note: `MyIter` defines an item `test_mut`, perhaps you need to implement it | LL | trait MyIter { | ^^^^^^^^^^^^ +LL | fn test_mut(&mut self); + | help: there is a method `get_mut` with a similar name, but with different arguments --> $SRC_DIR/core/src/slice/mod.rs:LL:COL @@ -25,6 +27,9 @@ note: `MyIter` defines an item `test`, perhaps you need to implement it | LL | trait MyIter { | ^^^^^^^^^^^^ +LL | fn test_mut(&mut self); +LL | fn test(&self); + | error[E0599]: no method named `test` found for array `[{integer}; 1]` in the current scope --> $DIR/vec-autoderef-autoref.rs:9:11 @@ -38,6 +43,9 @@ note: `MyIter` defines an item `test`, perhaps you need to implement it | LL | trait MyIter { | ^^^^^^^^^^^^ +LL | fn test_mut(&mut self); +LL | fn test(&self); + | error[E0599]: no method named `test` found for reference `&[{integer}; 1]` in the current scope --> $DIR/vec-autoderef-autoref.rs:10:12 @@ -51,6 +59,9 @@ note: `MyIter` defines an item `test`, perhaps you need to implement it | LL | trait MyIter { | ^^^^^^^^^^^^ +LL | fn test_mut(&mut self); +LL | fn test(&self); + | error: aborting due to 4 previous errors diff --git a/tests/ui/move-expr/closure-local-bindings.rs b/tests/ui/move-expr/closure-local-bindings.rs new file mode 100644 index 0000000000000..878d458cc977a --- /dev/null +++ b/tests/ui/move-expr/closure-local-bindings.rs @@ -0,0 +1,77 @@ +//@ check-fail +//@ edition: 2024 + +#![allow(incomplete_features)] +#![feature(gen_blocks, move_expr)] + +macro_rules! move_value { + ($value:expr) => { move($value) }; +} + +fn main() { + let _ = |x: i32| move(x); + //~^ ERROR cannot use `x` in this move expression + + let _ = |(x, _): (i32, i32)| move(x); + //~^ ERROR cannot use `x` in this move expression + + let x = 1; + let _ = || { + let x = 2; + move(x); + //~^ ERROR cannot use `x` in this move expression + }; + + let _ = || { + for x in [1] { + move(x); + //~^ ERROR cannot use `x` in this move expression + } + }; + + let _ = || { + if let Some(x) = Some(1) { + move(x); + //~^ ERROR cannot use `x` in this move expression + } + }; + + let _ = || { + let x = 1; + || move(move(x)) + //~^ ERROR cannot use `x` in this move expression + }; + + let _ = || || move({ + let x = 1; + move(x) + //~^ ERROR cannot use `x` in this move expression + }); + + let _ = || { + let x = 1; + move_value!(x); + //~^ ERROR cannot use `x` in this move expression + }; + + let _ = async |x: i32| move(x); + //~^ ERROR cannot use `x` in this move expression + + let _ = async { + let x = 1; + move(x); + //~^ ERROR cannot use `x` in this move expression + }; + + let _ = gen { + let x = 1; + yield move(x); + //~^ ERROR cannot use `x` in this move expression + }; + + let _ = || { + let x = 1; + move(|| x) + //~^ ERROR cannot use `x` in this move expression + }; +} diff --git a/tests/ui/move-expr/closure-local-bindings.stderr b/tests/ui/move-expr/closure-local-bindings.stderr new file mode 100644 index 0000000000000..a762eeb5eb1e2 --- /dev/null +++ b/tests/ui/move-expr/closure-local-bindings.stderr @@ -0,0 +1,125 @@ +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:12:27 + | +LL | let _ = |x: i32| move(x); + | -------- -----^- + | || | + | || this expression is evaluated outside that scope + | |`x` is defined here + | `x` is defined within this scope + +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:15:39 + | +LL | let _ = |(x, _): (i32, i32)| move(x); + | -------------------- -----^- + | | | | + | | | this expression is evaluated outside that scope + | | `x` is defined here + | `x` is defined within this scope + +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:21:14 + | +LL | let _ = || { + | -- `x` is defined within this scope +LL | let x = 2; + | - `x` is defined here +LL | move(x); + | -----^- this expression is evaluated outside that scope + +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:27:18 + | +LL | let _ = || { + | -- `x` is defined within this scope +LL | for x in [1] { + | - `x` is defined here +LL | move(x); + | -----^- this expression is evaluated outside that scope + +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:34:18 + | +LL | let _ = || { + | -- `x` is defined within this scope +LL | if let Some(x) = Some(1) { + | - `x` is defined here +LL | move(x); + | -----^- this expression is evaluated outside that scope + +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:41:22 + | +LL | let _ = || { + | -- `x` is defined within this scope +LL | let x = 1; + | - `x` is defined here +LL | || move(move(x)) + | -----^- this expression is evaluated outside that scope + +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:47:14 + | +LL | let _ = || || move({ + | -- `x` is defined within this scope +LL | let x = 1; + | - `x` is defined here +LL | move(x) + | -----^- this expression is evaluated outside that scope + +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:53:21 + | +LL | ($value:expr) => { move($value) }; + | ------------ this expression is evaluated outside that scope +... +LL | let _ = || { + | -- `x` is defined within this scope +LL | let x = 1; + | - `x` is defined here +LL | move_value!(x); + | ^ + +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:57:33 + | +LL | let _ = async |x: i32| move(x); + | -------------- -----^- + | | | | + | | | this expression is evaluated outside that scope + | | `x` is defined here + | `x` is defined within this scope + +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:62:14 + | +LL | let _ = async { + | ----- `x` is defined within this scope +LL | let x = 1; + | - `x` is defined here +LL | move(x); + | -----^- this expression is evaluated outside that scope + +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:68:20 + | +LL | let _ = gen { + | --- `x` is defined within this scope +LL | let x = 1; + | - `x` is defined here +LL | yield move(x); + | -----^- this expression is evaluated outside that scope + +error: cannot use `x` in this move expression + --> $DIR/closure-local-bindings.rs:74:17 + | +LL | let _ = || { + | -- `x` is defined within this scope +LL | let x = 1; + | - `x` is defined here +LL | move(|| x) + | --------^- this expression is evaluated outside that scope + +error: aborting due to 12 previous errors + diff --git a/tests/ui/move-expr/closure-local-uninitialized.rs b/tests/ui/move-expr/closure-local-uninitialized.rs new file mode 100644 index 0000000000000..bf5fd4364cbe3 --- /dev/null +++ b/tests/ui/move-expr/closure-local-uninitialized.rs @@ -0,0 +1,13 @@ +//@ check-fail +// Regression test for https://github.com/rust-lang/rust/issues/156509 + +#![allow(incomplete_features)] +#![feature(move_expr)] + +fn main() { + let _c = || { + let x; + move(x); + //~^ ERROR cannot use `x` in this move expression + }; +} diff --git a/tests/ui/move-expr/closure-local-uninitialized.stderr b/tests/ui/move-expr/closure-local-uninitialized.stderr new file mode 100644 index 0000000000000..a008c01fc38be --- /dev/null +++ b/tests/ui/move-expr/closure-local-uninitialized.stderr @@ -0,0 +1,12 @@ +error: cannot use `x` in this move expression + --> $DIR/closure-local-uninitialized.rs:10:14 + | +LL | let _c = || { + | -- `x` is defined within this scope +LL | let x; + | - `x` is defined here +LL | move(x); + | -----^- this expression is evaluated outside that scope + +error: aborting due to 1 previous error + diff --git a/tests/ui/move-expr/move-initializer-local-bindings.rs b/tests/ui/move-expr/move-initializer-local-bindings.rs new file mode 100644 index 0000000000000..000c39b5c23d9 --- /dev/null +++ b/tests/ui/move-expr/move-initializer-local-bindings.rs @@ -0,0 +1,66 @@ +//@ run-pass + +#![allow(incomplete_features, unused_variables)] +#![feature(move_expr)] + +fn main() { + let c = || move({ + let x = 3; + x + }); + assert_eq!(c(), 3); + + let c = || move({ + let x = 4; + (|| x)() + }); + assert_eq!(c(), 4); + + let outer = || { + let x = 5; + || move(x) + }; + assert_eq!(outer()(), 5); + + let outer = || { + let x = 6; + || move({ + let y = 7; + || move(y + x) + }) + }; + assert_eq!(outer()()(), 13); + + let c = || move({ + fn identity(x: i32) -> i32 { + x + } + identity(8) + }); + assert_eq!(c(), 8); + + let c = || move(const { 9 }); + assert_eq!(c(), 9); + + let x = 10; + let c = || move(x); + let d = || move(x + 1); + assert_eq!(c(), 10); + assert_eq!(d(), 11); + + let c = || { + let x = 12; + move({ + let x = 13; + x + }) + }; + assert_eq!(c(), 13); + + let c = |x: i32| move({ + let x; + x = 14; + x + }); + assert_eq!(c(0), 14); +} diff --git a/tests/ui/move-expr/name-resolution.rs b/tests/ui/move-expr/name-resolution.rs index 7c0886183eb36..0e4f44ed3b5ec 100644 --- a/tests/ui/move-expr/name-resolution.rs +++ b/tests/ui/move-expr/name-resolution.rs @@ -1,7 +1,4 @@ -//@ check-pass -//@ ignore-test (#155050): currently ICEs instead of reporting a name-resolution error -// FIXME(TaKO8Ki): Remove this ignore once closure-local names in `move(expr)` produce a real -// diagnostic instead of hitting the current `Res::Err` ICE path. +//@ check-fail #![allow(incomplete_features)] #![feature(move_expr)] @@ -9,5 +6,6 @@ fn main() { let _c = || { let x = 3; move(x); + //~^ ERROR cannot use `x` in this move expression }; } diff --git a/tests/ui/move-expr/name-resolution.stderr b/tests/ui/move-expr/name-resolution.stderr new file mode 100644 index 0000000000000..f82e3bc5de3f6 --- /dev/null +++ b/tests/ui/move-expr/name-resolution.stderr @@ -0,0 +1,12 @@ +error: cannot use `x` in this move expression + --> $DIR/name-resolution.rs:8:14 + | +LL | let _c = || { + | -- `x` is defined within this scope +LL | let x = 3; + | - `x` is defined here +LL | move(x); + | -----^- this expression is evaluated outside that scope + +error: aborting due to 1 previous error + diff --git a/tests/ui/nll/issue-57362-1.stderr b/tests/ui/nll/issue-57362-1.stderr index 79b1b131afa2c..892b9b7b30141 100644 --- a/tests/ui/nll/issue-57362-1.stderr +++ b/tests/ui/nll/issue-57362-1.stderr @@ -10,6 +10,8 @@ note: `Trait` defines an item `f`, perhaps you need to implement it | LL | trait Trait { | ^^^^^^^^^^^ +LL | fn f(self); + | error: aborting due to 1 previous error diff --git a/tests/ui/nll/issue-57362-2.stderr b/tests/ui/nll/issue-57362-2.stderr index 1b962b16bdc8f..913ae08efb788 100644 --- a/tests/ui/nll/issue-57362-2.stderr +++ b/tests/ui/nll/issue-57362-2.stderr @@ -10,6 +10,9 @@ note: `X` defines an item `make_g`, perhaps you need to implement it | LL | trait X { | ^^^^^^^ +LL | type G; +LL | fn make_g() -> Self::G; + | error: aborting due to 1 previous error diff --git a/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr b/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr index 0a56d1bc72031..dac3e57747ce1 100644 --- a/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr +++ b/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr @@ -10,6 +10,9 @@ note: `X` defines an item `make_g`, perhaps you need to implement it | LL | trait X { | ^^^^^^^ +LL | type G; +LL | fn make_g() -> Self::G; + | error[E0599]: no associated function or constant named `make_f` found for fn pointer `for<'a> fn(&'a ())` in the current scope --> $DIR/issue-57642-higher-ranked-subtype.rs:36:25 @@ -23,6 +26,9 @@ note: `Y` defines an item `make_f`, perhaps you need to implement it | LL | trait Y { | ^^^^^^^ +LL | type F; +LL | fn make_f() -> Self::F; + | error: aborting due to 2 previous errors diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.rs b/tests/ui/panics/short-ice-remove-middle-frames-2.rs index 28556304be622..9761c9e7a514c 100644 --- a/tests/ui/panics/short-ice-remove-middle-frames-2.rs +++ b/tests/ui/panics/short-ice-remove-middle-frames-2.rs @@ -9,6 +9,7 @@ //@ ignore-sgx Backtraces not symbolized //@ ignore-fuchsia Backtraces not symbolized //@ ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable. +//@ ignore-wasm backtraces not symbolized // This is needed to avoid test output differences across std being built with v0 symbols vs legacy // symbols. //@ normalize-stderr: "begin_panic::<&str>" -> "begin_panic" diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr index 1efd7dc59b591..31bd4662af041 100644 --- a/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr +++ b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr @@ -1,5 +1,5 @@ -thread 'main' ($TID) panicked at $DIR/short-ice-remove-middle-frames-2.rs:63:5: +thread 'main' ($TID) panicked at $DIR/short-ice-remove-middle-frames-2.rs:64:5: debug!!! stack backtrace: 0: std::panicking::begin_panic diff --git a/tests/ui/panics/short-ice-remove-middle-frames.rs b/tests/ui/panics/short-ice-remove-middle-frames.rs index 0468bffbe4446..5754414bdf48e 100644 --- a/tests/ui/panics/short-ice-remove-middle-frames.rs +++ b/tests/ui/panics/short-ice-remove-middle-frames.rs @@ -9,6 +9,7 @@ //@ ignore-sgx Backtraces not symbolized //@ ignore-fuchsia Backtraces not symbolized //@ ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable. +//@ ignore-wasm backtraces not symbolized // This is needed to avoid test output differences across std being built with v0 symbols vs legacy // symbols. diff --git a/tests/ui/panics/short-ice-remove-middle-frames.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr index 6ad72bbb43ca2..5796347fea6fe 100644 --- a/tests/ui/panics/short-ice-remove-middle-frames.run.stderr +++ b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr @@ -1,5 +1,5 @@ -thread 'main' ($TID) panicked at $DIR/short-ice-remove-middle-frames.rs:59:5: +thread 'main' ($TID) panicked at $DIR/short-ice-remove-middle-frames.rs:60:5: debug!!! stack backtrace: 0: std::panicking::begin_panic diff --git a/tests/ui/range/issue-54505-no-std.rs b/tests/ui/range/issue-54505-no-std.rs index 6ddfc7e231464..bf5d9e64d0d60 100644 --- a/tests/ui/range/issue-54505-no-std.rs +++ b/tests/ui/range/issue-54505-no-std.rs @@ -9,7 +9,7 @@ use core::ops::RangeBounds; -#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))] +#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten", target_os = "wasi"))] #[lang = "eh_personality"] extern "C" fn eh_personality() {} diff --git a/tests/ui/specialization/default-impl-not-a-candidate-issue-48515.stderr b/tests/ui/specialization/default-impl-not-a-candidate-issue-48515.stderr index 91df5005d7095..7f82ae5e5a5c6 100644 --- a/tests/ui/specialization/default-impl-not-a-candidate-issue-48515.stderr +++ b/tests/ui/specialization/default-impl-not-a-candidate-issue-48515.stderr @@ -56,6 +56,8 @@ note: `Set` defines an item `contains`, perhaps you need to implement it | LL | trait Set { | ^^^^^^^^^^^^ +LL | fn contains(&self, bit: T); + | error: aborting due to 4 previous errors diff --git a/tests/ui/specialization/default-impl-not-an-impl.stderr b/tests/ui/specialization/default-impl-not-an-impl.stderr index cde757b3f98a7..c6dcafdd7bb06 100644 --- a/tests/ui/specialization/default-impl-not-an-impl.stderr +++ b/tests/ui/specialization/default-impl-not-an-impl.stderr @@ -33,6 +33,8 @@ note: `Foo` defines an item `f`, perhaps you need to implement it | LL | trait Foo { | ^^^^^^^^^ +LL | fn f(&self) -> u32; + | error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/default-impl-not-an-impl.rs:65:23 diff --git a/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr index 7cec84b1af6dd..bc3f1e1cce908 100644 --- a/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr +++ b/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr @@ -13,6 +13,8 @@ note: `Foo` defines an item `foo_one`, perhaps you need to implement it | LL | trait Foo { | ^^^^^^^^^ +LL | fn foo_one(&self) -> &'static str; + | error: aborting due to 1 previous error diff --git a/tests/ui/target-feature/implicit-features-cli.rs b/tests/ui/target-feature/implicit-features-cli.rs index 34e7c3d506659..488929b662ccb 100644 --- a/tests/ui/target-feature/implicit-features-cli.rs +++ b/tests/ui/target-feature/implicit-features-cli.rs @@ -1,4 +1,4 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 //@ compile-flags: -Ctarget-feature=+relaxed-simd --crate-type=lib //@ build-pass diff --git a/tests/ui/target-feature/implicit-features.rs b/tests/ui/target-feature/implicit-features.rs index b9c48b0822d53..c5d8a4907a8db 100644 --- a/tests/ui/target-feature/implicit-features.rs +++ b/tests/ui/target-feature/implicit-features.rs @@ -1,4 +1,4 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 //@ compile-flags: --crate-type=lib //@ build-pass diff --git a/tests/ui/target-feature/wasm-disable-simd.rs b/tests/ui/target-feature/wasm-disable-simd.rs index 998c867482372..6115a6acb30aa 100644 --- a/tests/ui/target-feature/wasm-disable-simd.rs +++ b/tests/ui/target-feature/wasm-disable-simd.rs @@ -1,4 +1,4 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 //@ compile-flags: -Ctarget-feature=-simd128 --crate-type=lib //@ build-pass diff --git a/tests/ui/target-feature/wasm-relaxed-simd.rs b/tests/ui/target-feature/wasm-relaxed-simd.rs index 34e7c3d506659..488929b662ccb 100644 --- a/tests/ui/target-feature/wasm-relaxed-simd.rs +++ b/tests/ui/target-feature/wasm-relaxed-simd.rs @@ -1,4 +1,4 @@ -//@ only-wasm32-wasip1 +//@ only-wasm32 //@ compile-flags: -Ctarget-feature=+relaxed-simd --crate-type=lib //@ build-pass diff --git a/tests/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr b/tests/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr index b29442d7b8fb2..8bbdd2f75c538 100644 --- a/tests/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr +++ b/tests/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr @@ -45,6 +45,7 @@ note: `Foo` defines an item `foo`, perhaps you need to implement it | LL | trait Foo { | ^^^^^^^^^ +LL | fn foo(&self); = note: the trait `FooBar` defines an item `foo`, but is explicitly unimplemented error: aborting due to 4 previous errors diff --git a/tests/ui/traits/next-solver/assoc-item-own-bound-diagnostics.rs b/tests/ui/traits/next-solver/assoc-item-own-bound-diagnostics.rs new file mode 100644 index 0000000000000..20cfbfb6fcffe --- /dev/null +++ b/tests/ui/traits/next-solver/assoc-item-own-bound-diagnostics.rs @@ -0,0 +1,92 @@ +//@ compile-flags: -Znext-solver + +// Tests the diagnostics for associated-item own clauses (e.g. `type Assoc +// where Self: Sized;`) that are not satisfied by an impl. The recovered error +// should point at the type that fails the clause and only suggest fixes that +// would actually satisfy it. + +// The impl associated type already carries other where clauses, but is +// missing the `Self: Sized` clause required by the trait item. Relaxing the +// implicit `Sized` restriction of the associated type would not satisfy that +// clause. +trait TraitWithBound { + type Assoc + where + Self: Sized, + Self: 'static; +} + +impl TraitWithBound for T { + //~^ ERROR the size for values of type `T` cannot be known at compilation time + type Assoc = i32 + where + Self: 'static; +} + +// The value of the impl associated type does not satisfy the implicit `Sized` +// restriction of the trait item. Relaxing that restriction is the right fix, +// so the suggestion must still be emitted even though the trait item carries +// other explicit where clauses. +trait TraitWithOtherClause { + type Assoc + where + Self: 'static; +} + +impl TraitWithOtherClause for () { + type Assoc = [u8]; + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time +} + +// A trait item without any explicit where clauses: the ordinary +// implicit-`Sized` diagnostic is unchanged. +trait NormalAssoc { + type Assoc; +} + +impl NormalAssoc for () { + type Assoc = [u8]; + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time +} + +// A projection use site outside of an impl: the recovery also applies there. +trait NonImplTrait { + type Assoc + where + Self: Sized; +} + +fn non_impl_use() { + let _: ::Assoc; + //~^ ERROR the size for values of type `T` cannot be known at compilation time + //~| ERROR the trait bound `T: NonImplTrait` is not satisfied +} + +// Own clauses with traits other than `Sized` are handled the same way. +trait Marker {} + +trait TraitWithMarker { + type Assoc + where + Self: Marker; +} + +impl TraitWithMarker for T { + //~^ ERROR the trait bound `T: Marker` is not satisfied + type Assoc = i32; +} + +// Own clauses on traits with a custom `#[rustc_on_unimplemented]` diagnostic +// keep their custom label. +trait TraitWithSend { + type Assoc + where + Self: Send; +} + +impl TraitWithSend for T { + //~^ ERROR `T` cannot be sent between threads safely + type Assoc = i32; +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/assoc-item-own-bound-diagnostics.stderr b/tests/ui/traits/next-solver/assoc-item-own-bound-diagnostics.stderr new file mode 100644 index 0000000000000..26e62981a6b4e --- /dev/null +++ b/tests/ui/traits/next-solver/assoc-item-own-bound-diagnostics.stderr @@ -0,0 +1,135 @@ +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/assoc-item-own-bound-diagnostics.rs:19:6 + | +LL | impl TraitWithBound for T { + | ^ + | | + | doesn't have a size known at compile-time + | this type parameter needs to be `Sized` + | +note: required by a bound in `TraitWithBound::Assoc` + --> $DIR/assoc-item-own-bound-diagnostics.rs:15:15 + | +LL | trait TraitWithBound { +LL | type Assoc +LL | where +LL | Self: Sized, + | ^^^^^ required by this bound in `TraitWithBound::Assoc` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - impl TraitWithBound for T { +LL + impl TraitWithBound for T { + | + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/assoc-item-own-bound-diagnostics.rs:37:18 + | +LL | type Assoc = [u8]; + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `TraitWithOtherClause::Assoc` + --> $DIR/assoc-item-own-bound-diagnostics.rs:31:5 + | +LL | trait TraitWithOtherClause { +LL | / type Assoc +LL | | where +LL | | Self: 'static; + | |______________________^ required by this bound in `TraitWithOtherClause::Assoc` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Assoc: ?Sized + | ++++++++ + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/assoc-item-own-bound-diagnostics.rs:48:18 + | +LL | type Assoc = [u8]; + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `NormalAssoc::Assoc` + --> $DIR/assoc-item-own-bound-diagnostics.rs:44:5 + | +LL | trait NormalAssoc { +LL | type Assoc; + | ^^^^^^^^^^^ required by this bound in `NormalAssoc::Assoc` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Assoc: ?Sized; + | ++++++++ + +error[E0277]: the trait bound `T: Marker` is not satisfied + --> $DIR/assoc-item-own-bound-diagnostics.rs:74:6 + | +LL | impl TraitWithMarker for T { + | ^ the trait `Marker` is not implemented for `T` + | +note: required by a bound in `TraitWithMarker::Assoc` + --> $DIR/assoc-item-own-bound-diagnostics.rs:71:15 + | +LL | trait TraitWithMarker { +LL | type Assoc +LL | where +LL | Self: Marker; + | ^^^^^^ required by this bound in `TraitWithMarker::Assoc` +help: consider restricting type parameter `T` with trait `Marker` + | +LL | impl TraitWithMarker for T { + | ++++++++ + +error[E0277]: `T` cannot be sent between threads safely + --> $DIR/assoc-item-own-bound-diagnostics.rs:87:6 + | +LL | impl TraitWithSend for T { + | ^ `T` cannot be sent between threads safely + | +note: required by a bound in `TraitWithSend::Assoc` + --> $DIR/assoc-item-own-bound-diagnostics.rs:84:15 + | +LL | trait TraitWithSend { +LL | type Assoc +LL | where +LL | Self: Send; + | ^^^^ required by this bound in `TraitWithSend::Assoc` +help: consider restricting type parameter `T` with trait `Send` + | +LL | impl TraitWithSend for T { + | +++++++++++++++++++ + +error[E0277]: the trait bound `T: NonImplTrait` is not satisfied + --> $DIR/assoc-item-own-bound-diagnostics.rs:60:13 + | +LL | let _: ::Assoc; + | ^ the trait `NonImplTrait` is not implemented for `T` + | +help: consider further restricting type parameter `T` with trait `NonImplTrait` + | +LL | fn non_impl_use() { + | ++++++++++++++ + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/assoc-item-own-bound-diagnostics.rs:60:13 + | +LL | fn non_impl_use() { + | - this type parameter needs to be `Sized` +LL | let _: ::Assoc; + | ^ doesn't have a size known at compile-time + | +note: required by a bound in `NonImplTrait::Assoc` + --> $DIR/assoc-item-own-bound-diagnostics.rs:56:15 + | +LL | trait NonImplTrait { +LL | type Assoc +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `NonImplTrait::Assoc` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn non_impl_use() { +LL + fn non_impl_use() { + | + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/assoc-item-own-bound.current.stderr b/tests/ui/traits/next-solver/assoc-item-own-bound.current.stderr new file mode 100644 index 0000000000000..5f60362ef64a0 --- /dev/null +++ b/tests/ui/traits/next-solver/assoc-item-own-bound.current.stderr @@ -0,0 +1,17 @@ +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/assoc-item-own-bound.rs:18:18 + | +LL | impl Trait for T { + | - this type parameter needs to be `Sized` +LL | type Assoc = i32; + | ^^^ doesn't have a size known at compile-time + | +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - impl Trait for T { +LL + impl Trait for T { + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/assoc-item-own-bound.next.stderr b/tests/ui/traits/next-solver/assoc-item-own-bound.next.stderr new file mode 100644 index 0000000000000..4831cf72da63f --- /dev/null +++ b/tests/ui/traits/next-solver/assoc-item-own-bound.next.stderr @@ -0,0 +1,26 @@ +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/assoc-item-own-bound.rs:17:6 + | +LL | impl Trait for T { + | ^ + | | + | doesn't have a size known at compile-time + | this type parameter needs to be `Sized` + | +note: required by a bound in `Trait::Assoc` + --> $DIR/assoc-item-own-bound.rs:13:15 + | +LL | trait Trait { +LL | type Assoc +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Trait::Assoc` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - impl Trait for T { +LL + impl Trait for T { + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/assoc-item-own-bound.rs b/tests/ui/traits/next-solver/assoc-item-own-bound.rs new file mode 100644 index 0000000000000..17275775c704c --- /dev/null +++ b/tests/ui/traits/next-solver/assoc-item-own-bound.rs @@ -0,0 +1,22 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for rust-lang/rust#162368: an impl associated type that does +// not satisfy an explicit own clause of the trait item used to be reported as +// a projection type mismatch (E0271) by the new solver instead of the +// unsatisfied trait bound (E0277). + +trait Trait { + type Assoc + where + Self: Sized; +} + +//[next]~v ERROR the size for values of type `T` cannot be known at compilation time +impl Trait for T { + type Assoc = i32; + //[current]~^ ERROR the size for values of type `T` cannot be known at compilation time +} + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/subtrait-method.stderr b/tests/ui/traits/trait-upcasting/subtrait-method.stderr index a16daa11d6f7a..9bfc3dfde0430 100644 --- a/tests/ui/traits/trait-upcasting/subtrait-method.stderr +++ b/tests/ui/traits/trait-upcasting/subtrait-method.stderr @@ -10,6 +10,8 @@ note: `Baz` defines an item `c`, perhaps you need to implement it | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ +LL | fn c(&self) -> i32 { + | help: there is a method `a` with a similar name | LL - bar.c(); @@ -28,6 +30,8 @@ note: `Bar` defines an item `b`, perhaps you need to implement it | LL | trait Bar: Foo { | ^^^^^^^^^^^^^^ +LL | fn b(&self) -> i32 { + | help: there is a method `a` with a similar name | LL - foo.b(); @@ -46,6 +50,8 @@ note: `Baz` defines an item `c`, perhaps you need to implement it | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ +LL | fn c(&self) -> i32 { + | help: there is a method `a` with a similar name | LL - foo.c(); @@ -64,6 +70,8 @@ note: `Bar` defines an item `b`, perhaps you need to implement it | LL | trait Bar: Foo { | ^^^^^^^^^^^^^^ +LL | fn b(&self) -> i32 { + | help: there is a method `a` with a similar name | LL - foo.b(); @@ -82,6 +90,8 @@ note: `Baz` defines an item `c`, perhaps you need to implement it | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ +LL | fn c(&self) -> i32 { + | help: there is a method `a` with a similar name | LL - foo.c(); diff --git a/tests/ui/traits/trivial-unsized-projection-2.bad.stderr b/tests/ui/traits/trivial-unsized-projection-2.bad.stderr index 16f1ceaf7e67f..3b5efa6b73523 100644 --- a/tests/ui/traits/trivial-unsized-projection-2.bad.stderr +++ b/tests/ui/traits/trivial-unsized-projection-2.bad.stderr @@ -18,10 +18,6 @@ LL | type Assert LL | where LL | Self: Sized; | ^^^^^ required by this bound in `Bad::Assert` -help: consider relaxing the implicit `Sized` restriction - | -LL | type Assert: ?Sized - | ++++++++ error[E0277]: the size for values of type `[()]` cannot be known at compilation time --> $DIR/trivial-unsized-projection-2.rs:22:12 @@ -44,10 +40,6 @@ LL | where LL | Self: Sized; | ^^^^^ required by this bound in `Bad::Assert` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider relaxing the implicit `Sized` restriction - | -LL | type Assert: ?Sized - | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr b/tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr index a58cebabf75d8..0eb9e23a0e7ce 100644 --- a/tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr +++ b/tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr @@ -1,9 +1,3 @@ -error[E0271]: type mismatch resolving `::Assert == _` - --> $DIR/trivial-unsized-projection-2.rs:22:12 - | -LL | const FOO: ::Assert = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^ types differ - error[E0277]: the size for values of type `[()]` cannot be known at compilation time --> $DIR/trivial-unsized-projection-2.rs:22:12 | @@ -24,18 +18,28 @@ LL | type Assert LL | where LL | Self: Sized; | ^^^^^ required by this bound in `Bad::Assert` -help: consider relaxing the implicit `Sized` restriction - | -LL | type Assert: ?Sized - | ++++++++ -error[E0271]: type mismatch resolving `::Assert == _` +error[E0277]: the size for values of type `[()]` cannot be known at compilation time --> $DIR/trivial-unsized-projection-2.rs:22:36 | LL | const FOO: ::Assert = todo!(); - | ^^^^^^^ types differ + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: within `Tail`, the trait `Sized` is not implemented for `[()]` +note: required because it appears within the type `Tail` + --> $DIR/trivial-unsized-projection-2.rs:17:13 + | +LL | struct Tail([()]); + | ^^^^ required by this field +note: required by a bound in `Bad::Assert` + --> $DIR/trivial-unsized-projection-2.rs:14:15 + | +LL | trait Bad { +LL | type Assert +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Bad::Assert` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/trivial-unsized-projection-2.rs b/tests/ui/traits/trivial-unsized-projection-2.rs index 175a2712d25b5..af4e12f6f9008 100644 --- a/tests/ui/traits/trivial-unsized-projection-2.rs +++ b/tests/ui/traits/trivial-unsized-projection-2.rs @@ -23,8 +23,7 @@ const FOO: ::Assert = todo!(); //[bad]~^ ERROR the size for values of type `[()]` cannot be known at compilation time //[bad]~| ERROR the size for values of type `[()]` cannot be known at compilation time //[bad_new]~^^^ ERROR the size for values of type `[()]` cannot be known at compilation time -//[bad_new]~| ERROR: type mismatch resolving `::Assert == _` -//[bad_new]~| ERROR: type mismatch resolving `::Assert == _` +//[bad_new]~| ERROR the size for values of type `[()]` cannot be known at compilation time #[cfg(any(good, good_new))] // Well-formed in trivially false param-env diff --git a/tests/ui/traits/trivial-unsized-projection.bad.stderr b/tests/ui/traits/trivial-unsized-projection.bad.stderr index bab0a72587320..d003d8017151c 100644 --- a/tests/ui/traits/trivial-unsized-projection.bad.stderr +++ b/tests/ui/traits/trivial-unsized-projection.bad.stderr @@ -13,10 +13,6 @@ LL | type Assert LL | where LL | Self: Sized; | ^^^^^ required by this bound in `Bad::Assert` -help: consider relaxing the implicit `Sized` restriction - | -LL | type Assert: ?Sized - | ++++++++ error[E0277]: the size for values of type `[()]` cannot be known at compilation time --> $DIR/trivial-unsized-projection.rs:20:12 @@ -34,10 +30,6 @@ LL | where LL | Self: Sized; | ^^^^^ required by this bound in `Bad::Assert` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider relaxing the implicit `Sized` restriction - | -LL | type Assert: ?Sized - | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/traits/trivial-unsized-projection.bad_new.stderr b/tests/ui/traits/trivial-unsized-projection.bad_new.stderr index a055181542d4d..d7d3032c40d9d 100644 --- a/tests/ui/traits/trivial-unsized-projection.bad_new.stderr +++ b/tests/ui/traits/trivial-unsized-projection.bad_new.stderr @@ -1,9 +1,3 @@ -error[E0271]: type mismatch resolving `<[()] as Bad>::Assert == _` - --> $DIR/trivial-unsized-projection.rs:20:12 - | -LL | const FOO: <[()] as Bad>::Assert = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^ types differ - error[E0277]: the size for values of type `[()]` cannot be known at compilation time --> $DIR/trivial-unsized-projection.rs:20:12 | @@ -19,18 +13,23 @@ LL | type Assert LL | where LL | Self: Sized; | ^^^^^ required by this bound in `Bad::Assert` -help: consider relaxing the implicit `Sized` restriction - | -LL | type Assert: ?Sized - | ++++++++ -error[E0271]: type mismatch resolving `<[()] as Bad>::Assert == _` +error[E0277]: the size for values of type `[()]` cannot be known at compilation time --> $DIR/trivial-unsized-projection.rs:20:36 | LL | const FOO: <[()] as Bad>::Assert = todo!(); - | ^^^^^^^ types differ + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[()]` +note: required by a bound in `Bad::Assert` + --> $DIR/trivial-unsized-projection.rs:14:15 + | +LL | trait Bad { +LL | type Assert +LL | where +LL | Self: Sized; + | ^^^^^ required by this bound in `Bad::Assert` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/trivial-unsized-projection.rs b/tests/ui/traits/trivial-unsized-projection.rs index 8b62356785a35..62ff25fb7ac0a 100644 --- a/tests/ui/traits/trivial-unsized-projection.rs +++ b/tests/ui/traits/trivial-unsized-projection.rs @@ -21,8 +21,7 @@ const FOO: <[()] as Bad>::Assert = todo!(); //[bad]~^ ERROR the size for values of type `[()]` cannot be known at compilation time //[bad]~| ERROR the size for values of type `[()]` cannot be known at compilation time //[bad_new]~^^^ ERROR the size for values of type `[()]` cannot be known at compilation time -//[bad_new]~| ERROR type mismatch resolving `<[()] as Bad>::Assert == _` -//[bad_new]~| ERROR type mismatch resolving `<[()] as Bad>::Assert == _` +//[bad_new]~| ERROR the size for values of type `[()]` cannot be known at compilation time #[cfg(any(good, good_new))] // Well-formed in trivially false param-env diff --git a/tests/ui/trivial-bounds/trivial-bounds-leak.stderr b/tests/ui/trivial-bounds/trivial-bounds-leak.stderr index be472a5076913..b9882c74ad44f 100644 --- a/tests/ui/trivial-bounds/trivial-bounds-leak.stderr +++ b/tests/ui/trivial-bounds/trivial-bounds-leak.stderr @@ -19,6 +19,8 @@ note: `Foo` defines an item `test`, perhaps you need to implement it | LL | pub trait Foo { | ^^^^^^^^^^^^^ +LL | fn test(&self); + | error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/trivial-bounds-leak.rs:25:15 diff --git a/tests/ui/use/unused-trait-with-method-err.stderr b/tests/ui/use/unused-trait-with-method-err.stderr index 7ca4563673bb1..d748fddcf374a 100644 --- a/tests/ui/use/unused-trait-with-method-err.stderr +++ b/tests/ui/use/unused-trait-with-method-err.stderr @@ -13,6 +13,8 @@ note: `Bar` defines an item `uwu`, perhaps you need to implement it | LL | pub trait Bar { | ^^^^^^^^^^^^^ +LL | fn uwu(&self) {} + | error: aborting due to 1 previous error diff --git a/tests/ui/wasm/wasm-link-name-in-foreign-crate-respected.rs b/tests/ui/wasm/wasm-link-name-in-foreign-crate-respected.rs index e2ceeb8ae13e2..a39a9c6ada399 100644 --- a/tests/ui/wasm/wasm-link-name-in-foreign-crate-respected.rs +++ b/tests/ui/wasm/wasm-link-name-in-foreign-crate-respected.rs @@ -1,6 +1,6 @@ //@ only-wasm32 //@ aux-build:link-name-in-foreign-crate.rs -//@ compile-flags: --crate-type cdylib +//@ compile-flags: --crate-type cdylib -C link-arg=--skip-wit-component //@ build-pass //@ no-prefer-dynamic