diff --git a/Cargo.lock b/Cargo.lock index 2f4d5f7f786ed..9c6d6c22de4dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4101,6 +4101,7 @@ dependencies = [ name = "rustc_interface" version = "0.0.0" dependencies = [ + "rand 0.9.2", "rustc_abi", "rustc_ast", "rustc_ast_lowering", @@ -4602,7 +4603,6 @@ version = "0.0.0" dependencies = [ "getopts", "libc", - "rand 0.9.2", "rustc_abi", "rustc_ast", "rustc_data_structures", diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 0b7e308b9489f..4a663c48c0aff 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -200,5 +200,5 @@ index 073116933bd..c3e4578204d 100644 EOF echo "[TEST] rustc test suite" -./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,run-make-cargo,ui,incremental} +./x.py test --stage 0 --no-capture --verbose-run-make-subprocess-output=false tests/{codegen-units,run-make,run-make-cargo,ui,incremental} popd diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index bea254b7b3a6f..a9acd0ae34ca2 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -150,7 +150,6 @@ fn make_module(sess: &Session, name: String) -> UnwindModule { fn emit_cgu( output_filenames: &OutputFilenames, - invocation_temp: Option<&str>, prof: &SelfProfilerRef, name: String, module: UnwindModule, @@ -166,7 +165,6 @@ fn emit_cgu( let module_regular = emit_module( output_filenames, - invocation_temp, prof, product.object, ModuleKind::Regular, @@ -192,7 +190,6 @@ fn emit_cgu( fn emit_module( output_filenames: &OutputFilenames, - invocation_temp: Option<&str>, prof: &SelfProfilerRef, mut object: cranelift_object::object::write::Object<'_>, kind: ModuleKind, @@ -211,7 +208,7 @@ fn emit_module( object.set_section_data(comment_section, producer, 1); } - let tmp_file = output_filenames.temp_path_for_cgu(OutputType::Object, &name, invocation_temp); + let tmp_file = output_filenames.temp_path_for_cgu(OutputType::Object, &name); let file = match File::create(&tmp_file) { Ok(file) => file, Err(err) => return Err(format!("error creating object file: {}", err)), @@ -251,11 +248,8 @@ fn reuse_workproduct_for_cgu( cgu: &CodegenUnit<'_>, ) -> Result { let work_product = cgu.previous_work_product(tcx); - let obj_out_regular = tcx.output_filenames(()).temp_path_for_cgu( - OutputType::Object, - cgu.name().as_str(), - tcx.sess.invocation_temp.as_deref(), - ); + let obj_out_regular = + tcx.output_filenames(()).temp_path_for_cgu(OutputType::Object, cgu.name().as_str()); let source_file_regular = rustc_incremental::in_incr_comp_dir_sess( tcx.sess, work_product.saved_files.get("o").expect("no saved object file in work product"), @@ -394,7 +388,6 @@ fn module_codegen( let producer = crate::debuginfo::producer(tcx.sess); let profiler = tcx.prof.clone(); - let invocation_temp = tcx.sess.invocation_temp.clone(); let output_filenames = tcx.output_filenames(()).clone(); let should_write_ir = crate::pretty_clif::should_write_ir(tcx.sess); @@ -421,19 +414,13 @@ fn module_codegen( let global_asm_object_file = profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| { - crate::global_asm::compile_global_asm( - &global_asm_config, - &cgu_name, - global_asm, - invocation_temp.as_deref(), - ) + crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, global_asm) })?; let codegen_result = profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| { emit_cgu( &global_asm_config.output_filenames, - invocation_temp.as_deref(), &profiler, cgu_name, module, @@ -456,7 +443,6 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option { match emit_module( tcx.output_filenames(()), - tcx.sess.invocation_temp.as_deref(), &tcx.sess.prof, product.object, ModuleKind::Allocator, diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 3903e6ea3b1da..33b88d70d6f8d 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -33,14 +33,15 @@ fn create_jit_module( (jit_module, cx) } -pub(crate) fn run_jit(tcx: TyCtxt<'_>, crate_info: &CrateInfo, jit_args: Vec) -> ! { +pub(crate) fn run_jit(tcx: TyCtxt<'_>, target_cpu: String, jit_args: Vec) -> ! { if !tcx.crate_types().contains(&rustc_session::config::CrateType::Executable) { tcx.dcx().fatal("can't jit non-executable crate"); } let output_filenames = tcx.output_filenames(()); + let crate_info = CrateInfo::new(tcx, target_cpu); let should_write_ir = crate::pretty_clif::should_write_ir(tcx.sess); - let (mut jit_module, mut debug_context) = create_jit_module(tcx, crate_info); + let (mut jit_module, mut debug_context) = create_jit_module(tcx, &crate_info); let mut cached_context = Context::new(); let cgus = tcx.collect_and_partition_mono_items(()).codegen_units; diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 5765601763e44..0c5f4136a32d6 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -185,7 +185,6 @@ pub(crate) fn compile_global_asm( config: &GlobalAsmConfig, cgu_name: &str, global_asm: String, - invocation_temp: Option<&str>, ) -> Result, String> { if global_asm.is_empty() { return Ok(None); @@ -200,7 +199,7 @@ pub(crate) fn compile_global_asm( global_asm.push('\n'); let global_asm_object_file = add_file_stem_postfix( - config.output_filenames.temp_path_for_cgu(OutputType::Object, cgu_name, invocation_temp), + config.output_filenames.temp_path_for_cgu(OutputType::Object, cgu_name), ".asm", ); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index cbbb0ccbbc215..361f143d99913 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -209,12 +209,12 @@ impl CodegenBackend for CraneliftCodegenBackend { .to_owned() } - fn codegen_crate(&self, tcx: TyCtxt<'_>, _crate_info: &CrateInfo) -> Box { + fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE)); let config = self.config.get().unwrap(); if config.jit_mode { #[cfg(feature = "jit")] - driver::jit::run_jit(tcx, _crate_info, config.jit_args.clone()); + driver::jit::run_jit(tcx, self.target_cpu(tcx.sess), config.jit_args.clone()); #[cfg(not(feature = "jit"))] tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); @@ -228,6 +228,7 @@ impl CodegenBackend for CraneliftCodegenBackend { ongoing_codegen: Box, sess: &Session, outputs: &OutputFilenames, + _crate_info: &CrateInfo, ) -> (CompiledModules, FxIndexMap) { ongoing_codegen.downcast::().unwrap().join(sess, outputs) } diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 64674423de2c6..8fd38a2efd600 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -29,16 +29,8 @@ pub(crate) fn codegen( let lto_mode = module.module_llvm.lto_mode; let lto_supported = module.module_llvm.lto_supported; - let bc_out = cgcx.output_filenames.temp_path_for_cgu( - OutputType::Bitcode, - &module.name, - cgcx.invocation_temp.as_deref(), - ); - let obj_out = cgcx.output_filenames.temp_path_for_cgu( - OutputType::Object, - &module.name, - cgcx.invocation_temp.as_deref(), - ); + let bc_out = cgcx.output_filenames.temp_path_for_cgu(OutputType::Bitcode, &module.name); + let obj_out = cgcx.output_filenames.temp_path_for_cgu(OutputType::Object, &module.name); if config.bitcode_needed() { let _timer = @@ -82,22 +74,15 @@ pub(crate) fn codegen( } if config.emit_ir { - let out = cgcx.output_filenames.temp_path_for_cgu( - OutputType::LlvmAssembly, - &module.name, - cgcx.invocation_temp.as_deref(), - ); + let out = + cgcx.output_filenames.temp_path_for_cgu(OutputType::LlvmAssembly, &module.name); std::fs::write(out, "").expect("write file"); } if config.emit_asm { let _timer = prof.generic_activity_with_arg("GCC_module_codegen_emit_asm", &*module.name); - let path = cgcx.output_filenames.temp_path_for_cgu( - OutputType::Assembly, - &module.name, - cgcx.invocation_temp.as_deref(), - ); + let path = cgcx.output_filenames.temp_path_for_cgu(OutputType::Assembly, &module.name); context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str")); } @@ -215,7 +200,6 @@ pub(crate) fn codegen( config.emit_asm, config.emit_ir, &cgcx.output_filenames, - cgcx.invocation_temp.as_deref(), ) } diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 4be25b3fb0934..6ca2ef88ef291 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -291,8 +291,8 @@ impl CodegenBackend for GccCodegenBackend { target_cpu(sess).to_owned() } - fn codegen_crate(&self, tcx: TyCtxt<'_>, crate_info: &CrateInfo) -> Box { - Box::new(codegen_crate(self.clone(), tcx, crate_info)) + fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { + Box::new(codegen_crate(self.clone(), tcx)) } fn join_codegen( @@ -300,11 +300,12 @@ impl CodegenBackend for GccCodegenBackend { ongoing_codegen: Box, sess: &Session, _outputs: &OutputFilenames, + crate_info: &CrateInfo, ) -> (CompiledModules, FxIndexMap) { ongoing_codegen .downcast::>() .expect("Expected GccCodegenBackend's OngoingCodegen, found Box") - .join(sess) + .join(sess, crate_info) } fn target_config(&self, sess: &Session) -> TargetConfig { diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 515b571a9f4b3..417f321a6b4a7 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -117,17 +117,13 @@ pub(crate) fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTar tcx.sess.split_debuginfo(), tcx.sess.opts.unstable_opts.split_dwarf_kind, mod_name, - tcx.sess.invocation_temp.as_deref(), ) } else { None }; - let output_obj_file = Some(tcx.output_filenames(()).temp_path_for_cgu( - OutputType::Object, - mod_name, - tcx.sess.invocation_temp.as_deref(), - )); + let output_obj_file = + Some(tcx.output_filenames(()).temp_path_for_cgu(OutputType::Object, mod_name)); let config = TargetMachineFactoryConfig { split_dwarf_file, output_obj_file }; target_machine_factory( @@ -322,11 +318,7 @@ pub(crate) fn save_temp_bitcode( return; } let ext = format!("{name}.bc"); - let path = cgcx.output_filenames.temp_path_ext_for_cgu( - &ext, - &module.name, - cgcx.invocation_temp.as_deref(), - ); + let path = cgcx.output_filenames.temp_path_ext_for_cgu(&ext, &module.name); write_bitcode_to_file(&module.module_llvm, &path) } @@ -949,11 +941,8 @@ 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()); - let bc_summary_out = cgcx.output_filenames.temp_path_for_cgu( - OutputType::ThinLinkBitcode, - &module.name, - cgcx.invocation_temp.as_deref(), - ); + 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 && let Some(thin_link_bitcode_filename) = bc_summary_out.file_name() { @@ -1008,16 +997,8 @@ pub(crate) fn codegen( // copy it to the .o file, and delete the bitcode if it wasn't // otherwise requested. - let bc_out = cgcx.output_filenames.temp_path_for_cgu( - OutputType::Bitcode, - &module.name, - cgcx.invocation_temp.as_deref(), - ); - let obj_out = cgcx.output_filenames.temp_path_for_cgu( - OutputType::Object, - &module.name, - cgcx.invocation_temp.as_deref(), - ); + let bc_out = cgcx.output_filenames.temp_path_for_cgu(OutputType::Bitcode, &module.name); + let obj_out = cgcx.output_filenames.temp_path_for_cgu(OutputType::Object, &module.name); if config.bitcode_needed() { if config.emit_bc || config.emit_obj == EmitObj::Bitcode { @@ -1055,11 +1036,8 @@ pub(crate) fn codegen( if config.emit_ir { let _timer = prof.generic_activity_with_arg("LLVM_module_codegen_emit_ir", &*module.name); - let out = cgcx.output_filenames.temp_path_for_cgu( - OutputType::LlvmAssembly, - &module.name, - cgcx.invocation_temp.as_deref(), - ); + let out = + cgcx.output_filenames.temp_path_for_cgu(OutputType::LlvmAssembly, &module.name); let out_c = path_to_c_string(&out); extern "C" fn demangle_callback( @@ -1103,11 +1081,7 @@ pub(crate) fn codegen( if config.emit_asm { let _timer = prof.generic_activity_with_arg("LLVM_module_codegen_emit_asm", &*module.name); - let path = cgcx.output_filenames.temp_path_for_cgu( - OutputType::Assembly, - &module.name, - cgcx.invocation_temp.as_deref(), - ); + let path = cgcx.output_filenames.temp_path_for_cgu(OutputType::Assembly, &module.name); // We can't use the same module for asm and object code output, // because that triggers various errors like invalid IR or broken @@ -1136,9 +1110,7 @@ pub(crate) fn codegen( let _timer = prof.generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name); - let dwo_out = cgcx - .output_filenames - .temp_path_dwo_for_cgu(&module.name, cgcx.invocation_temp.as_deref()); + let dwo_out = cgcx.output_filenames.temp_path_dwo_for_cgu(&module.name); let dwo_out = match (cgcx.split_debuginfo, cgcx.split_dwarf_kind) { // Don't change how DWARF is emitted when disabled. (SplitDebuginfo::Off, _) => None, @@ -1203,7 +1175,6 @@ pub(crate) fn codegen( config.emit_asm, config.emit_ir, &cgcx.output_filenames, - cgcx.invocation_temp.as_deref(), ) } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 9a9e8287e787f..19dbdc6946b79 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -903,7 +903,6 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( tcx.sess.split_debuginfo(), tcx.sess.opts.unstable_opts.split_dwarf_kind, codegen_unit_name, - tcx.sess.invocation_temp.as_deref(), ) { // We get a path relative to the working directory from split_dwarf_path Some(tcx.sess.source_map().path_mapping().to_real_filename(work_dir, f)) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 575e37d0b171d..b273047b98fc6 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -333,8 +333,8 @@ impl CodegenBackend for LlvmCodegenBackend { crate::llvm_util::target_cpu(sess).to_string() } - fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, crate_info: &CrateInfo) -> Box { - Box::new(rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx, crate_info)) + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box { + Box::new(rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx)) } fn join_codegen( @@ -342,11 +342,12 @@ impl CodegenBackend for LlvmCodegenBackend { ongoing_codegen: Box, sess: &Session, outputs: &OutputFilenames, + crate_info: &CrateInfo, ) -> (CompiledModules, FxIndexMap) { let (compiled_modules, work_products) = ongoing_codegen .downcast::>() .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box") - .join(sess); + .join(sess, crate_info); if sess.opts.unstable_opts.llvm_time_trace { sess.time("llvm_dump_timing_file", || { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d8e2b54ad50a8..9368bc6e1ba72 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -112,12 +112,7 @@ pub fn link_binary( let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps); let crate_name = format!("{}", crate_info.local_crate_name); - let out_filename = output.file_for_writing( - outputs, - OutputType::Exe, - &crate_name, - sess.invocation_temp.as_deref(), - ); + let out_filename = output.file_for_writing(outputs, OutputType::Exe, &crate_name); match crate_type { CrateType::Rlib => { let _timer = sess.timer("link_rlib"); diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index ddfcd8a85f6b8..ed36fae3cdc4d 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -85,7 +85,7 @@ fn crate_type_allows_lto(crate_type: CrateType) -> bool { } } -pub(super) fn exported_symbols_for_lto( +pub(crate) fn exported_symbols_for_lto( tcx: TyCtxt<'_>, each_linked_rlib_for_lto: &[CrateNum], ) -> Vec { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index c48e8a58b6964..7b22ac231df1c 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -34,7 +34,7 @@ use rustc_span::{FileName, InnerSpan, Span, SpanData}; use rustc_target::spec::{MergeFunctions, SanitizerSet}; use tracing::debug; -use crate::back::link::{self, ensure_removed}; +use crate::back::link::ensure_removed; use crate::back::lto::{self, SerializedModule, check_lto_allowed}; use crate::errors::ErrorCreatingRemarkDir; use crate::traits::*; @@ -136,7 +136,8 @@ impl ModuleConfig { let emit_obj = if !should_emit_obj { EmitObj::None } else if sess.target.obj_is_bitcode - || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins) + || (sess.opts.cg.linker_plugin_lto.enabled() + && (!no_builtins || tcx.sess.is_sanitizer_cfi_enabled())) { // This case is selected if the target uses objects as bitcode, or // if linker plugin LTO is enabled. In the linker plugin LTO case @@ -144,14 +145,23 @@ impl ModuleConfig { // and convert it to object code. This may be done by either the // native linker or rustc itself. // - // Note, however, that the linker-plugin-lto requested here is - // explicitly ignored for `#![no_builtins]` crates. These crates are - // specifically ignored by rustc's LTO passes and wouldn't work if - // loaded into the linker. These crates define symbols that LLVM - // lowers intrinsics to, and these symbol dependencies aren't known - // until after codegen. As a result any crate marked - // `#![no_builtins]` is assumed to not participate in LTO and - // instead goes on to generate object code. + // By default this branch is skipped for `#![no_builtins]` crates so + // they emit native object files (machine code), not LLVM bitcode + // objects for the linker (see rust-lang/rust#146133). + // + // However, when LLVM CFI is enabled (`-Zsanitizer=cfi`), this + // breaks LLVM's expected pipeline: LLVM emits `llvm.type.test` + // intrinsics and related metadata that must be lowered by LLVM's + // `LowerTypeTests` pass before instruction selection during + // link-time LTO. Otherwise, `llvm.type.test` intrinsics and related + // metadata are not lowered by LLVM's `LowerTypeTests` pass before + // reaching the target backend, and LLVM may abort during codegen + // (for example in SelectionDAG type legalization) (see + // rust-lang/rust#142284). + // + // Therefore, with `-Clinker-plugin-lto` and `-Zsanitizer=cfi`, a + // `#![no_builtins]` crate must still use rustc's `EmitObj::Bitcode` + // path (and emit LLVM bitcode in the `.o` for linker-based LTO). EmitObj::Bitcode } else if need_bitcode_in_object(tcx) || sess.target.requires_lto { EmitObj::ObjectCode(BitcodeSection::Full) @@ -285,17 +295,13 @@ impl TargetMachineFactoryConfig { cgcx.split_debuginfo, cgcx.split_dwarf_kind, module_name, - cgcx.invocation_temp.as_deref(), ) } else { None }; - let output_obj_file = Some(cgcx.output_filenames.temp_path_for_cgu( - OutputType::Object, - module_name, - cgcx.invocation_temp.as_deref(), - )); + let output_obj_file = + Some(cgcx.output_filenames.temp_path_for_cgu(OutputType::Object, module_name)); TargetMachineFactoryConfig { split_dwarf_file, output_obj_file } } } @@ -322,7 +328,6 @@ pub struct CodegenContext { pub time_trace: bool, pub crate_types: Vec, pub output_filenames: Arc, - pub invocation_temp: Option, pub module_config: Arc, pub opt_level: OptLevel, pub backend_features: Vec, @@ -389,18 +394,8 @@ fn generate_thin_lto_work( enum MaybeLtoModules { NoLto(CompiledModules), - FatLto { - cgcx: CodegenContext, - exported_symbols_for_lto: Arc>, - each_linked_rlib_file_for_lto: Vec, - needs_fat_lto: Vec>, - }, - ThinLto { - cgcx: CodegenContext, - exported_symbols_for_lto: Arc>, - each_linked_rlib_file_for_lto: Vec, - needs_thin_lto: Vec>, - }, + FatLto { cgcx: CodegenContext, needs_fat_lto: Vec> }, + ThinLto { cgcx: CodegenContext, needs_thin_lto: Vec> }, } fn need_bitcode_in_object(tcx: TyCtxt<'_>) -> bool { @@ -424,7 +419,6 @@ fn need_pre_lto_bitcode_for_incr_comp(sess: &Session) -> bool { pub(crate) fn start_async_codegen( backend: B, tcx: TyCtxt<'_>, - crate_info: &CrateInfo, allocator_module: Option>, ) -> OngoingCodegen { let (coordinator_send, coordinator_receive) = channel(); @@ -440,7 +434,6 @@ pub(crate) fn start_async_codegen( let coordinator_thread = start_executing_work( backend.clone(), tcx, - crate_info, shared_emitter, codegen_worker_send, coordinator_receive, @@ -529,11 +522,7 @@ pub fn produce_final_output_artifacts( if let [module] = &compiled_modules.modules[..] { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - let path = crate_output.temp_path_for_cgu( - output_type, - &module.name, - sess.invocation_temp.as_deref(), - ); + let path = crate_output.temp_path_for_cgu(output_type, &module.name); let output = crate_output.path(output_type); if !output_type.is_text_output() && output.is_tty() { sess.dcx() @@ -912,12 +901,7 @@ fn execute_copy_from_cache_work_item( module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| { let dwarf_obj_out = cgcx .output_filenames - .split_dwarf_path( - cgcx.split_debuginfo, - cgcx.split_dwarf_kind, - &module.name, - cgcx.invocation_temp.as_deref(), - ) + .split_dwarf_path(cgcx.split_debuginfo, cgcx.split_dwarf_kind, &module.name) .expect( "saved dwarf object in work product but `split_dwarf_path` returned `None`", ); @@ -927,11 +911,7 @@ fn execute_copy_from_cache_work_item( let mut load_from_incr_cache = |perform, output_type: OutputType| { if perform { let saved_file = module.source.saved_files.get(output_type.extension())?; - let output_path = cgcx.output_filenames.temp_path_for_cgu( - output_type, - &module.name, - cgcx.invocation_temp.as_deref(), - ); + let output_path = cgcx.output_filenames.temp_path_for_cgu(output_type, &module.name); load_from_incr_comp_dir(output_path, &saved_file) } else { None @@ -992,8 +972,8 @@ fn do_thin_lto( prof: &SelfProfilerRef, shared_emitter: SharedEmitter, tm_factory: TargetMachineFactoryFn, - exported_symbols_for_lto: Arc>, - each_linked_rlib_for_lto: Vec, + exported_symbols_for_lto: &[String], + each_linked_rlib_for_lto: &[PathBuf], needs_thin_lto: Vec>, ) -> Vec { let _timer = prof.verbose_generic_activity("LLVM_thinlto"); @@ -1231,7 +1211,6 @@ enum MainThreadState { fn start_executing_work( backend: B, tcx: TyCtxt<'_>, - crate_info: &CrateInfo, shared_emitter: SharedEmitter, codegen_worker_send: Sender, coordinator_receive: Receiver>, @@ -1243,22 +1222,9 @@ fn start_executing_work( let sess = tcx.sess; let prof = sess.prof.clone(); - let mut each_linked_rlib_for_lto = Vec::new(); - let mut each_linked_rlib_file_for_lto = Vec::new(); - if sess.lto() != Lto::No && sess.lto() != Lto::ThinLocal { - drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| { - if link::ignored_for_lto(sess, crate_info, cnum) { - return; - } - - each_linked_rlib_for_lto.push(cnum); - each_linked_rlib_file_for_lto.push(path.to_path_buf()); - })); - } - - // Compute the set of symbols we need to retain when doing LTO (if we need to) + // Compute the set of symbols we need to retain when doing thin local LTO (if we need to) let exported_symbols_for_lto = - Arc::new(lto::exported_symbols_for_lto(tcx, &each_linked_rlib_for_lto)); + if sess.lto() == Lto::ThinLocal { lto::exported_symbols_for_lto(tcx, &[]) } else { vec![] }; // First up, convert our jobserver into a helper thread so we can use normal // mpsc channels to manage our messages and such. @@ -1313,7 +1279,6 @@ fn start_executing_work( split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend, pointer_size: tcx.data_layout.pointer_size(), - invocation_temp: sess.invocation_temp.clone(), }; // This is the "main loop" of parallel work happening for parallel codegen. @@ -1757,12 +1722,7 @@ fn start_executing_work( needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, bitcode_path }) } - return Ok(MaybeLtoModules::FatLto { - cgcx, - exported_symbols_for_lto, - each_linked_rlib_file_for_lto, - needs_fat_lto, - }); + return Ok(MaybeLtoModules::FatLto { cgcx, needs_fat_lto }); } else if !needs_thin_lto.is_empty() || !lto_import_only_modules.is_empty() { assert!(compiled_modules.is_empty()); assert!(needs_fat_lto.is_empty()); @@ -1777,8 +1737,8 @@ fn start_executing_work( &prof, shared_emitter.clone(), tm_factory, - exported_symbols_for_lto, - each_linked_rlib_file_for_lto, + &exported_symbols_for_lto, + &[], needs_thin_lto, )); } else { @@ -1790,12 +1750,7 @@ fn start_executing_work( }); } - return Ok(MaybeLtoModules::ThinLto { - cgcx, - exported_symbols_for_lto, - each_linked_rlib_file_for_lto, - needs_thin_lto, - }); + return Ok(MaybeLtoModules::ThinLto { cgcx, needs_thin_lto }); } } @@ -2139,7 +2094,11 @@ pub struct OngoingCodegen { } impl OngoingCodegen { - pub fn join(self, sess: &Session) -> (CompiledModules, FxIndexMap) { + pub fn join( + self, + sess: &Session, + crate_info: &CrateInfo, + ) -> (CompiledModules, FxIndexMap) { self.shared_emitter_main.check(sess, true); let maybe_lto_modules = sess.time("join_worker_thread", || match self.coordinator.join() { @@ -2163,12 +2122,7 @@ impl OngoingCodegen { drop(shared_emitter); compiled_modules } - MaybeLtoModules::FatLto { - cgcx, - exported_symbols_for_lto, - each_linked_rlib_file_for_lto, - needs_fat_lto, - } => { + MaybeLtoModules::FatLto { cgcx, needs_fat_lto } => { let tm_factory = self.backend.target_machine_factory( sess, cgcx.opt_level, @@ -2181,19 +2135,14 @@ impl OngoingCodegen { &cgcx, shared_emitter, tm_factory, - &exported_symbols_for_lto, - &each_linked_rlib_file_for_lto, + &crate_info.exported_symbols_for_lto, + &crate_info.each_linked_rlib_file_for_lto, needs_fat_lto, )], allocator_module: None, } } - MaybeLtoModules::ThinLto { - cgcx, - exported_symbols_for_lto, - each_linked_rlib_file_for_lto, - needs_thin_lto, - } => { + MaybeLtoModules::ThinLto { cgcx, needs_thin_lto } => { let tm_factory = self.backend.target_machine_factory( sess, cgcx.opt_level, @@ -2206,8 +2155,8 @@ impl OngoingCodegen { &sess.prof, shared_emitter, tm_factory, - exported_symbols_for_lto, - each_linked_rlib_file_for_lto, + &crate_info.exported_symbols_for_lto, + &crate_info.each_linked_rlib_file_for_lto, needs_thin_lto, ), allocator_module: None, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 4e2884c8cb63f..947475f8a0b22 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -686,11 +686,7 @@ pub fn allocator_shim_contents(tcx: TyCtxt<'_>, kind: AllocatorKind) -> Vec( - backend: B, - tcx: TyCtxt<'_>, - crate_info: &CrateInfo, -) -> OngoingCodegen { +pub fn codegen_crate(backend: B, tcx: TyCtxt<'_>) -> OngoingCodegen { if tcx.sess.target.need_explicit_cpu && tcx.sess.opts.cg.target_cpu.is_none() { // The target has no default cpu, but none is set explicitly tcx.dcx().emit_fatal(errors::CpuRequired); @@ -734,7 +730,7 @@ pub fn codegen_crate( None }; - let ongoing_codegen = start_async_codegen(backend.clone(), tcx, crate_info, allocator_module); + let ongoing_codegen = start_async_codegen(backend.clone(), tcx, allocator_module); // For better throughput during parallel processing by LLVM, we used to sort // CGUs largest to smallest. This would lead to better thread utilization @@ -959,6 +955,8 @@ impl CrateInfo { natvis_debugger_visualizers: Default::default(), lint_levels: CodegenLintLevels::from_tcx(tcx), metadata_symbol: exported_symbols::metadata_symbol_name(tcx), + each_linked_rlib_file_for_lto: Default::default(), + exported_symbols_for_lto: Default::default(), }; info.native_libraries.reserve(n_crates); @@ -1044,6 +1042,25 @@ impl CrateInfo { }); } + let mut each_linked_rlib_for_lto = Vec::new(); + let mut each_linked_rlib_file_for_lto = Vec::new(); + if tcx.sess.lto() != config::Lto::No && tcx.sess.lto() != config::Lto::ThinLocal { + drop(crate::back::link::each_linked_rlib(&info, None, &mut |cnum, path| { + if crate::back::link::ignored_for_lto(tcx.sess, &info, cnum) { + return; + } + + each_linked_rlib_for_lto.push(cnum); + each_linked_rlib_file_for_lto.push(path.to_path_buf()); + })); + } + info.each_linked_rlib_file_for_lto = each_linked_rlib_file_for_lto; + + // FIXME move to -Zlink-only half such that each_linked_rlib_file_for_lto can be moved there too + // Compute the set of symbols we need to retain when doing LTO (if we need to) + info.exported_symbols_for_lto = + crate::back::lto::exported_symbols_for_lto(tcx, &each_linked_rlib_for_lto); + let embed_visualizers = tcx.crate_types().iter().any(|&crate_type| match crate_type { CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => { // These are crate types for which we invoke the linker and can embed diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 22290d672c611..d48b54166270e 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -95,19 +95,14 @@ impl ModuleCodegen { emit_asm: bool, emit_ir: bool, outputs: &OutputFilenames, - invocation_temp: Option<&str>, ) -> CompiledModule { - let object = emit_obj - .then(|| outputs.temp_path_for_cgu(OutputType::Object, &self.name, invocation_temp)); - let dwarf_object = - emit_dwarf_obj.then(|| outputs.temp_path_dwo_for_cgu(&self.name, invocation_temp)); - let bytecode = emit_bc - .then(|| outputs.temp_path_for_cgu(OutputType::Bitcode, &self.name, invocation_temp)); - let assembly = emit_asm - .then(|| outputs.temp_path_for_cgu(OutputType::Assembly, &self.name, invocation_temp)); - let llvm_ir = emit_ir.then(|| { - outputs.temp_path_for_cgu(OutputType::LlvmAssembly, &self.name, invocation_temp) - }); + let object = emit_obj.then(|| outputs.temp_path_for_cgu(OutputType::Object, &self.name)); + let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo_for_cgu(&self.name)); + let bytecode = emit_bc.then(|| outputs.temp_path_for_cgu(OutputType::Bitcode, &self.name)); + let assembly = + emit_asm.then(|| outputs.temp_path_for_cgu(OutputType::Assembly, &self.name)); + let llvm_ir = + emit_ir.then(|| outputs.temp_path_for_cgu(OutputType::LlvmAssembly, &self.name)); CompiledModule { name: self.name, @@ -230,6 +225,8 @@ pub struct CrateInfo { pub natvis_debugger_visualizers: BTreeSet, pub lint_levels: CodegenLintLevels, pub metadata_symbol: String, + pub each_linked_rlib_file_for_lto: Vec, + pub exported_symbols_for_lto: Vec, } /// Target-specific options that get set in `cfg(...)`. diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 7b95562ddda37..9898b67b91f78 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -104,7 +104,7 @@ pub trait CodegenBackend { fn target_cpu(&self, sess: &Session) -> String; - fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, crate_info: &CrateInfo) -> Box; + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box; /// This is called on the returned `Box` from [`codegen_crate`](Self::codegen_crate) /// @@ -116,6 +116,7 @@ pub trait CodegenBackend { ongoing_codegen: Box, sess: &Session, outputs: &OutputFilenames, + crate_info: &CrateInfo, ) -> (CompiledModules, FxIndexMap); fn print_pass_timings(&self) {} diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 17effa07e3bcb..931317f80110b 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -459,22 +459,6 @@ impl StableOrd for String { const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = (); } -impl ToStableHashKey for String { - type KeyType = String; - #[inline] - fn to_stable_hash_key(&self, _: &mut Hcx) -> Self::KeyType { - self.clone() - } -} - -impl ToStableHashKey for (T1, T2) { - type KeyType = (T1::KeyType, T2::KeyType); - #[inline] - fn to_stable_hash_key(&self, hcx: &mut Hcx) -> Self::KeyType { - (self.0.to_stable_hash_key(hcx), self.1.to_stable_hash_key(hcx)) - } -} - impl StableHash for bool { #[inline] fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index f268192233c0d..917b685958da4 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -4,7 +4,6 @@ use std::fmt::Debug; use rustc_ast as ast; use rustc_ast::NodeId; -use rustc_data_structures::stable_hasher::ToStableHashKey; use rustc_data_structures::unord::UnordMap; use rustc_error_messages::{DiagArgValue, IntoDiagArg}; use rustc_macros::{Decodable, Encodable, StableHash}; @@ -712,15 +711,6 @@ impl IntoDiagArg for Namespace { } } -impl ToStableHashKey for Namespace { - type KeyType = Namespace; - - #[inline] - fn to_stable_hash_key(&self, _: &mut Hcx) -> Namespace { - *self - } -} - /// Just a helper ‒ separate structure for each namespace. #[derive(Copy, Clone, Default, Debug, StableHash)] pub struct PerNS { diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 606a47bc4a229..77a9f3617f989 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -1,59 +1,7 @@ -use rustc_data_structures::stable_hasher::{ - StableHash, StableHashCtxt, StableHasher, ToStableHashKey, -}; -use rustc_span::def_id::DefPathHash; +use rustc_data_structures::stable_hasher::{StableHash, StableHashCtxt, StableHasher}; use crate::HashIgnoredAttrId; -use crate::hir::{ - AttributeMap, BodyId, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, -}; -use crate::hir_id::ItemLocalId; - -impl ToStableHashKey for BodyId { - type KeyType = (DefPathHash, ItemLocalId); - - #[inline] - fn to_stable_hash_key(&self, hcx: &mut Hcx) -> (DefPathHash, ItemLocalId) { - let BodyId { hir_id } = *self; - hir_id.to_stable_hash_key(hcx) - } -} - -impl ToStableHashKey for ItemId { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &mut Hcx) -> DefPathHash { - self.owner_id.def_id.to_stable_hash_key(hcx) - } -} - -impl ToStableHashKey for TraitItemId { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &mut Hcx) -> DefPathHash { - self.owner_id.def_id.to_stable_hash_key(hcx) - } -} - -impl ToStableHashKey for ImplItemId { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &mut Hcx) -> DefPathHash { - self.owner_id.def_id.to_stable_hash_key(hcx) - } -} - -impl ToStableHashKey for ForeignItemId { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &mut Hcx) -> DefPathHash { - self.owner_id.def_id.to_stable_hash_key(hcx) - } -} +use crate::hir::{AttributeMap, OwnerNodes}; // The following implementations of StableHash for `ItemId`, `TraitItemId`, and // `ImplItemId` deserve special attention. Normally we do not hash `NodeId`s within diff --git a/compiler/rustc_hir_id/src/lib.rs b/compiler/rustc_hir_id/src/lib.rs index 3bbd46f4844e1..752ba4e8de394 100644 --- a/compiler/rustc_hir_id/src/lib.rs +++ b/compiler/rustc_hir_id/src/lib.rs @@ -176,22 +176,3 @@ pub const CRATE_HIR_ID: HirId = HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::ZERO }; pub const CRATE_OWNER_ID: OwnerId = OwnerId { def_id: CRATE_DEF_ID }; - -impl ToStableHashKey for HirId { - type KeyType = (DefPathHash, ItemLocalId); - - #[inline] - fn to_stable_hash_key(&self, hcx: &mut Hcx) -> (DefPathHash, ItemLocalId) { - let def_path_hash = self.owner.def_id.to_stable_hash_key(hcx); - (def_path_hash, self.local_id) - } -} - -impl ToStableHashKey for ItemLocalId { - type KeyType = ItemLocalId; - - #[inline] - fn to_stable_hash_key(&self, _: &mut Hcx) -> ItemLocalId { - *self - } -} diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index c234e21b92541..9c115736a3d4f 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +rand = "0.9.0" rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } rustc_ast_passes = { path = "../rustc_ast_passes" } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index cb41974af41b0..bcd1a52ce9dcd 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1305,8 +1305,6 @@ pub(crate) fn start_codegen<'tcx>( let metadata = rustc_metadata::fs::encode_and_write_metadata(tcx); - let crate_info = CrateInfo::new(tcx, codegen_backend.target_cpu(tcx.sess)); - let codegen = tcx.sess.time("codegen_crate", || { if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { // Skip crate items and just output metadata in -Z no-codegen mode. @@ -1315,7 +1313,7 @@ pub(crate) fn start_codegen<'tcx>( // Linker::link will skip join_codegen in case of a CodegenResults Any value. Box::new(CompiledModules { modules: vec![], allocator_module: None }) } else { - codegen_backend.codegen_crate(tcx, &crate_info) + codegen_backend.codegen_crate(tcx) } }); @@ -1327,6 +1325,8 @@ pub(crate) fn start_codegen<'tcx>( tcx.sess.code_stats.print_type_sizes(); } + let crate_info = CrateInfo::new(tcx, codegen_backend.target_cpu(tcx.sess)); + (codegen, crate_info, metadata) } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 63c7332893b81..fd1b5104fc6d3 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -53,9 +53,12 @@ impl Linker { // This was a check only build Ok(compiled_modules) => (*compiled_modules, IndexMap::default()), - Err(ongoing_codegen) => { - codegen_backend.join_codegen(ongoing_codegen, sess, &self.output_filenames) - } + Err(ongoing_codegen) => codegen_backend.join_codegen( + ongoing_codegen, + sess, + &self.output_filenames, + &self.crate_info, + ), } }); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 24b23cc4199e9..d7d306918fd0d 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -5,6 +5,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, OnceLock}; use std::{env, thread}; +use rand::{RngCore, rng}; use rustc_ast as ast; use rustc_attr_parsing::ShouldEmit; use rustc_codegen_ssa::back::archive::{ArArchiveBuilderBuilder, ArchiveBuilderBuilder}; @@ -12,6 +13,7 @@ use rustc_codegen_ssa::back::link::link_binary; use rustc_codegen_ssa::target_features::cfg_target_feature; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::{CompiledModules, CrateInfo, TargetConfig}; +use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::sync; @@ -406,7 +408,7 @@ impl CodegenBackend for DummyCodegenBackend { String::new() } - fn codegen_crate<'tcx>(&self, _tcx: TyCtxt<'tcx>, _crate_info: &CrateInfo) -> Box { + fn codegen_crate<'tcx>(&self, _tcx: TyCtxt<'tcx>) -> Box { Box::new(CompiledModules { modules: vec![], allocator_module: None }) } @@ -415,6 +417,7 @@ impl CodegenBackend for DummyCodegenBackend { ongoing_codegen: Box, _sess: &Session, _outputs: &OutputFilenames, + _crate_info: &CrateInfo, ) -> (CompiledModules, FxIndexMap) { (*ongoing_codegen.downcast().unwrap(), FxIndexMap::default()) } @@ -615,6 +618,12 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu parse_crate_name(sess, attrs, ShouldEmit::Nothing).map(|i| i.0.to_string()) }); + let invocation_temp = sess + .opts + .incremental + .as_ref() + .map(|_| rng().next_u32().to_base_fixed_len(CASE_INSENSITIVE).to_string()); + match sess.io.output_file { None => { // "-" as input file will cause the parser to read from stdin so we @@ -631,6 +640,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu stem, None, sess.io.temps_dir.clone(), + invocation_temp, sess.opts.unstable_opts.split_dwarf_out_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), @@ -661,6 +671,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu out_filestem, ofile, sess.io.temps_dir.clone(), + invocation_temp, sess.opts.unstable_opts.split_dwarf_out_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index bb047e9782d44..f45c242800830 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -138,17 +138,16 @@ declare_lint_pass!(ImproperCTypesLint => [ USES_POWER_ALIGNMENT ]); -/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple). -#[inline] -fn get_type_from_field<'tcx>( +/// A common pattern in this lint is to attempt normalize_erasing_regions, +/// but keep the original type if it were to fail. +/// This may or may not be supported in the logic behind the `Unnormalized` wrapper, +/// (FIXME?) +/// but it should be enough for non-wrapped types to be as normalised as this lint needs them to be. +fn maybe_normalize_erasing_regions<'tcx>( cx: &LateContext<'tcx>, - field: &ty::FieldDef, - args: GenericArgsRef<'tcx>, + value: Unnormalized<'tcx, Ty<'tcx>>, ) -> Ty<'tcx> { - let field_ty = field.ty(cx.tcx, args); - cx.tcx - .try_normalize_erasing_regions(cx.typing_env(), Unnormalized::new_wip(field_ty)) - .unwrap_or(field_ty) + cx.tcx.try_normalize_erasing_regions(cx.typing_env(), value).unwrap_or(value.skip_norm_wip()) } /// Check a variant of a non-exhaustive enum for improper ctypes @@ -257,12 +256,22 @@ fn check_struct_for_power_alignment<'tcx>( } } +/// Annotates whether we are in the context of an item *defined* in rust +/// and exposed to an FFI boundary, +/// or the context of an item from elsewhere, whose interface is re-*declared* in rust. #[derive(Clone, Copy)] enum CItemKind { Declaration, Definition, } +/// Annotates whether we are in the context of a function's argument types or return type. +#[derive(Clone, Copy)] +enum FnPos { + Arg, + Ret, +} + enum FfiResult<'tcx> { FfiSafe, FfiPhantom(Ty<'tcx>), @@ -286,8 +295,10 @@ enum IndirectionKind { } bitflags! { + /// VisitorState flags that are linked with the root type's use. + /// (These are the permanent part of the state, kept when visiting new Ty.) #[derive(Clone, Copy, Debug, PartialEq, Eq)] - struct VisitorState: u8 { + struct RootUseFlags: u8 { /// For use in (externally-linked) static variables. const STATIC = 0b000001; /// For use in functions in general. @@ -302,7 +313,45 @@ bitflags! { } } -impl VisitorState { +/// Description of the relationship between current Ty and +/// the type (or lack thereof) immediately containing it +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum OuterTyKind { + None, + /// A variant that should not exist, + /// but is needed because we don't change the lint's behavior yet + NoneThroughFnPtr, + /// Placeholder for properties that will be used eventually + Other, +} + +impl OuterTyKind { + /// Computes the relationship by providing the containing Ty itself + fn from_ty<'tcx>(ty: Ty<'tcx>) -> Self { + match ty.kind() { + ty::FnPtr(..) => Self::NoneThroughFnPtr, + ty::RawPtr(..) + | ty::Ref(..) + | ty::Adt(..) + | ty::Tuple(..) + | ty::Array(..) + | ty::Slice(_) => OuterTyKind::Other, + _ => bug!("Unexpected outer type {ty:?}"), + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +struct VisitorState { + /// Flags describing both the overall context in which the current Ty is, + /// linked to how the Visitor's original Ty was used. + root_use_flags: RootUseFlags, + /// Flags describing both the immediate context in which the current Ty is, + /// linked to how it relates to its parent Ty (or lack thereof). + outer_ty_kind: OuterTyKind, +} + +impl RootUseFlags { // The values that can be set. const STATIC_TY: Self = Self::STATIC; const ARGUMENT_TY_IN_DEFINITION: Self = @@ -317,86 +366,85 @@ impl VisitorState { const RETURN_TY_IN_FNPTR: Self = Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits() | Self::FN_RETURN.bits()) .unwrap(); +} - /// Get the proper visitor state for a given function's arguments. - fn argument_from_fnmode(fn_mode: CItemKind) -> Self { - match fn_mode { - CItemKind::Definition => VisitorState::ARGUMENT_TY_IN_DEFINITION, - CItemKind::Declaration => VisitorState::ARGUMENT_TY_IN_DECLARATION, +impl VisitorState { + /// From an existing state, compute the state of any subtype of the current type. + /// (General case. For the case where the current type is a function pointer, see `next_in_fnptr`.) + fn next(&self, current_ty: Ty<'_>) -> Self { + assert!(!matches!(current_ty.kind(), ty::FnPtr(..))); + VisitorState { + root_use_flags: self.root_use_flags, + outer_ty_kind: OuterTyKind::from_ty(current_ty), } } - /// Get the proper visitor state for a given function's return type. - fn return_from_fnmode(fn_mode: CItemKind) -> Self { - match fn_mode { - CItemKind::Definition => VisitorState::RETURN_TY_IN_DEFINITION, - CItemKind::Declaration => VisitorState::RETURN_TY_IN_DECLARATION, + /// From an existing state, compute the state of any subtype of the current type. + /// (Case where the current type is a function pointer, + /// meaning we need to specify if the subtype is an argument or the return.) + fn next_in_fnptr(&self, current_ty: Ty<'_>, fn_pos: FnPos) -> Self { + assert!(matches!(current_ty.kind(), ty::FnPtr(..))); + VisitorState { + root_use_flags: match fn_pos { + FnPos::Ret => RootUseFlags::RETURN_TY_IN_FNPTR, + FnPos::Arg => RootUseFlags::ARGUMENT_TY_IN_FNPTR, + }, + outer_ty_kind: OuterTyKind::from_ty(current_ty), } } + /// Get the proper visitor state for a given function's arguments or return type. + fn fn_entry_point(fn_mode: CItemKind, fn_pos: FnPos) -> Self { + let p_flags = match (fn_mode, fn_pos) { + (CItemKind::Definition, FnPos::Ret) => RootUseFlags::RETURN_TY_IN_DEFINITION, + (CItemKind::Declaration, FnPos::Ret) => RootUseFlags::RETURN_TY_IN_DECLARATION, + (CItemKind::Definition, FnPos::Arg) => RootUseFlags::ARGUMENT_TY_IN_DEFINITION, + (CItemKind::Declaration, FnPos::Arg) => RootUseFlags::ARGUMENT_TY_IN_DECLARATION, + }; + VisitorState { root_use_flags: p_flags, outer_ty_kind: OuterTyKind::None } + } + + /// Get the proper visitor state for a static variable's type + fn static_entry_point() -> Self { + VisitorState { root_use_flags: RootUseFlags::STATIC_TY, outer_ty_kind: OuterTyKind::None } + } + /// Whether the type is used in a function. - fn is_in_function(self) -> bool { - let ret = self.contains(Self::FUNC); + fn is_in_function(&self) -> bool { + let ret = self.root_use_flags.contains(RootUseFlags::FUNC); if ret { - debug_assert!(!self.contains(Self::STATIC)); + debug_assert!(!self.root_use_flags.contains(RootUseFlags::STATIC)); } ret } + /// Whether the type is used (directly or not) in a function, in return position. - fn is_in_function_return(self) -> bool { - let ret = self.contains(Self::FN_RETURN); + fn is_in_function_return(&self) -> bool { + let ret = self.root_use_flags.contains(RootUseFlags::FN_RETURN); if ret { debug_assert!(self.is_in_function()); } ret } + /// Whether the type is used (directly or not) in a defined function. /// In other words, whether or not we allow non-FFI-safe types behind a C pointer, /// to be treated as an opaque type on the other side of the FFI boundary. - fn is_in_defined_function(self) -> bool { - self.contains(Self::DEFINED) && self.is_in_function() + fn is_in_defined_function(&self) -> bool { + self.root_use_flags.contains(RootUseFlags::DEFINED) && self.is_in_function() } /// Whether the type is used (directly or not) in a function pointer type. /// Here, we also allow non-FFI-safe types behind a C pointer, /// to be treated as an opaque type on the other side of the FFI boundary. - fn is_in_fnptr(self) -> bool { - self.contains(Self::THEORETICAL) && self.is_in_function() + fn is_in_fnptr(&self) -> bool { + self.root_use_flags.contains(RootUseFlags::THEORETICAL) && self.is_in_function() } /// Whether we can expect type parameters and co in a given type. - fn can_expect_ty_params(self) -> bool { + fn can_expect_ty_params(&self) -> bool { // rust-defined functions, as well as FnPtrs - self.contains(Self::THEORETICAL) || self.is_in_defined_function() - } -} - -bitflags! { - /// Data that summarises how an "outer type" surrounds its inner type(s) - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - struct OuterTyData: u8 { - /// To show that there is no outer type, the current type is directly used by a `static` - /// variable or a function/FnPtr - const NO_OUTER_TY = 0b01; - /// For NO_OUTER_TY cases, show that we are being directly used by a FnPtr specifically - /// FIXME(ctypes): this is only used for "bad behaviour" reproduced for compatibility's sake - const NO_OUTER_TY_FNPTR = 0b10; - } -} - -impl OuterTyData { - /// Get the proper data for a given outer type. - fn from_ty<'tcx>(ty: Ty<'tcx>) -> Self { - match ty.kind() { - ty::FnPtr(..) => Self::NO_OUTER_TY | Self::NO_OUTER_TY_FNPTR, - ty::RawPtr(..) - | ty::Ref(..) - | ty::Adt(..) - | ty::Tuple(..) - | ty::Array(..) - | ty::Slice(_) => Self::empty(), - k @ _ => bug!("unexpected outer type {:?} of kind {:?}", ty, k), - } + self.root_use_flags.contains(RootUseFlags::THEORETICAL) || self.is_in_defined_function() } } @@ -415,8 +463,17 @@ struct ImproperCTypesVisitor<'a, 'tcx> { } impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { - fn new(cx: &'a LateContext<'tcx>, base_ty: Ty<'tcx>, base_fn_mode: CItemKind) -> Self { - Self { cx, base_ty, base_fn_mode, cache: FxHashSet::default() } + fn new( + cx: &'a LateContext<'tcx>, + base_ty: Unnormalized<'tcx, Ty<'tcx>>, + base_fn_mode: CItemKind, + ) -> Self { + ImproperCTypesVisitor { + cx, + base_ty: maybe_normalize_erasing_regions(cx, base_ty), + base_fn_mode, + cache: FxHashSet::default(), + } } /// Checks if the given indirection (box,ref,pointer) is "ffi-safe". @@ -485,7 +542,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { { FfiSafe } else { - self.visit_type(state, OuterTyData::from_ty(ty), inner_ty) + self.visit_type(state.next(ty), inner_ty) } } } @@ -505,8 +562,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let transparent_with_all_zst_fields = if def.repr().transparent() { if let Some(field) = super::transparent_newtype_field(self.cx.tcx, variant) { // Transparent newtypes have at most one non-ZST field which needs to be checked.. - let field_ty = get_type_from_field(self.cx, field, args); - match self.visit_type(state, OuterTyData::from_ty(ty), field_ty) { + let field_ty = maybe_normalize_erasing_regions( + self.cx, + Unnormalized::new_wip(field.ty(self.cx.tcx, args)), + ); + match self.visit_type(state.next(ty), field_ty) { FfiUnsafe { ty, .. } if ty.is_unit() => (), r => return r, } @@ -524,8 +584,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe. let mut all_phantom = !variant.fields.is_empty(); for field in &variant.fields { - let field_ty = get_type_from_field(self.cx, field, args); - all_phantom &= match self.visit_type(state, OuterTyData::from_ty(ty), field_ty) { + let field_ty = maybe_normalize_erasing_regions( + self.cx, + Unnormalized::new_wip(field.ty(self.cx.tcx, args)), + ); + all_phantom &= match self.visit_type(state.next(ty), field_ty) { FfiSafe => false, // `()` fields are FFI-safe! FfiUnsafe { ty, .. } if ty.is_unit() => false, @@ -570,7 +633,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { "consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct" )) } else { - // FIXME(ctypes): confirm that this makes sense for unions once #60405 / RFC2645 stabilises + // FIXME(#60405): confirm that this makes sense for unions once #60405 / RFC2645 stabilises Some(msg!( "consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union" )) @@ -628,7 +691,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none() { // Special-case types like `Option` and `Result` if let Some(inner_ty) = repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty) { - return self.visit_type(state, OuterTyData::from_ty(ty), inner_ty); + return self.visit_type(state.next(ty), inner_ty); } return FfiUnsafe { @@ -660,12 +723,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Checks if the given type is "ffi-safe" (has a stable, well-defined /// representation which can be exported to C code). - fn visit_type( - &mut self, - state: VisitorState, - outer_ty: OuterTyData, - ty: Ty<'tcx>, - ) -> FfiResult<'tcx> { + fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> { use FfiResult::*; let tcx = self.cx.tcx; @@ -709,7 +767,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Pattern types are just extra invariants on the type that you need to uphold, // but only the base type is relevant for being representable in FFI. // (note: this lint was written when pattern types could only be integers constrained to ranges) - ty::Pat(pat_ty, _) => self.visit_type(state, outer_ty, pat_ty), + // (also note: the lack of ".next(ty)" on the state is on purpose) + ty::Pat(pat_ty, _) => self.visit_type(state, pat_ty), // types which likely have a stable representation, if the target architecture defines those // note: before rust 1.77, 128-bit ints were not FFI-safe on x86_64 @@ -740,12 +799,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }, ty::Tuple(tuple) => { - // C functions can return void - let empty_and_safe = tuple.is_empty() - && outer_ty.contains(OuterTyData::NO_OUTER_TY) - && state.is_in_function_return(); - - if empty_and_safe { + if tuple.is_empty() + && state.is_in_function_return() + && matches!( + state.outer_ty_kind, + OuterTyKind::None | OuterTyKind::NoneThroughFnPtr + ) + { + // C functions can return void FfiSafe } else { FfiUnsafe { @@ -774,9 +835,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Array(inner_ty, _) => { if state.is_in_function() - && outer_ty.contains(OuterTyData::NO_OUTER_TY) - // FIXME(ctypes): VVV-this-VVV shouldn't be the case - && !outer_ty.contains(OuterTyData::NO_OUTER_TY_FNPTR) + // FIXME(ctypes): VVV-this-VVV shouldn't make a difference between ::None and ::NoneThroughFnPtr + && matches!(state.outer_ty_kind, OuterTyKind::None) { // C doesn't really support passing arrays by value - the only way to pass an array by value // is through a struct. @@ -788,7 +848,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } else { // let's allow phantoms to go through, // since an array of 1-ZSTs is also a 1-ZST - self.visit_type(state, OuterTyData::from_ty(ty), inner_ty) + self.visit_type(state.next(ty), inner_ty) } } @@ -806,19 +866,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let sig = tcx.instantiate_bound_regions_with_erased(sig); for arg in sig.inputs() { - match self.visit_type( - VisitorState::ARGUMENT_TY_IN_FNPTR, - OuterTyData::from_ty(ty), - *arg, - ) { + match self.visit_type(state.next_in_fnptr(ty, FnPos::Arg), *arg) { FfiSafe => {} r => return r, } } let ret_ty = sig.output(); - - self.visit_type(VisitorState::RETURN_TY_IN_FNPTR, OuterTyData::from_ty(ty), ret_ty) + self.visit_type(state.next_in_fnptr(ty, FnPos::Ret), ret_ty) } ty::Foreign(..) => FfiSafe, @@ -886,17 +941,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }) } - fn check_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> { - let ty = self - .cx - .tcx - .try_normalize_erasing_regions(self.cx.typing_env(), Unnormalized::new_wip(ty)) - .unwrap_or(ty); + fn check_type( + &mut self, + state: VisitorState, + ty: Unnormalized<'tcx, Ty<'tcx>>, + ) -> FfiResult<'tcx> { + let ty = maybe_normalize_erasing_regions(self.cx, ty); if let Some(res) = self.visit_for_opaque_ty(ty) { return res; } - self.visit_type(state, OuterTyData::NO_OUTER_TY, ty) + self.visit_type(state, ty) } } @@ -925,7 +980,7 @@ impl<'tcx> ImproperCTypesLint { self.spans.push(ty.span); } - hir::intravisit::walk_ty(self, ty) + hir::intravisit::walk_ty(self, ty); } } @@ -949,6 +1004,7 @@ impl<'tcx> ImproperCTypesLint { let all_types = iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)); for (fn_ptr_ty, span) in all_types { + let fn_ptr_ty = Unnormalized::new_wip(fn_ptr_ty); let mut visitor = ImproperCTypesVisitor::new(cx, fn_ptr_ty, fn_mode); // FIXME(ctypes): make a check_for_fnptr let ffi_res = visitor.check_type(state, fn_ptr_ty); @@ -970,12 +1026,12 @@ impl<'tcx> ImproperCTypesLint { let sig = cx.tcx.instantiate_bound_regions_with_erased(sig); for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { - let state = VisitorState::argument_from_fnmode(fn_mode); + let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg); self.check_type_for_external_abi_fnptr(cx, state, input_hir, *input_ty, fn_mode); } if let hir::FnRetTy::Return(ret_hir) = decl.output { - let state = VisitorState::return_from_fnmode(fn_mode); + let state = VisitorState::fn_entry_point(fn_mode, FnPos::Ret); self.check_type_for_external_abi_fnptr(cx, state, ret_hir, sig.output(), fn_mode); } } @@ -998,9 +1054,9 @@ impl<'tcx> ImproperCTypesLint { } fn check_foreign_static(&mut self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) { - let ty = cx.tcx.type_of(id).instantiate_identity().skip_norm_wip(); + let ty = cx.tcx.type_of(id).instantiate_identity(); let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration); - let ffi_res = visitor.check_type(VisitorState::STATIC_TY, ty); + let ffi_res = visitor.check_type(VisitorState::static_entry_point(), ty); self.process_ffi_result(cx, span, ffi_res, CItemKind::Declaration); } @@ -1016,16 +1072,18 @@ impl<'tcx> ImproperCTypesLint { let sig = cx.tcx.instantiate_bound_regions_with_erased(sig); for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { - let state = VisitorState::argument_from_fnmode(fn_mode); - let mut visitor = ImproperCTypesVisitor::new(cx, *input_ty, fn_mode); - let ffi_res = visitor.check_type(state, *input_ty); + let input_ty = Unnormalized::new_wip(*input_ty); + let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg); + let mut visitor = ImproperCTypesVisitor::new(cx, input_ty, fn_mode); + let ffi_res = visitor.check_type(state, input_ty); self.process_ffi_result(cx, input_hir.span, ffi_res, fn_mode); } if let hir::FnRetTy::Return(ret_hir) = decl.output { - let state = VisitorState::return_from_fnmode(fn_mode); - let mut visitor = ImproperCTypesVisitor::new(cx, sig.output(), fn_mode); - let ffi_res = visitor.check_type(state, sig.output()); + let output_ty = Unnormalized::new_wip(sig.output()); + let state = VisitorState::fn_entry_point(fn_mode, FnPos::Ret); + let mut visitor = ImproperCTypesVisitor::new(cx, output_ty, fn_mode); + let ffi_res = visitor.check_type(state, output_ty); self.process_ffi_result(cx, ret_hir.span, ffi_res, fn_mode); } } @@ -1124,7 +1182,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint { | hir::ItemKind::TyAlias(_, _, ty) => { self.check_type_for_external_abi_fnptr( cx, - VisitorState::STATIC_TY, + VisitorState::static_entry_point(), ty, cx.tcx.type_of(item.owner_id).instantiate_identity().skip_norm_wip(), CItemKind::Definition, @@ -1158,7 +1216,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint { fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'tcx>) { self.check_type_for_external_abi_fnptr( cx, - VisitorState::STATIC_TY, + VisitorState::static_entry_point(), field.ty, cx.tcx.type_of(field.def_id).instantiate_identity().skip_norm_wip(), CItemKind::Definition, diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 517f2954c5461..025f36a34f00d 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -3,12 +3,11 @@ use std::fmt::Display; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stable_hasher::{ - StableCompare, StableHash, StableHashCtxt, StableHasher, ToStableHashKey, + StableCompare, StableHash, StableHashCtxt, StableHasher, }; use rustc_error_messages::{DiagArgValue, IntoDiagArg}; -use rustc_hir_id::{HirId, ItemLocalId}; +use rustc_hir_id::HirId; use rustc_macros::{Decodable, Encodable, StableHash}; -use rustc_span::def_id::DefPathHash; pub use rustc_span::edition::Edition; use rustc_span::{AttrId, Ident, Symbol, sym}; use serde::{Deserialize, Serialize}; @@ -154,23 +153,6 @@ impl StableHash for LintExpectationId { } } -impl ToStableHashKey for LintExpectationId { - type KeyType = (DefPathHash, ItemLocalId, u16, u16); - - #[inline] - fn to_stable_hash_key(&self, hcx: &mut Hcx) -> Self::KeyType { - match self { - LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => { - let (def_path_hash, lint_idx) = hir_id.to_stable_hash_key(hcx); - (def_path_hash, lint_idx, *attr_index, *lint_index) - } - _ => { - unreachable!("StableHash should only be called for a filled `LintExpectationId`") - } - } - } -} - /// Setting for how to handle a lint. /// /// See: @@ -623,15 +605,6 @@ impl StableHash for LintId { } } -impl ToStableHashKey for LintId { - type KeyType = &'static str; - - #[inline] - fn to_stable_hash_key(&self, _: &mut Hcx) -> &'static str { - self.lint_name_raw() - } -} - impl StableCompare for LintId { const CAN_USE_UNSTABLE_SORT: bool = true; diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 38ceac7ae5bda..60a4b66d39187 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -51,7 +51,7 @@ use std::fmt; use std::hash::Hash; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; -use rustc_data_structures::stable_hasher::{StableHasher, StableOrd, ToStableHashKey}; +use rustc_data_structures::stable_hasher::{StableHasher, StableOrd}; use rustc_hir::def_id::DefId; use rustc_hir::definitions::DefPathHash; use rustc_macros::{Decodable, Encodable, StableHash}; @@ -231,13 +231,7 @@ impl WorkProductId { WorkProductId { hash: hasher.finish() } } } -impl ToStableHashKey for WorkProductId { - type KeyType = Fingerprint; - #[inline] - fn to_stable_hash_key(&self, _: &mut Hcx) -> Self::KeyType { - self.hash - } -} + impl StableOrd for WorkProductId { // Fingerprint can use unstable (just a tuple of `u64`s), so WorkProductId can as well const CAN_USE_UNSTABLE_SORT: bool = true; diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 5c92f126e116c..71bd08861b8d5 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -5,6 +5,7 @@ use std::fmt::Debug; use std::hash::Hash; use rustc_ast::tokenstream::TokenStream; +use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::stable_hasher::StableHash; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::hir_id::OwnerId; @@ -256,8 +257,8 @@ impl<'tcx> QueryKey for GenericArg<'tcx> { } impl<'tcx> QueryKey for Ty<'tcx> { - fn default_span(&self, _: TyCtxt<'_>) -> Span { - DUMMY_SP + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + def_id_of_type(*self).map(|def_id| tcx.def_span(def_id)).unwrap_or(DUMMY_SP) } } @@ -360,3 +361,58 @@ impl<'tcx> QueryKey for (ty::Instance<'tcx>, CollectionMode) { self.0.default_span(tcx) } } + +/// Gets a `DefId` associated with a type +/// +/// Visited set is needed to avoid full iteration over +/// deeply nested tuples that have no DefId. +fn def_id_of_type_cached<'a>(ty: Ty<'a>, visited: &mut SsoHashSet>) -> Option { + match *ty.kind() { + ty::Adt(adt_def, _) => Some(adt_def.did()), + + ty::Dynamic(data, ..) => data.principal_def_id(), + + ty::Pat(subty, _) | ty::Array(subty, _) | ty::Slice(subty) => { + def_id_of_type_cached(subty, visited) + } + + ty::RawPtr(ty, _) => def_id_of_type_cached(ty, visited), + + ty::Ref(_, ty, _) => def_id_of_type_cached(ty, visited), + + ty::Tuple(tys) => tys.iter().find_map(|ty| { + if visited.insert(ty) { + return def_id_of_type_cached(ty, visited); + } + return None; + }), + + ty::FnDef(def_id, _) + | ty::Closure(def_id, _) + | ty::CoroutineClosure(def_id, _) + | ty::Coroutine(def_id, _) + | ty::CoroutineWitness(def_id, _) + | ty::Foreign(def_id) => Some(def_id), + + ty::Alias(alias) => Some(alias.kind.def_id()), + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Str + | ty::FnPtr(..) + | ty::UnsafeBinder(_) + | ty::Placeholder(..) + | ty::Param(_) + | ty::Infer(_) + | ty::Bound(..) + | ty::Error(_) + | ty::Never + | ty::Float(_) => None, + } +} + +fn def_id_of_type(ty: Ty<'_>) -> Option { + def_id_of_type_cached(ty, &mut SsoHashSet::new()) +} diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index 729a5049d6333..1f22e0af9c006 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -7,11 +7,10 @@ use std::ptr; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{ - HashingControls, StableHash, StableHashCtxt, StableHasher, ToStableHashKey, + HashingControls, StableHash, StableHashCtxt, StableHasher, }; use tracing::trace; -use crate::middle::region; use crate::{mir, ty}; impl<'tcx, H, T> StableHash for &'tcx ty::list::RawList @@ -45,20 +44,6 @@ where } } -impl<'tcx, H, T> ToStableHashKey for &'tcx ty::list::RawList -where - T: StableHash, -{ - type KeyType = Fingerprint; - - #[inline] - fn to_stable_hash_key(&self, hcx: &mut Hcx) -> Fingerprint { - let mut hasher = StableHasher::new(); - self.stable_hash(hcx, &mut hasher); - hasher.finish() - } -} - impl<'tcx> StableHash for ty::GenericArg<'tcx> { fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { self.kind().stable_hash(hcx, hasher); @@ -81,12 +66,3 @@ impl StableHash for mir::interpret::CtfeProvenance { self.into_parts().stable_hash(hcx, hasher); } } - -impl ToStableHashKey for region::Scope { - type KeyType = region::Scope; - - #[inline] - fn to_stable_hash_key(&self, _: &mut Hcx) -> region::Scope { - *self - } -} diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index d66e04f581069..79d05e2d20a69 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -6,7 +6,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start getopts = "0.2" -rand = "0.9.0" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f8da18632a997..fff1bae2c2264 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -14,7 +14,7 @@ use std::{cmp, fs, iter}; use externs::{ExternOpt, split_extern_opt}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_data_structures::stable_hasher::{StableHasher, StableOrd, ToStableHashKey}; +use rustc_data_structures::stable_hasher::{StableHasher, StableOrd}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagCtxtFlags}; use rustc_feature::UnstableFeatures; @@ -628,7 +628,6 @@ macro_rules! define_output_types { )* } - impl StableOrd for OutputType { const CAN_USE_UNSTABLE_SORT: bool = true; @@ -636,15 +635,6 @@ macro_rules! define_output_types { const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = (); } - impl ToStableHashKey for OutputType { - type KeyType = Self; - - fn to_stable_hash_key(&self, _: &mut Hcx) -> Self::KeyType { - *self - } - } - - impl OutputType { pub fn iter_all() -> impl Iterator { static ALL_VARIANTS: &[OutputType] = &[ @@ -1107,13 +1097,10 @@ impl OutFileName { outputs: &OutputFilenames, flavor: OutputType, codegen_unit_name: &str, - invocation_temp: Option<&str>, ) -> PathBuf { match *self { OutFileName::Real(ref path) => path.clone(), - OutFileName::Stdout => { - outputs.temp_path_for_cgu(flavor, codegen_unit_name, invocation_temp) - } + OutFileName::Stdout => outputs.temp_path_for_cgu(flavor, codegen_unit_name), } } @@ -1138,6 +1125,17 @@ pub struct OutputFilenames { filestem: String, pub single_output_file: Option, temps_directory: Option, + + /// A random string generated per invocation of rustc. + /// + /// This is prepended to all temporary files so that they do not collide + /// during concurrent invocations of rustc, or past invocations that were + /// preserved with a flag like `-C save-temps`, since these files may be + /// hard linked. + // This does not affect incr comp outputs, only where temp files are stored. + #[stable_hasher(ignore)] + invocation_temp: Option, + explicit_dwo_out_directory: Option, pub outputs: OutputTypes, } @@ -1180,6 +1178,7 @@ impl OutputFilenames { out_filestem: String, single_output_file: Option, temps_directory: Option, + invocation_temp: Option, explicit_dwo_out_directory: Option, extra: String, outputs: OutputTypes, @@ -1188,6 +1187,7 @@ impl OutputFilenames { out_directory, single_output_file, temps_directory, + invocation_temp, explicit_dwo_out_directory, outputs, crate_stem: format!("{out_crate_name}{extra}"), @@ -1224,23 +1224,14 @@ impl OutputFilenames { /// Gets the path where a compilation artifact of the given type for the /// given codegen unit should be placed on disk. If codegen_unit_name is /// None, a path distinct from those of any codegen unit will be generated. - pub fn temp_path_for_cgu( - &self, - flavor: OutputType, - codegen_unit_name: &str, - invocation_temp: Option<&str>, - ) -> PathBuf { + pub fn temp_path_for_cgu(&self, flavor: OutputType, codegen_unit_name: &str) -> PathBuf { let extension = flavor.extension(); - self.temp_path_ext_for_cgu(extension, codegen_unit_name, invocation_temp) + self.temp_path_ext_for_cgu(extension, codegen_unit_name) } /// Like `temp_path`, but specifically for dwarf objects. - pub fn temp_path_dwo_for_cgu( - &self, - codegen_unit_name: &str, - invocation_temp: Option<&str>, - ) -> PathBuf { - let p = self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp); + pub fn temp_path_dwo_for_cgu(&self, codegen_unit_name: &str) -> PathBuf { + let p = self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name); if let Some(dwo_out) = &self.explicit_dwo_out_directory { let mut o = dwo_out.clone(); o.push(p.file_name().unwrap()); @@ -1252,16 +1243,11 @@ impl OutputFilenames { /// Like `temp_path`, but also supports things where there is no corresponding /// OutputType, like noopt-bitcode or lto-bitcode. - pub fn temp_path_ext_for_cgu( - &self, - ext: &str, - codegen_unit_name: &str, - invocation_temp: Option<&str>, - ) -> PathBuf { + pub fn temp_path_ext_for_cgu(&self, ext: &str, codegen_unit_name: &str) -> PathBuf { let mut extension = codegen_unit_name.to_string(); // Append `.{invocation_temp}` to ensure temporary files are unique. - if let Some(rng) = invocation_temp { + if let Some(rng) = &self.invocation_temp { extension.push('.'); extension.push_str(rng); } @@ -1302,10 +1288,9 @@ impl OutputFilenames { split_debuginfo_kind: SplitDebuginfo, split_dwarf_kind: SplitDwarfKind, cgu_name: &str, - invocation_temp: Option<&str>, ) -> Option { - let obj_out = self.temp_path_for_cgu(OutputType::Object, cgu_name, invocation_temp); - let dwo_out = self.temp_path_dwo_for_cgu(cgu_name, invocation_temp); + let obj_out = self.temp_path_for_cgu(OutputType::Object, cgu_name); + let dwo_out = self.temp_path_dwo_for_cgu(cgu_name); match (split_debuginfo_kind, split_dwarf_kind) { (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None, // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 3b2fc53381a93..9bd5d434266ec 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -5,8 +5,6 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::{env, io}; -use rand::{RngCore, rng}; -use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; @@ -163,14 +161,6 @@ pub struct Session { target_filesearch: FileSearch, host_filesearch: FileSearch, - /// A random string generated per invocation of rustc. - /// - /// This is prepended to all temporary files so that they do not collide - /// during concurrent invocations of rustc, or past invocations that were - /// preserved with a flag like `-C save-temps`, since these files may be - /// hard linked. - pub invocation_temp: Option, - /// The names of intrinsics that the current codegen backend replaces /// with its own implementations. pub replaced_intrinsics: FxHashSet, @@ -1097,11 +1087,6 @@ pub fn build_session( filesearch::FileSearch::new(&sopts.search_paths, &target_tlib_path, &target); let host_filesearch = filesearch::FileSearch::new(&sopts.search_paths, &host_tlib_path, &host); - let invocation_temp = sopts - .incremental - .as_ref() - .map(|_| rng().next_u32().to_base_fixed_len(CASE_INSENSITIVE).to_string()); - let timings = TimingSectionHandler::new(sopts.json_timings); let sess = Session { @@ -1132,7 +1117,6 @@ pub fn build_session( file_depinfo: Default::default(), target_filesearch, host_filesearch, - invocation_temp, replaced_intrinsics: FxHashSet::default(), // filled by `run_compiler` thin_lto_supported: true, // filled by `run_compiler` mir_opt_bisect_eval_count: AtomicUsize::new(0), diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index d07c7fcfd4683..6ce3d6b309f0e 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -465,24 +465,6 @@ impl ToStableHashKey for LocalDefId { } } -impl ToStableHashKey for CrateNum { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &mut Hcx) -> DefPathHash { - self.as_def_id().to_stable_hash_key(hcx) - } -} - -impl ToStableHashKey for DefPathHash { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, _: &mut Hcx) -> DefPathHash { - *self - } -} - macro_rules! typed_def_id { ($Name:ident, $LocalName:ident) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, StableHash)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ea2880d8d7dff..a342775b136f9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -8,7 +8,7 @@ use std::{fmt, str}; use rustc_arena::DroplessArena; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::stable_hasher::{ - StableCompare, StableHash, StableHashCtxt, StableHasher, ToStableHashKey, + StableCompare, StableHash, StableHashCtxt, StableHasher, }; use rustc_data_structures::sync::Lock; use rustc_macros::{Decodable, Encodable, StableHash, symbols}; @@ -2641,14 +2641,6 @@ impl StableHash for Symbol { } } -impl ToStableHashKey for Symbol { - type KeyType = String; - #[inline] - fn to_stable_hash_key(&self, _: &mut Hcx) -> String { - self.as_str().to_string() - } -} - impl StableCompare for Symbol { const CAN_USE_UNSTABLE_SORT: bool = true; diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 4e4be901dbfff..26d98b5d8ad7d 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -5,12 +5,6 @@ use std::marker::PhantomData; use rustc_ast_ir::Mutability; #[cfg(feature = "nightly")] -use rustc_data_structures::fingerprint::Fingerprint; -#[cfg(feature = "nightly")] -use rustc_data_structures::stable_hasher::{ - StableHash, StableHashCtxt, StableHasher, ToStableHashKey, -}; -#[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, StableHash}; use crate::inherent::*; @@ -48,18 +42,6 @@ pub enum SimplifiedType { Error, } -#[cfg(feature = "nightly")] -impl ToStableHashKey for SimplifiedType { - type KeyType = Fingerprint; - - #[inline] - fn to_stable_hash_key(&self, hcx: &mut Hcx) -> Fingerprint { - let mut hasher = StableHasher::new(); - self.stable_hash(hcx, &mut hasher); - hasher.finish() - } -} - /// Generic parameters are pretty much just bound variables, e.g. /// the type of `fn foo<'a, T>(x: &'a T) -> u32 { ... }` can be thought of as /// `for<'a, T> fn(&'a T) -> u32`. diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index a8046a5541c51..6001869dbf284 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -474,6 +474,57 @@ impl TcpStream { self.0.linger() } + /// Sets the value of the `SO_KEEPALIVE` option on this socket. + /// + /// If set to `true`, the operating system will periodically send keepalive + /// probes on an idle connection to verify that the remote peer is still + /// reachable. If the peer fails to respond after a system-determined number + /// of probes, the connection is considered broken and subsequent I/O calls + /// will return an error. + /// + /// This is useful for detecting dead peers on long-lived connections where + /// no application-level traffic is exchanged, such as database or SSH + /// connections. + /// + /// The timing and frequency of keepalive probes are controlled by + /// system-level settings and are not configured by this method alone. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(tcp_keepalive)] + /// + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_keepalive(true).expect("set_keepalive call failed"); + #[unstable(feature = "tcp_keepalive", issue = "155889")] + pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> { + self.0.set_keepalive(keepalive) + } + + /// Gets the value of the `SO_KEEPALIVE` option on this socket. + /// + /// For more information about this option, see [`TcpStream::set_keepalive`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(tcp_keepalive)] + /// + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_keepalive(true).expect("set_keepalive call failed"); + /// assert_eq!(stream.keepalive().unwrap_or(false), true); + /// ``` + #[unstable(feature = "tcp_keepalive", issue = "155889")] + pub fn keepalive(&self) -> io::Result { + self.0.keepalive() + } + /// Sets the value of the `TCP_NODELAY` option on this socket. /// /// If set, this option disables the Nagle algorithm. This means that diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index af15009e665e1..f6fe8e1b2353b 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -844,6 +844,21 @@ fn linger() { assert_eq!(None, t!(stream.linger())); } +#[test] +#[cfg_attr(target_env = "sgx", ignore)] +#[cfg_attr(target_os = "wasi", ignore)] +fn keepalive() { + let addr = next_test_ip4(); + let _listener = t!(TcpListener::bind(&addr)); + let stream = t!(TcpStream::connect(&addr)); + + assert_eq!(false, t!(stream.keepalive())); + t!(stream.set_keepalive(true)); + assert_eq!(true, t!(stream.keepalive())); + t!(stream.set_keepalive(false)); + assert_eq!(false, t!(stream.keepalive())); +} + #[test] #[cfg_attr(target_env = "sgx", ignore)] fn nodelay() { diff --git a/library/std/src/path.rs b/library/std/src/path.rs index da3d9c2454a74..222bf77996c7f 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1796,6 +1796,25 @@ impl PathBuf { self.inner } + /// Converts the `PathBuf` into a `String` if it contains valid Unicode data. + /// + /// On failure, ownership of the original `PathBuf` is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(pathbuf_into_string)] + /// use std::path::PathBuf; + /// + /// let path_buf = PathBuf::from("foo"); + /// let string = path_buf.into_string(); + /// assert_eq!(string, Ok(String::from("foo"))); + /// ``` + #[unstable(feature = "pathbuf_into_string", issue = "156203")] + pub fn into_string(self) -> Result { + self.into_os_string().into_string().map_err(PathBuf::from) + } + /// Converts this `PathBuf` into a [boxed](Box) [`Path`]. #[stable(feature = "into_boxed_path", since = "1.20.0")] #[must_use = "`self` will be dropped if the result is not used"] diff --git a/library/std/src/sys/net/connection/motor.rs b/library/std/src/sys/net/connection/motor.rs index 79a528792106c..be879f43b0bb4 100644 --- a/library/std/src/sys/net/connection/motor.rs +++ b/library/std/src/sys/net/connection/motor.rs @@ -5,7 +5,7 @@ use crate::net::SocketAddr::{V4, V6}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; -use crate::sys::{AsInner, FromInner, IntoInner, map_motor_error}; +use crate::sys::{AsInner, FromInner, IntoInner, map_motor_error, unsupported}; use crate::time::Duration; // We want to re-use as much of Rust's stdlib code as possible, @@ -127,6 +127,14 @@ impl TcpStream { moto_rt::net::linger(self.inner.as_raw_fd()).map_err(map_motor_error) } + pub fn set_keepalive(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn keepalive(&self) -> io::Result { + unsupported() + } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { moto_rt::net::set_nodelay(self.inner.as_raw_fd(), nodelay).map_err(map_motor_error) } diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs index 5735a5db488fb..c72581cf69f0b 100644 --- a/library/std/src/sys/net/connection/sgx.rs +++ b/library/std/src/sys/net/connection/sgx.rs @@ -219,6 +219,14 @@ impl TcpStream { sgx_ineffective(None) } + pub fn set_keepalive(&self, _: bool) -> io::Result<()> { + sgx_ineffective(()) + } + + pub fn keepalive(&self) -> io::Result { + sgx_ineffective(false) + } + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { sgx_ineffective(()) } diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index 7bbb3fba9ad4a..09953cc515af7 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -272,6 +272,15 @@ impl Socket { Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } + pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> { + unsafe { setsockopt(self, netc::SOL_SOCKET, netc::SO_KEEPALIVE, keepalive as c_int) } + } + + pub fn keepalive(&self) -> io::Result { + let raw: c_int = unsafe { getsockopt(self, netc::SOL_SOCKET, netc::SO_KEEPALIVE)? }; + Ok(raw != 0) + } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { let value: i32 = if nodelay { 1 } else { 0 }; unsafe { setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, value) } diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 256b99dfa9874..8efe8bd785149 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -468,6 +468,14 @@ impl TcpStream { self.inner.linger() } + pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> { + self.inner.set_keepalive(keepalive) + } + + pub fn keepalive(&self) -> io::Result { + self.inner.keepalive() + } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { self.inner.set_nodelay(nodelay) } diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index 7e3cd9b6a5e0a..79e6c12d6ab33 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -6,6 +6,7 @@ use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; use crate::os::solid::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd}; +use crate::sys::pal::unsupported; use crate::sys::{FromInner, IntoInner, abi}; use crate::time::Duration; use crate::{cmp, mem, ptr, str}; @@ -332,6 +333,14 @@ impl Socket { Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } + pub fn set_keepalive(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn keepalive(&self) -> io::Result { + unsupported() + } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { unsafe { setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) } } diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index 04714048e3c5b..936dd4c93233c 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -456,6 +456,15 @@ impl Socket { Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } + pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> { + unsafe { setsockopt(self, libc::SOL_SOCKET, libc::SO_KEEPALIVE, keepalive as c_int) } + } + + pub fn keepalive(&self) -> io::Result { + let raw: c_int = unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_KEEPALIVE)? }; + Ok(raw != 0) + } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { unsafe { setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) } } diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index ca4fa343cb9ab..0ea139cad6a04 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -426,6 +426,15 @@ impl Socket { Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } + pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> { + unsafe { setsockopt(self, c::SOL_SOCKET, c::SO_KEEPALIVE, keepalive as c::BOOL) } + } + + pub fn keepalive(&self) -> io::Result { + let raw: c::BOOL = unsafe { getsockopt(self, c::SOL_SOCKET, c::SO_KEEPALIVE)? }; + Ok(raw != 0) + } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { unsafe { setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) } } diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index 107a3e23733de..b32316a709903 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -112,6 +112,14 @@ impl TcpStream { unsupported() } + pub fn set_keepalive(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn keepalive(&self) -> io::Result { + unsupported() + } + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { unsupported() } diff --git a/library/std/src/sys/net/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs index fb18e8dec557c..c019ec1c9e521 100644 --- a/library/std/src/sys/net/connection/unsupported.rs +++ b/library/std/src/sys/net/connection/unsupported.rs @@ -87,6 +87,14 @@ impl TcpStream { self.0 } + pub fn set_keepalive(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn keepalive(&self) -> io::Result { + self.0 + } + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { self.0 } diff --git a/library/std/src/sys/net/connection/wasip1.rs b/library/std/src/sys/net/connection/wasip1.rs index d6c7e023e865d..93cb777a70842 100644 --- a/library/std/src/sys/net/connection/wasip1.rs +++ b/library/std/src/sys/net/connection/wasip1.rs @@ -145,6 +145,14 @@ impl TcpStream { unsupported() } + pub fn set_keepalive(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn keepalive(&self) -> io::Result { + unsupported() + } + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { unsupported() } diff --git a/library/std/src/sys/net/connection/xous/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs index 4df75453d1f45..521d24e3c496e 100644 --- a/library/std/src/sys/net/connection/xous/tcpstream.rs +++ b/library/std/src/sys/net/connection/xous/tcpstream.rs @@ -353,6 +353,14 @@ impl TcpStream { unimpl!(); } + pub fn set_keepalive(&self, _: bool) -> io::Result<()> { + unimpl!(); + } + + pub fn keepalive(&self) -> io::Result { + unimpl!(); + } + pub fn set_nodelay(&self, enabled: bool) -> io::Result<()> { crate::os::xous::ffi::blocking_scalar( services::net_server(), diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index c21d1de81341f..7b5abbc363786 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2388,6 +2388,7 @@ SleepConditionVariableSRW SleepEx SO_BROADCAST SO_ERROR +SO_KEEPALIVE SO_LINGER SO_RCVTIMEO SO_SNDTIMEO diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index eb54efd1c1fe0..7cef71097a784 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -3189,6 +3189,7 @@ pub const SOCK_STREAM: WINSOCK_SOCKET_TYPE = 1i32; pub const SOL_SOCKET: i32 = 65535i32; pub const SO_BROADCAST: i32 = 32i32; pub const SO_ERROR: i32 = 4103i32; +pub const SO_KEEPALIVE: i32 = 8i32; pub const SO_LINGER: i32 = 128i32; pub const SO_RCVTIMEO: i32 = 4102i32; pub const SO_SNDTIMEO: i32 = 4101i32; diff --git a/src/tools/miri/tests/fail/layout_cycle.rs b/src/tools/miri/tests/fail/layout_cycle.rs index 8d5f1914d0c32..9e93761871d61 100644 --- a/src/tools/miri/tests/fail/layout_cycle.rs +++ b/src/tools/miri/tests/fail/layout_cycle.rs @@ -1,8 +1,7 @@ -//~ ERROR: cycle detected when computing layout of - use std::mem; pub struct S { + //~^ ERROR: cycle detected when computing layout of pub f: ::I, } diff --git a/src/tools/miri/tests/fail/layout_cycle.stderr b/src/tools/miri/tests/fail/layout_cycle.stderr index f8d555e5a10b8..1efbe239016e0 100644 --- a/src/tools/miri/tests/fail/layout_cycle.stderr +++ b/src/tools/miri/tests/fail/layout_cycle.stderr @@ -1,6 +1,14 @@ error[E0391]: cycle detected when computing layout of `S>` + --> tests/fail/layout_cycle.rs:LL:CC | - = note: ...which requires computing layout of ` as Tr>::I`... +LL | pub struct S { + | ^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing layout of ` as Tr>::I`... + --> tests/fail/layout_cycle.rs:LL:CC + | +LL | type I: Tr; + | ^^^^^^^^^^ = note: ...which again requires computing layout of `S>`, completing the cycle note: cycle used when const-evaluating + checking `core::mem::SizedTypeProperties::SIZE` --> RUSTLIB/core/src/mem/mod.rs:LL:CC diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/Cargo.lock b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/Cargo.lock new file mode 100644 index 0000000000000..8d2834ad01aba --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/Cargo.lock @@ -0,0 +1,45 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "cfi-types" +version = "0.0.8" + +[[package]] +name = "cross-lang-cfi-types-crate-abort" +version = "0.1.0" +dependencies = [ + "cfi-types", +] + +[[package]] +name = "cross-lang-cfi-types-crate-not-abort" +version = "0.1.0" +dependencies = [ + "cfi-types", +] + +[[package]] +name = "indirect-arity-mismatch-abort" +version = "0.1.0" + +[[package]] +name = "indirect-pointee-type-mismatch-abort" +version = "0.1.0" + +[[package]] +name = "indirect-return-type-mismatch-abort" +version = "0.1.0" + +[[package]] +name = "indirect-type-mismatch-abort" +version = "0.1.0" + +[[package]] +name = "indirect-type-qualifier-mismatch-abort" +version = "0.1.0" + +[[package]] +name = "invalid-branch-target-abort" +version = "0.1.0" diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/Cargo.toml new file mode 100644 index 0000000000000..2b22762883c04 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/Cargo.toml @@ -0,0 +1,13 @@ +# Workspace mirroring the examples in . +[workspace] +resolver = "2" +members = [ + "invalid-branch-target-abort", + "indirect-arity-mismatch-abort", + "indirect-pointee-type-mismatch-abort", + "indirect-return-type-mismatch-abort", + "indirect-type-qualifier-mismatch-abort", + "indirect-type-mismatch-abort", + "cross-lang-cfi-types-crate-abort", + "cross-lang-cfi-types-crate-not-abort", +] diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/Cargo.toml new file mode 100644 index 0000000000000..2b6082a5b653d --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "cross-lang-cfi-types-crate-abort" +version = "0.1.0" +edition = "2021" + +[dependencies] +cfi-types = { path = "../vendor/cfi-types" } diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/build.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/build.rs new file mode 100644 index 0000000000000..e6a0311d2d1be --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/build.rs @@ -0,0 +1,5 @@ +include!("../shared_build_rs.rs"); + +fn main() { + build_foo_static_lib(&[]); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/src/foo.c b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/src/foo.c new file mode 100644 index 0000000000000..9021075763bb3 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/src/foo.c @@ -0,0 +1,5 @@ +int +do_twice(int (*fn)(int), int arg) +{ + return fn(arg) + fn(arg); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/src/main.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/src/main.rs new file mode 100644 index 0000000000000..dc6490f6d3ff5 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-abort/src/main.rs @@ -0,0 +1,36 @@ +// This example demonstrates redirecting control flow using an indirect +// branch/call to a function with different return and parameter types than the +// return type expected and arguments intended/passed at the call/branch site, +// across the FFI boundary using the `cfi_types` crate for cross-language LLVM +// CFI. + +use std::mem; + +use cfi_types::{c_int, c_long}; + +#[link(name = "foo")] +unsafe extern "C" { + fn do_twice(f: unsafe extern "C" fn(c_int) -> c_int, arg: i32) -> i32; +} + +unsafe extern "C" fn add_one(x: c_int) -> c_int { + c_int(x.0 + 1) +} + +unsafe extern "C" fn add_two(x: c_long) -> c_long { + c_long(x.0 + 2) +} + +fn main() { + let answer = unsafe { do_twice(add_one, 5) }; + + println!("The answer is: {}", answer); + + println!("With CFI enabled, you should not see the next answer"); + let f: unsafe extern "C" fn(c_int) -> c_int = unsafe { + mem::transmute::<*const u8, unsafe extern "C" fn(c_int) -> c_int>(add_two as *const u8) + }; + let next_answer = unsafe { do_twice(f, 5) }; + + println!("The next answer is: {}", next_answer); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/Cargo.toml new file mode 100644 index 0000000000000..81b068d79742e --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "cross-lang-cfi-types-crate-not-abort" +version = "0.1.0" +edition = "2021" + +[dependencies] +cfi-types = { path = "../vendor/cfi-types" } diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/build.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/build.rs new file mode 100644 index 0000000000000..e6a0311d2d1be --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/build.rs @@ -0,0 +1,5 @@ +include!("../shared_build_rs.rs"); + +fn main() { + build_foo_static_lib(&[]); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/src/foo.c b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/src/foo.c new file mode 100644 index 0000000000000..d02bbb285883d --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/src/foo.c @@ -0,0 +1,23 @@ +#include +#include + +// This definition has the type id "_ZTSFvlE". +void +hello_from_c(long arg) +{ + printf("Hello from C!\n"); +} + +// This definition has the type id "_ZTSFvPFvlElE"--this can be ignored for the +// purposes of this example. +void +indirect_call_from_c(void (*fn)(long), long arg) +{ + // This call site tests whether the destination pointer is a member of the + // group derived from the same type id of the fn declaration, which has the + // type id "_ZTSFvlE". + // + // Notice that since the test is at the call site and generated by Clang, + // the type id used in the test is encoded by Clang. + fn(arg); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/src/main.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/src/main.rs new file mode 100644 index 0000000000000..a9d1326d6dc43 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-cfi-types-crate-not-abort/src/main.rs @@ -0,0 +1,67 @@ +use cfi_types::c_long; + +#[link(name = "foo")] +extern "C" { + // This declaration has the type id "_ZTSFvlE" because it uses the CFI types + // for cross-language LLVM CFI support. The cfi_types crate provides a new + // set of C types as user-defined types using the cfi_encoding attribute and + // repr(transparent) to be used for cross-language LLVM CFI support. This + // new set of C types allows the Rust compiler to identify and correctly + // encode C types in extern "C" function types indirectly called across the + // FFI boundary when CFI is enabled. + fn hello_from_c(_: c_long); + + // This declaration has the type id "_ZTSFvPFvlElE" because it uses the CFI + // types for cross-language LLVM CFI support--this can be ignored for the + // purposes of this example. + fn indirect_call_from_c(f: unsafe extern "C" fn(c_long), arg: c_long); +} + +// This definition has the type id "_ZTSFvlE" because it uses the CFI types for +// cross-language LLVM CFI support, similarly to the hello_from_c declaration +// above. +unsafe extern "C" fn hello_from_rust(_: c_long) { + println!("Hello, world!"); +} + +// This definition has the type id "_ZTSFvlE" because it uses the CFI types for +// cross-language LLVM CFI support, similarly to the hello_from_c declaration +// above. +unsafe extern "C" fn hello_from_rust_again(_: c_long) { + println!("Hello from Rust again!"); +} + +// This definition would also have the type id "_ZTSFvPFvlElE" because it uses +// the CFI types for cross-language LLVM CFI support, similarly to the +// hello_from_c declaration above--this can be ignored for the purposes of this +// example. +fn indirect_call(f: unsafe extern "C" fn(c_long), arg: c_long) { + // This indirect call site tests whether the destination pointer is a member + // of the group derived from the same type id of the f declaration, which + // has the type id "_ZTSFvlE" because it uses the CFI types for + // cross-language LLVM CFI support, similarly to the hello_from_c + // declaration above. + unsafe { f(arg) } +} + +// This definition has the type id "_ZTSFvvE"--this can be ignored for the +// purposes of this example. +fn main() { + // This demonstrates an indirect call within Rust-only code using the same + // encoding for hello_from_rust and the test at the indirect call site at + // indirect_call (i.e., "_ZTSFvlE"). + indirect_call(hello_from_rust, c_long(5)); + + // This demonstrates an indirect call across the FFI boundary with the Rust + // compiler and Clang using the same encoding for hello_from_c and the test + // at the indirect call site at indirect_call (i.e., "_ZTSFvlE"). + indirect_call(hello_from_c, c_long(5)); + + // This demonstrates an indirect call to a function passed as a callback + // across the FFI boundary with the Rust compiler and Clang the same + // encoding for the passed-callback declaration and the test at the indirect + // call site at indirect_call_from_c (i.e., "_ZTSFvlE"). + unsafe { + indirect_call_from_c(hello_from_rust_again, c_long(5)); + } +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/Cargo.lock b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/Cargo.lock new file mode 100644 index 0000000000000..5c2cbfd47ac55 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "cross-lang-integer-normalization-abort" +version = "0.1.0" diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/Cargo.toml new file mode 100644 index 0000000000000..b9044fba728ad --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "cross-lang-integer-normalization-abort" +version = "0.1.0" +edition = "2021" + +# Not a member of the parent `sanitizer-cfi-build-std-clang` workspace so it can +# be built with different `RUSTFLAGS` (i.e., integer normalization). +[workspace] +members = ["."] +resolver = "2" diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/build.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/build.rs new file mode 100644 index 0000000000000..de04b350552af --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/build.rs @@ -0,0 +1,5 @@ +include!("../shared_build_rs.rs"); + +fn main() { + build_foo_static_lib(&["-fsanitize-cfi-icall-experimental-normalize-integers"]); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/src/foo.c b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/src/foo.c new file mode 100644 index 0000000000000..9021075763bb3 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/src/foo.c @@ -0,0 +1,5 @@ +int +do_twice(int (*fn)(int), int arg) +{ + return fn(arg) + fn(arg); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/src/main.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/src/main.rs new file mode 100644 index 0000000000000..ef5d1da6ca737 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-abort/src/main.rs @@ -0,0 +1,34 @@ +// This example demonstrates redirecting control flow using an indirect +// branch/call to a function with different return and parameter types than the +// return type expected and arguments intended/passed at the call/branch site, +// across the FFI boundary using integer normalization for cross-language LLVM +// CFI. + +use std::mem; + +#[link(name = "foo")] +extern "C" { + fn do_twice(f: unsafe extern "C" fn(i32) -> i32, arg: i32) -> i32; +} + +unsafe extern "C" fn add_one(x: i32) -> i32 { + x + 1 +} + +unsafe extern "C" fn add_two(x: i64) -> i64 { + x + 2 +} + +fn main() { + let answer = unsafe { do_twice(add_one, 5) }; + + println!("The answer is: {}", answer); + + println!("With CFI enabled, you should not see the next answer"); + let f: unsafe extern "C" fn(i32) -> i32 = unsafe { + mem::transmute::<*const u8, unsafe extern "C" fn(i32) -> i32>(add_two as *const u8) + }; + let next_answer = unsafe { do_twice(f, 5) }; + + println!("The next answer is: {}", next_answer); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/Cargo.lock b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/Cargo.lock new file mode 100644 index 0000000000000..957356f828d94 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "cross-lang-integer-normalization-not-abort" +version = "0.1.0" diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/Cargo.toml new file mode 100644 index 0000000000000..a89a3ae9b3501 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "cross-lang-integer-normalization-not-abort" +version = "0.1.0" +edition = "2021" + +# Not a member of the parent `sanitizer-cfi-build-std-clang` workspace so it can +# be built with different `RUSTFLAGS` (i.e., integer normalization). +[workspace] +members = ["."] +resolver = "2" diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/build.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/build.rs new file mode 100644 index 0000000000000..de04b350552af --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/build.rs @@ -0,0 +1,5 @@ +include!("../shared_build_rs.rs"); + +fn main() { + build_foo_static_lib(&["-fsanitize-cfi-icall-experimental-normalize-integers"]); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/src/foo.c b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/src/foo.c new file mode 100644 index 0000000000000..d02bbb285883d --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/src/foo.c @@ -0,0 +1,23 @@ +#include +#include + +// This definition has the type id "_ZTSFvlE". +void +hello_from_c(long arg) +{ + printf("Hello from C!\n"); +} + +// This definition has the type id "_ZTSFvPFvlElE"--this can be ignored for the +// purposes of this example. +void +indirect_call_from_c(void (*fn)(long), long arg) +{ + // This call site tests whether the destination pointer is a member of the + // group derived from the same type id of the fn declaration, which has the + // type id "_ZTSFvlE". + // + // Notice that since the test is at the call site and generated by Clang, + // the type id used in the test is encoded by Clang. + fn(arg); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/src/main.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/src/main.rs new file mode 100644 index 0000000000000..70a4d9a789e58 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/cross-lang-integer-normalization-not-abort/src/main.rs @@ -0,0 +1,89 @@ +use std::ffi::c_long; + +#[link(name = "foo")] +extern "C" { + // This declaration would have the type id "_ZTSFvlE", but at the time types + // are encoded, all type aliases are already resolved to their respective + // Rust aliased types, so this is encoded either as "_ZTSFvu3i32E" or + // "_ZTSFvu3i64E" depending to what type c_long type alias is resolved to, + // which currently uses the u vendor extended type + // encoding for the Rust integer types--this is the problem demonstrated in + // this example. + fn hello_from_c(_: c_long); + + // This declaration would have the type id "_ZTSFvPFvlElE", but is encoded + // either as "_ZTSFvPFvu3i32ES_E" (compressed) or "_ZTSFvPFvu3i64ES_E" + // (compressed), similarly to the hello_from_c declaration above--this can + // be ignored for the purposes of this example. + fn indirect_call_from_c(f: unsafe extern "C" fn(c_long), arg: c_long); +} + +// This definition would have the type id "_ZTSFvlE", but is encoded either as +// "_ZTSFvu3i32E" or "_ZTSFvu3i64E", similarly to the hello_from_c declaration +// above. +unsafe extern "C" fn hello_from_rust(_: c_long) { + println!("Hello, world!"); +} + +// This definition would have the type id "_ZTSFvlE", but is encoded either as +// "_ZTSFvu3i32E" or "_ZTSFvu3i64E", similarly to the hello_from_c declaration +// above. +unsafe extern "C" fn hello_from_rust_again(_: c_long) { + println!("Hello from Rust again!"); +} + +// This definition would also have the type id "_ZTSFvPFvlElE", but is encoded +// either as "_ZTSFvPFvu3i32ES_E" (compressed) or "_ZTSFvPFvu3i64ES_E" +// (compressed), similarly to the hello_from_c declaration above--this can be +// ignored for the purposes of this example. +fn indirect_call(f: unsafe extern "C" fn(c_long), arg: c_long) { + // This indirect call site tests whether the destination pointer is a member + // of the group derived from the same type id of the f declaration, which + // would have the type id "_ZTSFvlE", but is encoded either as + // "_ZTSFvu3i32E" or "_ZTSFvu3i64E", similarly to the hello_from_c + // declaration above. + // + // Notice that since the test is at the call site and generated by the Rust + // compiler, the type id used in the test is encoded by the Rust compiler. + unsafe { f(arg) } +} + +// This definition has the type id "_ZTSFvvE"--this can be ignored for the +// purposes of this example. +fn main() { + // This demonstrates an indirect call within Rust-only code using the same + // encoding for hello_from_rust and the test at the indirect call site at + // indirect_call (i.e., "_ZTSFvu3i32E" or "_ZTSFvu3i64E"). + indirect_call(hello_from_rust, 5); + + // This demonstrates an indirect call across the FFI boundary with the Rust + // compiler and Clang using different encodings for hello_from_c and the + // test at the indirect call site at indirect_call (i.e., "_ZTSFvu3i32E" or + // "_ZTSFvu3i64E" vs "_ZTSFvlE"). + // + // When using rustc LTO (i.e., -Clto), this works because the type id used + // is from the Rust-declared hello_from_c, which is encoded by the Rust + // compiler (i.e., "_ZTSFvu3i32E" or "_ZTSFvu3i64E"). + // + // When using (proper) LTO (i.e., -Clinker-plugin-lto), this does not work + // because the type id used is from the C-defined hello_from_c, which is + // encoded by Clang (i.e., "_ZTSFvlE"). + indirect_call(hello_from_c, 5); + + // This demonstrates an indirect call to a function passed as a callback + // across the FFI boundary with the Rust compiler and Clang using different + // encodings for the passed-callback declaration and the test at the + // indirect call site at indirect_call_from_c (i.e., "_ZTSFvu3i32E" or + // "_ZTSFvu3i64E" vs "_ZTSFvlE"). + // + // When Rust functions are passed as callbacks across the FFI boundary to be + // called back from C code, the tests are also at the call site but + // generated by Clang instead, so the type ids used in the tests are encoded + // by Clang, which will not match the type ids of declarations encoded by + // the Rust compiler (e.g., hello_from_rust_again). (The same happens the + // other way around for C functions passed as callbacks across the FFI + // boundary to be called back from Rust code.) + unsafe { + indirect_call_from_c(hello_from_rust_again, 5); + } +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-arity-mismatch-abort/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-arity-mismatch-abort/Cargo.toml new file mode 100644 index 0000000000000..8c7f2b33265f7 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-arity-mismatch-abort/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "indirect-arity-mismatch-abort" +version = "0.1.0" +edition = "2021" diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-arity-mismatch-abort/src/main.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-arity-mismatch-abort/src/main.rs new file mode 100644 index 0000000000000..8cc0dba58b201 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-arity-mismatch-abort/src/main.rs @@ -0,0 +1,30 @@ +// This example demonstrates redirecting control flow using an indirect +// branch/call to a function with a different number of parameters than +// arguments intended/passed at the call/branch site. + +use std::mem; + +fn add_one(x: i32) -> i32 { + x + 1 +} + +fn add_two(x: i32, _y: i32) -> i32 { + x + 2 +} + +fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { + f(arg) + f(arg) +} + +fn main() { + let answer = do_twice(add_one, 5); + + println!("The answer is: {}", answer); + + println!("With CFI enabled, you should not see the next answer"); + let f: fn(i32) -> i32 = + unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) }; + let next_answer = do_twice(f, 5); + + println!("The next answer is: {}", next_answer); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-pointee-type-mismatch-abort/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-pointee-type-mismatch-abort/Cargo.toml new file mode 100644 index 0000000000000..0526f844363b9 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-pointee-type-mismatch-abort/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "indirect-pointee-type-mismatch-abort" +version = "0.1.0" +edition = "2021" diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-pointee-type-mismatch-abort/src/main.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-pointee-type-mismatch-abort/src/main.rs new file mode 100644 index 0000000000000..ad0d7ddf0192f --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-pointee-type-mismatch-abort/src/main.rs @@ -0,0 +1,32 @@ +// This example demonstrates redirecting control flow using an indirect +// branch/call to a function with different return and parameter (i.e., pointee) +// types than the return type expected and arguments intended/passed at the +// call/branch site. + +use std::mem; + +fn add_one(x: *const i32) -> i32 { + unsafe { *x + 1 } +} + +fn add_two(x: *const i64) -> i32 { + unsafe { (*x + 2) as i32 } +} + +fn do_twice(f: fn(*const i32) -> i32, arg: *const i32) -> i32 { + f(arg) + f(arg) +} + +fn main() { + let value: i32 = 5; + let answer = do_twice(add_one, &value); + + println!("The answer is: {}", answer); + + println!("With CFI enabled, you should not see the next answer"); + let f: fn(*const i32) -> i32 = + unsafe { mem::transmute::<*const u8, fn(*const i32) -> i32>(add_two as *const u8) }; + let next_answer = do_twice(f, &value); + + println!("The next answer is: {}", next_answer); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-return-type-mismatch-abort/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-return-type-mismatch-abort/Cargo.toml new file mode 100644 index 0000000000000..392975f872277 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-return-type-mismatch-abort/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "indirect-return-type-mismatch-abort" +version = "0.1.0" +edition = "2021" diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-return-type-mismatch-abort/src/main.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-return-type-mismatch-abort/src/main.rs new file mode 100644 index 0000000000000..e21e71ee71a0f --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-return-type-mismatch-abort/src/main.rs @@ -0,0 +1,30 @@ +// This example demonstrates redirecting control flow using an indirect +// branch/call to a function with a different return type than the return type +// expected at the call/branch site. + +use std::mem; + +fn add_one(x: i32) -> i32 { + x + 1 +} + +fn add_two(x: i32) -> i64 { + i64::from(x + 2) +} + +fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { + f(arg) + f(arg) +} + +fn main() { + let answer = do_twice(add_one, 5); + + println!("The answer is: {}", answer); + + println!("With CFI enabled, you should not see the next answer"); + let f: fn(i32) -> i32 = + unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) }; + let next_answer = do_twice(f, 5); + + println!("The next answer is: {}", next_answer); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-mismatch-abort/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-mismatch-abort/Cargo.toml new file mode 100644 index 0000000000000..e167b2acfbcf5 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-mismatch-abort/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "indirect-type-mismatch-abort" +version = "0.1.0" +edition = "2021" diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-mismatch-abort/src/main.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-mismatch-abort/src/main.rs new file mode 100644 index 0000000000000..0f40aa316152e --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-mismatch-abort/src/main.rs @@ -0,0 +1,30 @@ +// This example demonstrates redirecting control flow using an indirect +// branch/call to a function with different return and parameter types than the +// return type expected and arguments intended/passed at the call/branch site. + +use std::mem; + +fn add_one(x: i32) -> i32 { + x + 1 +} + +fn add_two(x: i64) -> i64 { + x + 2 +} + +fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { + f(arg) + f(arg) +} + +fn main() { + let answer = do_twice(add_one, 5); + + println!("The answer is: {}", answer); + + println!("With CFI enabled, you should not see the next answer"); + let f: fn(i32) -> i32 = + unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) }; + let next_answer = do_twice(f, 5); + + println!("The next answer is: {}", next_answer); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-qualifier-mismatch-abort/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-qualifier-mismatch-abort/Cargo.toml new file mode 100644 index 0000000000000..1f4b3d4b0c9b6 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-qualifier-mismatch-abort/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "indirect-type-qualifier-mismatch-abort" +version = "0.1.0" +edition = "2021" diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-qualifier-mismatch-abort/src/main.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-qualifier-mismatch-abort/src/main.rs new file mode 100644 index 0000000000000..e37d883addf1d --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/indirect-type-qualifier-mismatch-abort/src/main.rs @@ -0,0 +1,31 @@ +// This example demonstrates redirecting control flow using an indirect +// branch/call to a function with parameter type qualifiers than the argument +// type qualifiers intended/passed at the call/branch site. + +use std::mem; + +fn add_one(x: &i32) -> i32 { + *x + 1 +} + +fn add_two(x: &mut i32) -> i32 { + *x + 2 +} + +fn do_twice(f: fn(&i32) -> i32, arg: &i32) -> i32 { + f(arg) + f(arg) +} + +fn main() { + let value: i32 = 5; + let answer = do_twice(add_one, &value); + + println!("The answer is: {}", answer); + + println!("With CFI enabled, you should not see the next answer"); + let f: fn(&i32) -> i32 = + unsafe { mem::transmute::<*const u8, fn(&i32) -> i32>(add_two as *const u8) }; + let next_answer = do_twice(f, &value); + + println!("The next answer is: {}", next_answer); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/invalid-branch-target-abort/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/invalid-branch-target-abort/Cargo.toml new file mode 100644 index 0000000000000..e6af74f961e04 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/invalid-branch-target-abort/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "invalid-branch-target-abort" +version = "0.1.0" +edition = "2021" diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/invalid-branch-target-abort/src/main.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/invalid-branch-target-abort/src/main.rs new file mode 100644 index 0000000000000..0b047bf5fefb6 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/invalid-branch-target-abort/src/main.rs @@ -0,0 +1,50 @@ +// This example demonstrates redirecting control flow using an indirect +// branch/call to an invalid destination (i.e., within the body of the +// function). + +use std::mem; + +fn add_one(x: i32) -> i32 { + x + 1 +} + +#[unsafe(naked)] +pub extern "C" fn add_two(_x: i32) -> ! { + // x + 2 preceded by a landing pad/nop block + core::arch::naked_asm!( + r#" + nop + nop + nop + nop + nop + nop + nop + nop + nop + lea eax, [rdi + 2] + ret + "#, + ); +} + +fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { + f(arg) + f(arg) +} + +fn main() { + let answer = do_twice(add_one, 5); + + println!("The answer is: {}", answer); + + println!("With CFI enabled, you should not see the next answer"); + let f: fn(i32) -> i32 = unsafe { + // Offset 0 is a valid branch/call destination (i.e., the function entry + // point), but offsets 1-8 within the landing pad/nop block are invalid + // branch/call destinations (i.e., within the body of the function). + mem::transmute::<*const u8, fn(i32) -> i32>((add_two as *const u8).offset(5)) + }; + let next_answer = do_twice(f, 5); + + println!("The next answer is: {}", next_answer); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/rmake.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/rmake.rs new file mode 100644 index 0000000000000..c85d01a71105a --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/rmake.rs @@ -0,0 +1,151 @@ +//! Verifies that the examples in build and run with +//!`-Zbuild-std` to prevent regressions such as [rust-lang/rust#142284]. + +//@ needs-sanitizer-cfi +//@ needs-force-clang-based-tests +//@ needs-rust-lld +//@ needs-target-std +//@ ignore-cross-compile +//@ only-x86_64-unknown-linux-gnu + +#![deny(warnings)] + +use std::path::Path; + +use run_make_support::external_deps::rustc::sysroot as rustc_sysroot; +use run_make_support::run::cmd; +use run_make_support::{bin_name, cargo, path, target}; + +fn clang_path() -> String { + if let Ok(d) = std::env::var("LLVM_BIN_DIR") { + let clang = Path::new(d.trim_end_matches('/')).join("clang"); + if clang.exists() { + return clang.display().to_string(); + } + } + if let Ok(clang) = std::env::var("CLANG") { + let clang = Path::new(clang.trim_end_matches('/')); + if clang.exists() { + return clang.display().to_string(); + } + } + "clang".to_string() +} + +fn fuse_ld_path() -> String { + if let Ok(d) = std::env::var("LLVM_BIN_DIR") { + let llvm_bin_dir = Path::new(d.trim_end_matches('/')); + let gcc_ld_lld = llvm_bin_dir.join("gcc-ld").join("ld.lld"); + if gcc_ld_lld.exists() { + return gcc_ld_lld.display().to_string(); + } + let ld_lld = llvm_bin_dir.join("ld.lld"); + if ld_lld.exists() { + return ld_lld.display().to_string(); + } + } + if let Ok(clang) = std::env::var("CLANG") { + let clang = Path::new(clang.trim_end_matches('/')); + if let Some(clang_dir) = clang.parent() { + let gcc_ld_lld = clang_dir.join("gcc-ld").join("ld.lld"); + if gcc_ld_lld.exists() { + return gcc_ld_lld.display().to_string(); + } + let ld_lld = clang_dir.join("ld.lld"); + if ld_lld.exists() { + return ld_lld.display().to_string(); + } + } + } + let target_bin_dir = rustc_sysroot().join("lib").join("rustlib").join(target()).join("bin"); + let gcc_ld_lld = target_bin_dir.join("gcc-ld").join("ld.lld"); + if gcc_ld_lld.exists() { + return gcc_ld_lld.display().to_string(); + } + "ld.lld".to_string() +} + +fn run_and_expect_cfi_abort(target_dir: &Path, target: &str, binary: &str) { + let exe = target_dir.join(target).join("release").join(bin_name(binary)); + let output = cmd(&exe).run_fail(); + output + .assert_stdout_contains("With CFI enabled, you should not see the next answer") + .assert_stdout_not_contains("The next answer is:"); +} + +fn run_and_expect_cfi_not_abort(target_dir: &Path, target: &str, binary: &str) { + let exe = target_dir.join(target).join("release").join(bin_name(binary)); + let output = cmd(&exe).run(); + output.assert_stdout_contains("Hello from C!"); +} + +fn main() { + let clang = clang_path(); + let fuse_ld = fuse_ld_path(); + let tgt = target(); + let target_dir = path("target"); + let lib = std::env::var("LIB").unwrap_or_default(); + + let prior_rustflags = std::env::var("RUSTFLAGS").unwrap_or_default(); + + let rustflags = format!( + "{prior_rustflags} -Clinker-plugin-lto -Clinker={clang} \ + -Clink-arg=-fuse-ld={fuse_ld} -Zsanitizer=cfi \ + -Ctarget-feature=-crt-static" + ) + .trim() + .to_owned(); + + let rustflags_with_integer_normalization = + format!("{rustflags} -Zsanitizer-cfi-normalize-integers").trim().to_owned(); + + let run = |manifest: &Path, rustflags: &str, workspace: bool| { + let mut c = cargo(); + c.arg("build") + .arg("--manifest-path") + .arg(manifest) + .arg("--release") + .arg("-Zbuild-std") + .arg("--target") + .arg(&tgt); + if workspace { + c.arg("--workspace"); + } + c.env("RUSTFLAGS", rustflags) + .env("CC", &clang) + .env("CARGO_TARGET_DIR", &target_dir) + .env("RUSTC_BOOTSTRAP", "1") + .env("LIB", &lib) + .run(); + }; + + run(Path::new("Cargo.toml"), &rustflags, true); + for bin in [ + "invalid-branch-target-abort", + "indirect-arity-mismatch-abort", + "indirect-pointee-type-mismatch-abort", + "indirect-return-type-mismatch-abort", + "indirect-type-qualifier-mismatch-abort", + "indirect-type-mismatch-abort", + "cross-lang-cfi-types-crate-abort", + ] { + run_and_expect_cfi_abort(&target_dir, &tgt, bin); + } + for bin in ["cross-lang-cfi-types-crate-not-abort"] { + run_and_expect_cfi_not_abort(&target_dir, &tgt, bin); + } + + run( + Path::new("cross-lang-integer-normalization-abort/Cargo.toml"), + &rustflags_with_integer_normalization, + false, + ); + run_and_expect_cfi_abort(&target_dir, &tgt, "cross-lang-integer-normalization-abort"); + + run( + Path::new("cross-lang-integer-normalization-not-abort/Cargo.toml"), + &rustflags_with_integer_normalization, + false, + ); + run_and_expect_cfi_not_abort(&target_dir, &tgt, "cross-lang-integer-normalization-not-abort"); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/shared_build_rs.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/shared_build_rs.rs new file mode 100644 index 0000000000000..2c2e0fd4ffb81 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/shared_build_rs.rs @@ -0,0 +1,73 @@ +use std::env; +use std::path::{Path, PathBuf}; +use std::process::Command; + +fn clang_path() -> PathBuf { + if let Ok(d) = env::var("LLVM_BIN_DIR") { + let clang = Path::new(d.trim_end_matches('/')).join("clang"); + if clang.exists() { + return clang; + } + } + if let Ok(clang) = env::var("CLANG") { + let clang = Path::new(clang.trim_end_matches('/')); + if clang.exists() { + return clang.to_path_buf(); + } + } + PathBuf::from("clang") +} + +fn llvm_ar_path() -> PathBuf { + if let Ok(d) = env::var("LLVM_BIN_DIR") { + let llvm_ar = Path::new(d.trim_end_matches('/')).join("llvm-ar"); + if llvm_ar.exists() { + return llvm_ar; + } + } + if let Ok(clang) = env::var("CLANG") { + let clang = Path::new(&clang); + if let Some(clang_dir) = clang.parent() { + let llvm_ar = clang_dir.join("llvm-ar"); + if llvm_ar.exists() { + return llvm_ar; + } + } + } + PathBuf::from("llvm-ar") +} + +fn build_foo_static_lib(extra_flags: &[&str]) { + let out_dir = env::var("OUT_DIR").expect("OUT_DIR"); + let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"); + let c_src = Path::new(&manifest_dir).join("src/foo.c"); + let bc_path = Path::new(&out_dir).join("foo.bc"); + let a_path = Path::new(&out_dir).join("libfoo.a"); + + let clang = clang_path(); + let llvm_ar = llvm_ar_path(); + + let mut clang_args = vec!["-Wall", "-flto=thin", "-fsanitize=cfi"]; + clang_args.extend_from_slice(extra_flags); + clang_args.extend_from_slice(&["-fvisibility=hidden", "-c", "-emit-llvm", "-o"]); + + let st = Command::new(&clang) + .args(&clang_args) + .arg(&bc_path) + .arg(&c_src) + .status() + .unwrap_or_else(|e| panic!("failed to spawn `{}`: {e}", clang.display())); + assert!(st.success(), "`{}` failed with {st}", clang.display()); + + let st = Command::new(&llvm_ar) + .args(["rcs", a_path.to_str().unwrap(), bc_path.to_str().unwrap()]) + .status() + .unwrap_or_else(|e| panic!("failed to spawn `{}`: {e}", llvm_ar.display())); + assert!(st.success(), "`{}` failed with {st}", llvm_ar.display()); + + println!("cargo:rustc-link-search=native={out_dir}"); + println!("cargo:rustc-link-lib=static=foo"); + println!("cargo:rerun-if-changed={}", c_src.display()); + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=../shared_build_rs.rs"); +} diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/vendor/cfi-types/Cargo.toml b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/vendor/cfi-types/Cargo.toml new file mode 100644 index 0000000000000..180bfea79fa03 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/vendor/cfi-types/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "cfi-types" +version = "0.0.8" +edition = "2021" + +description = "CFI types for cross-language LLVM CFI support" +homepage = "https://github.com/rcvalle/rust-crate-cfi-types" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rcvalle/rust-crate-cfi-types" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/tests/run-make-cargo/sanitizer-cfi-build-std-clang/vendor/cfi-types/src/lib.rs b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/vendor/cfi-types/src/lib.rs new file mode 100644 index 0000000000000..436097c32fd82 --- /dev/null +++ b/tests/run-make-cargo/sanitizer-cfi-build-std-clang/vendor/cfi-types/src/lib.rs @@ -0,0 +1,96 @@ +//! CFI types for cross-language LLVM CFI support. +//! +//! The cfi_types crate provides a new set of C types as user-defined types +//! using the cfi_encoding attribute and repr(transparent) to be used for +//! cross-language LLVM CFI support. This new set of C types allows the Rust +//! compiler to identify and correctly encode C types in extern "C" function +//! types indirectly called across the FFI boundary when CFI is enabled. +//! +//! The use of these types are optional and are recommended for when enforcement +//! and explicitness of types used across the FFI boundary and no loss of +//! granularity for cross-language LLVM CFI are preferred. +//! +//! Alternatively, the `-Zsanitizer-cfi-normalize-integers` option may be used +//! with the Clang `-fsanitize-cfi-icall-experimental-normalize-integers` option +//! for cross-language LLVM CFI support. + +#![feature(cfg_sanitizer_cfi)] +#![feature(cfi_encoding)] +#![allow(non_camel_case_types)] + +/// CFI type equivalent to Rust's core::ffi::c_char type alias. +#[allow(dead_code)] +#[cfg_attr(not(sanitizer_cfi_normalize_integers), cfi_encoding = "c")] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[repr(transparent)] +pub struct c_char(pub core::ffi::c_char); + +/// CFI type equivalent to Rust's core::ffi::c_int type alias. +#[allow(dead_code)] +#[cfg_attr(not(sanitizer_cfi_normalize_integers), cfi_encoding = "i")] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[repr(transparent)] +pub struct c_int(pub core::ffi::c_int); + +/// CFI type equivalent to Rust's core::ffi::c_long type alias. +#[allow(dead_code)] +#[cfg_attr(not(sanitizer_cfi_normalize_integers), cfi_encoding = "l")] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[repr(transparent)] +pub struct c_long(pub core::ffi::c_long); + +/// CFI type equivalent to Rust's core::ffi::c_longlong type alias. +#[allow(dead_code)] +#[cfg_attr(not(sanitizer_cfi_normalize_integers), cfi_encoding = "x")] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[repr(transparent)] +pub struct c_longlong(pub core::ffi::c_longlong); + +/// CFI type equivalent to Rust's core::ffi::c_schar type alias. +#[allow(dead_code)] +#[cfg_attr(not(sanitizer_cfi_normalize_integers), cfi_encoding = "a")] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[repr(transparent)] +pub struct c_schar(pub core::ffi::c_schar); + +/// CFI type equivalent to Rust's core::ffi::c_short type alias. +#[allow(dead_code)] +#[cfg_attr(not(sanitizer_cfi_normalize_integers), cfi_encoding = "s")] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[repr(transparent)] +pub struct c_short(pub core::ffi::c_short); + +/// CFI type equivalent to Rust's core::ffi::c_uchar type alias. +#[allow(dead_code)] +#[cfg_attr(not(sanitizer_cfi_normalize_integers), cfi_encoding = "h")] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[repr(transparent)] +pub struct c_uchar(pub core::ffi::c_uchar); + +/// CFI type equivalent to Rust's core::ffi::c_uint type alias. +#[allow(dead_code)] +#[cfg_attr(not(sanitizer_cfi_normalize_integers), cfi_encoding = "j")] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[repr(transparent)] +pub struct c_uint(pub core::ffi::c_uint); + +/// CFI type equivalent to Rust's core::ffi::c_ulong type alias. +#[allow(dead_code)] +#[cfg_attr(not(sanitizer_cfi_normalize_integers), cfi_encoding = "m")] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[repr(transparent)] +pub struct c_ulong(pub core::ffi::c_ulong); + +/// CFI type equivalent to Rust's core::ffi::c_ulonglong type alias. +#[allow(dead_code)] +#[cfg_attr(not(sanitizer_cfi_normalize_integers), cfi_encoding = "y")] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[repr(transparent)] +pub struct c_ulonglong(pub core::ffi::c_ulonglong); + +/// CFI type equivalent to Rust's core::ffi::c_ushort type alias. +#[allow(dead_code)] +#[cfg_attr(not(sanitizer_cfi_normalize_integers), cfi_encoding = "t")] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[repr(transparent)] +pub struct c_ushort(pub core::ffi::c_ushort); diff --git a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs index 5dd11b0a016e3..8a7cacf20e2e4 100644 --- a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs +++ b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs @@ -37,7 +37,7 @@ impl CodegenBackend for TheBackend { "fake_target_cpu".to_owned() } - fn codegen_crate(&self, _tcx: TyCtxt<'_>, _crate_info: &CrateInfo) -> Box { + fn codegen_crate(&self, _tcx: TyCtxt<'_>) -> Box { Box::new(CompiledModules { modules: vec![], allocator_module: None }) } @@ -46,6 +46,7 @@ impl CodegenBackend for TheBackend { ongoing_codegen: Box, _sess: &Session, _outputs: &OutputFilenames, + _crate_info: &CrateInfo, ) -> (CompiledModules, FxIndexMap) { let codegen_results = ongoing_codegen .downcast::() diff --git a/tests/ui/associated-inherent-types/normalization-overflow.stderr b/tests/ui/associated-inherent-types/normalization-overflow.current.stderr similarity index 78% rename from tests/ui/associated-inherent-types/normalization-overflow.stderr rename to tests/ui/associated-inherent-types/normalization-overflow.current.stderr index 05aad31c5f419..e3e662788cf09 100644 --- a/tests/ui/associated-inherent-types/normalization-overflow.stderr +++ b/tests/ui/associated-inherent-types/normalization-overflow.current.stderr @@ -1,5 +1,5 @@ error: overflow evaluating associated type `T::This` - --> $DIR/normalization-overflow.rs:9:5 + --> $DIR/normalization-overflow.rs:14:5 | LL | type This = Self::This; | ^^^^^^^^^ diff --git a/tests/ui/associated-inherent-types/normalization-overflow.next.stderr b/tests/ui/associated-inherent-types/normalization-overflow.next.stderr new file mode 100644 index 0000000000000..5f0939b9f7763 --- /dev/null +++ b/tests/ui/associated-inherent-types/normalization-overflow.next.stderr @@ -0,0 +1,9 @@ +error[E0271]: type mismatch resolving `T::This normalizes-to _` + --> $DIR/normalization-overflow.rs:14:5 + | +LL | type This = Self::This; + | ^^^^^^^^^ types differ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/associated-inherent-types/normalization-overflow.rs b/tests/ui/associated-inherent-types/normalization-overflow.rs index 4228238aa7b7a..c5505578f4f00 100644 --- a/tests/ui/associated-inherent-types/normalization-overflow.rs +++ b/tests/ui/associated-inherent-types/normalization-overflow.rs @@ -1,12 +1,19 @@ -#![feature(inherent_associated_types)] +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ [next] compile-flags: -Znext-solver + +#![feature(inherent_associated_types, rustc_attrs)] #![allow(incomplete_features)] +#![rustc_no_implicit_bounds] // FIXME(fmease): I'd prefer to report a cycle error here instead of an overflow one. struct T; impl T { - type This = Self::This; //~ ERROR overflow evaluating associated type `T::This` + type This = Self::This; + //[current]~^ ERROR: overflow evaluating associated type `T::This` + //[next]~^^ ERROR: type mismatch resolving `T::This normalizes-to _` } fn main() {} diff --git a/tests/ui/consts/const-size_of-cycle.stderr b/tests/ui/consts/const-size_of-cycle.stderr index 01aa5e726b451..6a7f44ed35893 100644 --- a/tests/ui/consts/const-size_of-cycle.stderr +++ b/tests/ui/consts/const-size_of-cycle.stderr @@ -10,7 +10,11 @@ note: ...which requires simplifying constant for the type system `core::mem::Siz --> $SRC_DIR/core/src/mem/mod.rs:LL:COL note: ...which requires const-evaluating + checking `core::mem::SizedTypeProperties::SIZE`... --> $SRC_DIR/core/src/mem/mod.rs:LL:COL - = note: ...which requires computing layout of `Foo`... +note: ...which requires computing layout of `Foo`... + --> $DIR/const-size_of-cycle.rs:1:1 + | +LL | struct Foo { + | ^^^^^^^^^^ = note: ...which requires computing layout of `[u8; std::mem::size_of::()]`... note: ...which requires normalizing `[u8; std::mem::size_of::()]`... --> $DIR/const-size_of-cycle.rs:2:17 diff --git a/tests/ui/consts/issue-44415.stderr b/tests/ui/consts/issue-44415.stderr index 0e3f2e6199f76..28f6813717337 100644 --- a/tests/ui/consts/issue-44415.stderr +++ b/tests/ui/consts/issue-44415.stderr @@ -9,7 +9,11 @@ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`.. | LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `Foo`... +note: ...which requires computing layout of `Foo`... + --> $DIR/issue-44415.rs:5:1 + | +LL | struct Foo { + | ^^^^^^^^^^ = note: ...which requires computing layout of `[u8; unsafe { intrinsics::size_of::() }]`... note: ...which requires normalizing `[u8; unsafe { intrinsics::size_of::() }]`... --> $DIR/issue-44415.rs:6:17 diff --git a/tests/ui/infinite/infinite-type-alias-mutual-recursion.feature_new.stderr b/tests/ui/infinite/infinite-type-alias-mutual-recursion.feature_new.stderr new file mode 100644 index 0000000000000..1d6ace580951b --- /dev/null +++ b/tests/ui/infinite/infinite-type-alias-mutual-recursion.feature_new.stderr @@ -0,0 +1,21 @@ +error[E0271]: type mismatch resolving `X3 normalizes-to _` + --> $DIR/infinite-type-alias-mutual-recursion.rs:12:1 + | +LL | type X1 = X2; + | ^^^^^^^ types differ + +error[E0271]: type mismatch resolving `X1 normalizes-to _` + --> $DIR/infinite-type-alias-mutual-recursion.rs:16:1 + | +LL | type X2 = X3; + | ^^^^^^^ types differ + +error[E0271]: type mismatch resolving `X2 normalizes-to _` + --> $DIR/infinite-type-alias-mutual-recursion.rs:19:1 + | +LL | type X3 = X1; + | ^^^^^^^ types differ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/infinite/infinite-type-alias-mutual-recursion.feature_old.stderr b/tests/ui/infinite/infinite-type-alias-mutual-recursion.feature_old.stderr new file mode 100644 index 0000000000000..c7adc3af02fab --- /dev/null +++ b/tests/ui/infinite/infinite-type-alias-mutual-recursion.feature_old.stderr @@ -0,0 +1,27 @@ +error[E0275]: overflow normalizing the type alias `X2` + --> $DIR/infinite-type-alias-mutual-recursion.rs:12:1 + | +LL | type X1 = X2; + | ^^^^^^^ + | + = note: in case this is a recursive type alias, consider using a struct, enum, or union instead + +error[E0275]: overflow normalizing the type alias `X3` + --> $DIR/infinite-type-alias-mutual-recursion.rs:16:1 + | +LL | type X2 = X3; + | ^^^^^^^ + | + = note: in case this is a recursive type alias, consider using a struct, enum, or union instead + +error[E0275]: overflow normalizing the type alias `X1` + --> $DIR/infinite-type-alias-mutual-recursion.rs:19:1 + | +LL | type X3 = X1; + | ^^^^^^^ + | + = note: in case this is a recursive type alias, consider using a struct, enum, or union instead + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/infinite/infinite-type-alias-mutual-recursion.gated_new.stderr b/tests/ui/infinite/infinite-type-alias-mutual-recursion.gated_new.stderr new file mode 100644 index 0000000000000..888e1d18dea77 --- /dev/null +++ b/tests/ui/infinite/infinite-type-alias-mutual-recursion.gated_new.stderr @@ -0,0 +1,30 @@ +error[E0391]: cycle detected when expanding type alias `X1` + --> $DIR/infinite-type-alias-mutual-recursion.rs:12:11 + | +LL | type X1 = X2; + | ^^ + | +note: ...which requires expanding type alias `X2`... + --> $DIR/infinite-type-alias-mutual-recursion.rs:16:11 + | +LL | type X2 = X3; + | ^^ +note: ...which requires expanding type alias `X3`... + --> $DIR/infinite-type-alias-mutual-recursion.rs:19:11 + | +LL | type X3 = X1; + | ^^ + = note: ...which again requires expanding type alias `X1`, completing the cycle + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `X1` is well-formed + --> $DIR/infinite-type-alias-mutual-recursion.rs:12:1 + | +LL | type X1 = X2; + | ^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/infinite/infinite-type-alias-mutual-recursion.gated_old.stderr b/tests/ui/infinite/infinite-type-alias-mutual-recursion.gated_old.stderr new file mode 100644 index 0000000000000..888e1d18dea77 --- /dev/null +++ b/tests/ui/infinite/infinite-type-alias-mutual-recursion.gated_old.stderr @@ -0,0 +1,30 @@ +error[E0391]: cycle detected when expanding type alias `X1` + --> $DIR/infinite-type-alias-mutual-recursion.rs:12:11 + | +LL | type X1 = X2; + | ^^ + | +note: ...which requires expanding type alias `X2`... + --> $DIR/infinite-type-alias-mutual-recursion.rs:16:11 + | +LL | type X2 = X3; + | ^^ +note: ...which requires expanding type alias `X3`... + --> $DIR/infinite-type-alias-mutual-recursion.rs:19:11 + | +LL | type X3 = X1; + | ^^ + = note: ...which again requires expanding type alias `X1`, completing the cycle + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `X1` is well-formed + --> $DIR/infinite-type-alias-mutual-recursion.rs:12:1 + | +LL | type X1 = X2; + | ^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs b/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs index 6a43c4ac78720..24e1318ca3d7d 100644 --- a/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs +++ b/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs @@ -1,14 +1,23 @@ -//@ revisions: feature gated +//@ revisions: feature_old gated_old feature_new gated_new //@ ignore-parallel-frontend query cycle -#![cfg_attr(feature, feature(lazy_type_alias))] +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ [feature_new] compile-flags: -Znext-solver +//@ [gated_new] compile-flags: -Znext-solver + +#![feature(rustc_attrs)] +#![rustc_no_implicit_bounds] +#![cfg_attr(any(feature_old, feature_new), feature(lazy_type_alias))] #![allow(incomplete_features)] type X1 = X2; -//[gated]~^ ERROR cycle detected when expanding type alias `X1` -//[feature]~^^ ERROR: overflow normalizing the type alias `X2` +//[gated_old,gated_new]~^ ERROR cycle detected when expanding type alias `X1` +//[feature_old]~^^ ERROR: overflow normalizing the type alias `X2` +//[feature_new]~^^^ ERROR: type mismatch resolving `X3 normalizes-to _` type X2 = X3; -//[feature]~^ ERROR: overflow normalizing the type alias `X3` +//[feature_old]~^ ERROR: overflow normalizing the type alias `X3` +//[feature_new]~^^ ERROR: type mismatch resolving `X1 normalizes-to _` type X3 = X1; -//[feature]~^ ERROR: overflow normalizing the type alias `X1` +//[feature_old]~^ ERROR: overflow normalizing the type alias `X1` +//[feature_new]~^^ ERROR: type mismatch resolving `X2 normalizes-to _` fn main() {} diff --git a/tests/ui/layout/layout-cycle.rs b/tests/ui/layout/layout-cycle.rs index 846ce0882cad1..e873fcdaa97a9 100644 --- a/tests/ui/layout/layout-cycle.rs +++ b/tests/ui/layout/layout-cycle.rs @@ -1,11 +1,11 @@ //@ build-fail -//~^ ERROR: cycle detected when computing layout of // Issue #111176 -- ensure that we do not emit ICE on layout cycles use std::mem; pub struct S { + //~^ ERROR: cycle detected when computing layout of pub f: ::I, } diff --git a/tests/ui/layout/layout-cycle.stderr b/tests/ui/layout/layout-cycle.stderr index 28c35d431226e..0652f032c9dba 100644 --- a/tests/ui/layout/layout-cycle.stderr +++ b/tests/ui/layout/layout-cycle.stderr @@ -1,6 +1,14 @@ error[E0391]: cycle detected when computing layout of `S>` + --> $DIR/layout-cycle.rs:7:1 | - = note: ...which requires computing layout of ` as Tr>::I`... +LL | pub struct S { + | ^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing layout of ` as Tr>::I`... + --> $DIR/layout-cycle.rs:13:5 + | +LL | type I: Tr; + | ^^^^^^^^^^ = note: ...which again requires computing layout of `S>`, completing the cycle note: cycle used when const-evaluating + checking `core::mem::SizedTypeProperties::SIZE` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/layout/post-mono-layout-cycle.rs b/tests/ui/layout/post-mono-layout-cycle.rs index 841fc30a50bcf..71ccc8de94da2 100644 --- a/tests/ui/layout/post-mono-layout-cycle.rs +++ b/tests/ui/layout/post-mono-layout-cycle.rs @@ -1,5 +1,4 @@ //@ build-fail -//~^ ERROR cycle detected when computing layout of `Wrapper<()>` trait Trait { type Assoc; @@ -10,6 +9,7 @@ impl Trait for () { } struct Wrapper { + //~^ ERROR cycle detected when computing layout of `Wrapper<()>` _x: ::Assoc, } diff --git a/tests/ui/layout/post-mono-layout-cycle.stderr b/tests/ui/layout/post-mono-layout-cycle.stderr index b9b1b988499e6..05c57d20b8feb 100644 --- a/tests/ui/layout/post-mono-layout-cycle.stderr +++ b/tests/ui/layout/post-mono-layout-cycle.stderr @@ -1,8 +1,17 @@ error[E0391]: cycle detected when computing layout of `Wrapper<()>` + --> $DIR/post-mono-layout-cycle.rs:11:1 | - = note: ...which requires computing layout of `<() as Trait>::Assoc`... +LL | struct Wrapper { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing layout of `<() as Trait>::Assoc`... + --> $DIR/post-mono-layout-cycle.rs:4:5 + | +LL | type Assoc; + | ^^^^^^^^^^ = note: ...which again requires computing layout of `Wrapper<()>`, completing the cycle - = note: cycle used when computing layout of `core::option::Option>` +note: cycle used when computing layout of `core::option::Option>` + --> $SRC_DIR/core/src/option.rs:LL:COL = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error diff --git a/tests/ui/pattern/non-structural-match-types-cycle-err.stderr b/tests/ui/pattern/non-structural-match-types-cycle-err.stderr index 2f4ac63fc570a..a7dd597d96142 100644 --- a/tests/ui/pattern/non-structural-match-types-cycle-err.stderr +++ b/tests/ui/pattern/non-structural-match-types-cycle-err.stderr @@ -14,8 +14,13 @@ note: ...which requires const-evaluating + checking ` = None; | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `core::option::Option<{async block@$DIR/non-structural-match-types-cycle-err.rs:18:16: 18:21}>`... - = note: ...which requires computing layout of `{async block@$DIR/non-structural-match-types-cycle-err.rs:18:16: 18:21}`... +note: ...which requires computing layout of `core::option::Option<{async block@$DIR/non-structural-match-types-cycle-err.rs:18:16: 18:21}>`... + --> $SRC_DIR/core/src/option.rs:LL:COL +note: ...which requires computing layout of `{async block@$DIR/non-structural-match-types-cycle-err.rs:18:16: 18:21}`... + --> $DIR/non-structural-match-types-cycle-err.rs:18:16 + | +LL | match Some(async {}) { + | ^^^^^ note: ...which requires optimizing MIR for `defines::{closure#0}`... --> $DIR/non-structural-match-types-cycle-err.rs:18:16 | diff --git a/tests/ui/recursion/issue-26548-recursion-via-normalize.rs b/tests/ui/recursion/issue-26548-recursion-via-normalize.rs index 6c7fc4beb543d..a7eeccbfbd544 100644 --- a/tests/ui/recursion/issue-26548-recursion-via-normalize.rs +++ b/tests/ui/recursion/issue-26548-recursion-via-normalize.rs @@ -1,9 +1,8 @@ -//~ ERROR cycle detected when computing layout of `core::option::Option` -//~| NOTE see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -//~| NOTE ...which requires computing layout of `S`... -//~| NOTE ...which requires computing layout of `core::option::Option<::It>`... -//~| NOTE ...which again requires computing layout of `core::option::Option`, completing the cycle -//~| NOTE cycle used when computing layout of `core::option::Option<::It>` +//~? ERROR cycle detected when computing layout of `core::option::Option` +//~? NOTE see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +//~? NOTE ...which requires computing layout of `core::option::Option<::It>`... +//~? NOTE ...which again requires computing layout of `core::option::Option`, completing the cycle +//~? NOTE cycle used when computing layout of `core::option::Option<::It>` trait Mirror { type It: ?Sized; @@ -12,6 +11,7 @@ impl Mirror for T { type It = Self; } struct S(Option<::It>); +//~^ NOTE ...which requires computing layout of `S`... fn main() { let _s = S(None); diff --git a/tests/ui/recursion/issue-26548-recursion-via-normalize.stderr b/tests/ui/recursion/issue-26548-recursion-via-normalize.stderr index e77fb025bcf19..daf9240ec5c9a 100644 --- a/tests/ui/recursion/issue-26548-recursion-via-normalize.stderr +++ b/tests/ui/recursion/issue-26548-recursion-via-normalize.stderr @@ -1,9 +1,16 @@ error[E0391]: cycle detected when computing layout of `core::option::Option` + --> $SRC_DIR/core/src/option.rs:LL:COL | - = note: ...which requires computing layout of `S`... - = note: ...which requires computing layout of `core::option::Option<::It>`... +note: ...which requires computing layout of `S`... + --> $DIR/issue-26548-recursion-via-normalize.rs:13:1 + | +LL | struct S(Option<::It>); + | ^^^^^^^^ +note: ...which requires computing layout of `core::option::Option<::It>`... + --> $SRC_DIR/core/src/option.rs:LL:COL = note: ...which again requires computing layout of `core::option::Option`, completing the cycle - = note: cycle used when computing layout of `core::option::Option<::It>` +note: cycle used when computing layout of `core::option::Option<::It>` + --> $SRC_DIR/core/src/option.rs:LL:COL = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error diff --git a/tests/ui/rmeta/no_optimized_mir.rs b/tests/ui/rmeta/no_optimized_mir.rs index dbf612cd03cc7..c8ed00b039b23 100644 --- a/tests/ui/rmeta/no_optimized_mir.rs +++ b/tests/ui/rmeta/no_optimized_mir.rs @@ -10,5 +10,4 @@ fn main() { rmeta_meta::missing_optimized_mir(); } -//~? ERROR crate `rmeta_meta` required to be available in rlib format, but was not found in this form //~? ERROR missing optimized MIR for `missing_optimized_mir` in the crate `rmeta_meta` diff --git a/tests/ui/rmeta/no_optimized_mir.stderr b/tests/ui/rmeta/no_optimized_mir.stderr index 91aa98172fe56..254f100aa7b5e 100644 --- a/tests/ui/rmeta/no_optimized_mir.stderr +++ b/tests/ui/rmeta/no_optimized_mir.stderr @@ -1,5 +1,3 @@ -error: crate `rmeta_meta` required to be available in rlib format, but was not found in this form - error: missing optimized MIR for `missing_optimized_mir` in the crate `rmeta_meta` | note: missing optimized MIR for this item (was the crate `rmeta_meta` compiled with `--emit=metadata`?) @@ -8,5 +6,5 @@ note: missing optimized MIR for this item (was the crate `rmeta_meta` compiled w LL | pub fn missing_optimized_mir() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/sized/recursive-type-binding.rs b/tests/ui/sized/recursive-type-binding.rs index 52de04afd66d3..c67e8369a3b73 100644 --- a/tests/ui/sized/recursive-type-binding.rs +++ b/tests/ui/sized/recursive-type-binding.rs @@ -1,12 +1,14 @@ //@ build-fail -//~^ ERROR cycle detected when computing layout of `Foo<()>` -trait A { type Assoc: ?Sized; } +trait A { + type Assoc: ?Sized; +} impl A for () { type Assoc = Foo<()>; } struct Foo(T::Assoc); +//~^ ERROR cycle detected when computing layout of `Foo<()>` fn main() { let x: Foo<()>; diff --git a/tests/ui/sized/recursive-type-binding.stderr b/tests/ui/sized/recursive-type-binding.stderr index d9c2efa4d53b7..290262c16a079 100644 --- a/tests/ui/sized/recursive-type-binding.stderr +++ b/tests/ui/sized/recursive-type-binding.stderr @@ -1,9 +1,17 @@ error[E0391]: cycle detected when computing layout of `Foo<()>` + --> $DIR/recursive-type-binding.rs:10:1 | - = note: ...which requires computing layout of `<() as A>::Assoc`... +LL | struct Foo(T::Assoc); + | ^^^^^^^^^^^^^^^^ + | +note: ...which requires computing layout of `<() as A>::Assoc`... + --> $DIR/recursive-type-binding.rs:4:5 + | +LL | type Assoc: ?Sized; + | ^^^^^^^^^^^^^^^^^^ = note: ...which again requires computing layout of `Foo<()>`, completing the cycle note: cycle used when elaborating drops for `main` - --> $DIR/recursive-type-binding.rs:11:1 + --> $DIR/recursive-type-binding.rs:13:1 | LL | fn main() { | ^^^^^^^^^ diff --git a/tests/ui/sized/recursive-type-coercion-from-never.rs b/tests/ui/sized/recursive-type-coercion-from-never.rs index 7bd87ae06c5e4..7bb535bb20a75 100644 --- a/tests/ui/sized/recursive-type-coercion-from-never.rs +++ b/tests/ui/sized/recursive-type-coercion-from-never.rs @@ -1,15 +1,17 @@ //@ build-fail -//~^ ERROR cycle detected when computing layout of `Foo<()>` // Regression test for a stack overflow: https://github.com/rust-lang/rust/issues/113197 -trait A { type Assoc; } +trait A { + type Assoc; +} impl A for () { type Assoc = Foo<()>; } struct Foo(T::Assoc); +//~^ ERROR cycle detected when computing layout of `Foo<()>` fn main() { Foo::<()>(todo!()); diff --git a/tests/ui/sized/recursive-type-coercion-from-never.stderr b/tests/ui/sized/recursive-type-coercion-from-never.stderr index 7580e780dda59..1e04c2ab396f0 100644 --- a/tests/ui/sized/recursive-type-coercion-from-never.stderr +++ b/tests/ui/sized/recursive-type-coercion-from-never.stderr @@ -1,9 +1,17 @@ error[E0391]: cycle detected when computing layout of `Foo<()>` + --> $DIR/recursive-type-coercion-from-never.rs:13:1 | - = note: ...which requires computing layout of `<() as A>::Assoc`... +LL | struct Foo(T::Assoc); + | ^^^^^^^^^^^^^^^^ + | +note: ...which requires computing layout of `<() as A>::Assoc`... + --> $DIR/recursive-type-coercion-from-never.rs:6:5 + | +LL | type Assoc; + | ^^^^^^^^^^ = note: ...which again requires computing layout of `Foo<()>`, completing the cycle note: cycle used when elaborating drops for `main` - --> $DIR/recursive-type-coercion-from-never.rs:14:1 + --> $DIR/recursive-type-coercion-from-never.rs:16:1 | LL | fn main() { | ^^^^^^^^^ diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.rs b/tests/ui/sized/stack-overflow-trait-infer-98842.rs index d6522e3cfb643..ff080eb19d03c 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.rs +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.rs @@ -2,11 +2,11 @@ // issue: rust-lang/rust#98842 //@ check-fail //@ edition:2021 -//~^^^^ ERROR cycle detected when computing layout of `Foo` // If the inner `Foo` is named through an associated type, // the "infinite size" error does not occur. struct Foo(<&'static Foo as ::core::ops::Deref>::Target); +//~^ ERROR cycle detected when computing layout of `Foo` // But Rust will be unable to know whether `Foo` is sized or not, // and it will infinitely recurse somewhere trying to figure out the // size of this pointer (is my guess): diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.stderr index 5557a6fc45b89..f15d95ea94804 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.stderr +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.stderr @@ -1,6 +1,11 @@ error[E0391]: cycle detected when computing layout of `Foo` + --> $DIR/stack-overflow-trait-infer-98842.rs:8:1 | - = note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`... +LL | struct Foo(<&'static Foo as ::core::ops::Deref>::Target); + | ^^^^^^^^^^ + | +note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`... + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL = note: ...which again requires computing layout of `Foo`, completing the cycle note: cycle used when const-evaluating + checking `_` --> $DIR/stack-overflow-trait-infer-98842.rs:13:1 diff --git a/tests/ui/traits/assoc-type-hrtb-normalization-30472.rs b/tests/ui/traits/normalize/assoc-type-hrtb-normalization-30472.rs similarity index 100% rename from tests/ui/traits/assoc-type-hrtb-normalization-30472.rs rename to tests/ui/traits/normalize/assoc-type-hrtb-normalization-30472.rs diff --git a/tests/ui/traits/copy-impl-cannot-normalize.rs b/tests/ui/traits/normalize/copy-impl-cannot-normalize.rs similarity index 100% rename from tests/ui/traits/copy-impl-cannot-normalize.rs rename to tests/ui/traits/normalize/copy-impl-cannot-normalize.rs diff --git a/tests/ui/traits/copy-impl-cannot-normalize.stderr b/tests/ui/traits/normalize/copy-impl-cannot-normalize.stderr similarity index 100% rename from tests/ui/traits/copy-impl-cannot-normalize.stderr rename to tests/ui/traits/normalize/copy-impl-cannot-normalize.stderr diff --git a/tests/ui/traits/deep-norm-pending.rs b/tests/ui/traits/normalize/deep-norm-pending.rs similarity index 100% rename from tests/ui/traits/deep-norm-pending.rs rename to tests/ui/traits/normalize/deep-norm-pending.rs diff --git a/tests/ui/traits/deep-norm-pending.stderr b/tests/ui/traits/normalize/deep-norm-pending.stderr similarity index 100% rename from tests/ui/traits/deep-norm-pending.stderr rename to tests/ui/traits/normalize/deep-norm-pending.stderr diff --git a/tests/ui/traits/normalize-associated-type-in-where-clause.rs b/tests/ui/traits/normalize/normalize-associated-type-in-where-clause.rs similarity index 100% rename from tests/ui/traits/normalize-associated-type-in-where-clause.rs rename to tests/ui/traits/normalize/normalize-associated-type-in-where-clause.rs diff --git a/tests/ui/traits/normalize-conflicting-impls.rs b/tests/ui/traits/normalize/normalize-conflicting-impls.rs similarity index 100% rename from tests/ui/traits/normalize-conflicting-impls.rs rename to tests/ui/traits/normalize/normalize-conflicting-impls.rs diff --git a/tests/ui/traits/normalize-conflicting-impls.stderr b/tests/ui/traits/normalize/normalize-conflicting-impls.stderr similarity index 100% rename from tests/ui/traits/normalize-conflicting-impls.stderr rename to tests/ui/traits/normalize/normalize-conflicting-impls.stderr diff --git a/tests/ui/traits/normalize/normalize-diverging-alias-in-defaulted-type-parameter.rs b/tests/ui/traits/normalize/normalize-diverging-alias-in-defaulted-type-parameter.rs new file mode 100644 index 0000000000000..c359f8363e53e --- /dev/null +++ b/tests/ui/traits/normalize/normalize-diverging-alias-in-defaulted-type-parameter.rs @@ -0,0 +1,25 @@ +// Ensure that defaulted type parameters whose default contains diverging aliases are properly +// caught with both solvers. This is currently not the case, and this is tracked in issue +// https://github.com/rust-lang/rust/issues/156271. +// MCVE from https://github.com/rust-lang/trait-system-refactor-initiative/issues/139#issuecomment-2704576249. + +//@ revisions: current next +//@ check-pass +//@ known-bug: #156271 +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ [next] compile-flags: -Znext-solver + +#![feature(rustc_attrs)] +#![rustc_no_implicit_bounds] + +trait Trait { + type Diverges; +} + +impl Trait for T { + type Diverges = D::Diverges; +} + +struct Bar::Diverges>(*mut T); + +fn main() {} diff --git a/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.current.stderr b/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.current.stderr new file mode 100644 index 0000000000000..7787d6b68f257 --- /dev/null +++ b/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.current.stderr @@ -0,0 +1,9 @@ +error[E0275]: overflow evaluating the requirement `::Diverges == _` + --> $DIR/normalize-diverging-alias-in-struct.rs:21:12 + | +LL | field: Box<::Diverges>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.next.stderr b/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.next.stderr new file mode 100644 index 0000000000000..d7046d2b058ba --- /dev/null +++ b/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.next.stderr @@ -0,0 +1,18 @@ +error[E0271]: type mismatch resolving `::Diverges normalizes-to _` + --> $DIR/normalize-diverging-alias-in-struct.rs:21:12 + | +LL | field: Box<::Diverges>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + +error[E0271]: type mismatch resolving `::Diverges normalizes-to _` + --> $DIR/normalize-diverging-alias-in-struct.rs:21:12 + | +LL | field: Box<::Diverges>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | +note: required by a bound in `Box` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.rs b/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.rs new file mode 100644 index 0000000000000..45b2cb56c25f7 --- /dev/null +++ b/tests/ui/traits/normalize/normalize-diverging-alias-in-struct.rs @@ -0,0 +1,27 @@ +// Ensure that structs with fields whose types contain diverging aliases are properly caught with +// both solvers. +// MCVE from https://github.com/rust-lang/trait-system-refactor-initiative/issues/139#issuecomment-2703127026. + +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ [next] compile-flags: -Znext-solver + +#![feature(rustc_attrs)] +#![rustc_no_implicit_bounds] + +trait Trait { + type Diverges; +} + +impl Trait for T { + type Diverges = D::Diverges; +} + +struct Foo { + field: Box<::Diverges>, + //[current]~^ ERROR: overflow evaluating the requirement `::Diverges == _` + //[next]~^^ ERROR: type mismatch resolving `::Diverges normalizes-to _` + //[next]~| ERROR: type mismatch resolving `::Diverges normalizes-to _` +} + +fn main() {} diff --git a/tests/ui/traits/normalize-supertrait.rs b/tests/ui/traits/normalize/normalize-supertrait.rs similarity index 100% rename from tests/ui/traits/normalize-supertrait.rs rename to tests/ui/traits/normalize/normalize-supertrait.rs diff --git a/tests/ui/traits/pointee-normalize-equate.rs b/tests/ui/traits/normalize/pointee-normalize-equate.rs similarity index 100% rename from tests/ui/traits/pointee-normalize-equate.rs rename to tests/ui/traits/normalize/pointee-normalize-equate.rs diff --git a/tests/ui/traits/self-referential-param-env-normalization.rs b/tests/ui/traits/normalize/self-referential-param-env-normalization.rs similarity index 100% rename from tests/ui/traits/self-referential-param-env-normalization.rs rename to tests/ui/traits/normalize/self-referential-param-env-normalization.rs diff --git a/tests/ui/traits/self-referential-param-env-normalization.stderr b/tests/ui/traits/normalize/self-referential-param-env-normalization.stderr similarity index 100% rename from tests/ui/traits/self-referential-param-env-normalization.stderr rename to tests/ui/traits/normalize/self-referential-param-env-normalization.stderr diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.current.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization-2.current.stderr similarity index 100% rename from tests/ui/traits/unconstrained-projection-normalization-2.current.stderr rename to tests/ui/traits/normalize/unconstrained-projection-normalization-2.current.stderr diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization-2.next.stderr similarity index 100% rename from tests/ui/traits/unconstrained-projection-normalization-2.next.stderr rename to tests/ui/traits/normalize/unconstrained-projection-normalization-2.next.stderr diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.rs b/tests/ui/traits/normalize/unconstrained-projection-normalization-2.rs similarity index 100% rename from tests/ui/traits/unconstrained-projection-normalization-2.rs rename to tests/ui/traits/normalize/unconstrained-projection-normalization-2.rs diff --git a/tests/ui/traits/unconstrained-projection-normalization.current.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization.current.stderr similarity index 100% rename from tests/ui/traits/unconstrained-projection-normalization.current.stderr rename to tests/ui/traits/normalize/unconstrained-projection-normalization.current.stderr diff --git a/tests/ui/traits/unconstrained-projection-normalization.next.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization.next.stderr similarity index 100% rename from tests/ui/traits/unconstrained-projection-normalization.next.stderr rename to tests/ui/traits/normalize/unconstrained-projection-normalization.next.stderr diff --git a/tests/ui/traits/unconstrained-projection-normalization.rs b/tests/ui/traits/normalize/unconstrained-projection-normalization.rs similarity index 100% rename from tests/ui/traits/unconstrained-projection-normalization.rs rename to tests/ui/traits/normalize/unconstrained-projection-normalization.rs diff --git a/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.current.stderr b/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.current.stderr index 50dcea0bfac69..d429b08c8c986 100644 --- a/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.current.stderr +++ b/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.current.stderr @@ -1,8 +1,20 @@ error[E0391]: cycle detected when computing layout of `<[Hello] as Normalize>::Assoc` + --> $DIR/129541-recursive-enum-and-array-impl.rs:8:5 | - = note: ...which requires computing layout of `Hello`... +LL | type Assoc; + | ^^^^^^^^^^ + | +note: ...which requires computing layout of `Hello`... + --> $DIR/129541-recursive-enum-and-array-impl.rs:21:1 + | +LL | enum Hello { + | ^^^^^^^^^^ = note: ...which again requires computing layout of `<[Hello] as Normalize>::Assoc`, completing the cycle - = note: cycle used when computing layout of `Hello` +note: cycle used when computing layout of `Hello` + --> $DIR/129541-recursive-enum-and-array-impl.rs:21:1 + | +LL | enum Hello { + | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error diff --git a/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.next.stderr b/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.next.stderr index 50dcea0bfac69..d429b08c8c986 100644 --- a/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.next.stderr +++ b/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.next.stderr @@ -1,8 +1,20 @@ error[E0391]: cycle detected when computing layout of `<[Hello] as Normalize>::Assoc` + --> $DIR/129541-recursive-enum-and-array-impl.rs:8:5 | - = note: ...which requires computing layout of `Hello`... +LL | type Assoc; + | ^^^^^^^^^^ + | +note: ...which requires computing layout of `Hello`... + --> $DIR/129541-recursive-enum-and-array-impl.rs:21:1 + | +LL | enum Hello { + | ^^^^^^^^^^ = note: ...which again requires computing layout of `<[Hello] as Normalize>::Assoc`, completing the cycle - = note: cycle used when computing layout of `Hello` +note: cycle used when computing layout of `Hello` + --> $DIR/129541-recursive-enum-and-array-impl.rs:21:1 + | +LL | enum Hello { + | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error diff --git a/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.rs b/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.rs index 5b7bf5f3404c3..6c0411135dad0 100644 --- a/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.rs +++ b/tests/ui/traits/solver-cycles/129541-recursive-enum-and-array-impl.rs @@ -1,6 +1,4 @@ // Regression test for #129541 -//~^ ERROR cycle detected when computing layout of `<[Hello] as Normalize>::Assoc` [E0391] - //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver @@ -8,6 +6,7 @@ trait Bound {} trait Normalize { type Assoc; + //~^ ERROR cycle detected when computing layout of `<[Hello] as Normalize>::Assoc` [E0391] } impl Normalize for T { diff --git a/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr b/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr index 13ae6dfcaa354..8b6d11b8df85c 100644 --- a/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr +++ b/tests/ui/type-alias-enum-variants/self-in-enum-definition.stderr @@ -9,7 +9,11 @@ note: ...which requires const-evaluating + checking `Alpha::V3::{constant#0}`... | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `Alpha`... +note: ...which requires computing layout of `Alpha`... + --> $DIR/self-in-enum-definition.rs:2:1 + | +LL | enum Alpha { + | ^^^^^^^^^^ = note: ...which again requires simplifying constant for the type system `Alpha::V3::{constant#0}`, completing the cycle note: cycle used when checking that `Alpha` is well-formed --> $DIR/self-in-enum-definition.rs:2:1