From c67aea7fddcf613abd3c76ee4ac31eced6da8265 Mon Sep 17 00:00:00 2001 From: wackbyte Date: Mon, 24 Apr 2023 10:14:03 -0400 Subject: [PATCH 01/34] rustdoc: fix position of `default` in method rendering --- src/librustdoc/html/render/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f923f9054512..4ba648f8ad14 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -820,6 +820,7 @@ fn assoc_method( let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item"); let name = meth.name.as_ref().unwrap(); let vis = visibility_print_with_space(meth.visibility(tcx), meth.item_id, cx).to_string(); + let defaultness = print_default_space(meth.is_default()); // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove // this condition. let constness = match render_mode { @@ -830,7 +831,6 @@ fn assoc_method( }; let asyncness = header.asyncness.print_with_space(); let unsafety = header.unsafety.print_with_space(); - let defaultness = print_default_space(meth.is_default()); let abi = print_abi_with_space(header.abi).to_string(); let href = assoc_href_attr(meth, link, cx); @@ -838,10 +838,10 @@ fn assoc_method( let generics_len = format!("{:#}", g.print(cx)).len(); let mut header_len = "fn ".len() + vis.len() + + defaultness.len() + constness.len() + asyncness.len() + unsafety.len() - + defaultness.len() + abi.len() + name.as_str().len() + generics_len; @@ -860,14 +860,14 @@ fn assoc_method( w.reserve(header_len + "{".len() + "".len()); write!( w, - "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn \ + "{indent}{vis}{defaultness}{constness}{asyncness}{unsafety}{abi}fn \ {name}{generics}{decl}{notable_traits}{where_clause}", indent = indent_str, vis = vis, + defaultness = defaultness, constness = constness, asyncness = asyncness, unsafety = unsafety, - defaultness = defaultness, abi = abi, href = href, name = name, From 13f58a8ea02fa6d62b0c44ceda9d5332562e1339 Mon Sep 17 00:00:00 2001 From: wackbyte Date: Thu, 22 Jun 2023 22:28:29 -0400 Subject: [PATCH 02/34] Add tests for default unsafe trait methods --- tests/rustdoc/default-trait-method.rs | 43 +++++++++++++++++++-------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/tests/rustdoc/default-trait-method.rs b/tests/rustdoc/default-trait-method.rs index 6d0e339c48dc..c89506781640 100644 --- a/tests/rustdoc/default-trait-method.rs +++ b/tests/rustdoc/default-trait-method.rs @@ -1,26 +1,45 @@ #![feature(min_specialization)] // @has default_trait_method/trait.Item.html -// @has - '//*[@id="tymethod.foo"]' 'fn foo()' -// @!has - '//*[@id="tymethod.foo"]' 'default fn foo()' -// @has - '//*[@id="tymethod.bar"]' 'fn bar()' -// @!has - '//*[@id="tymethod.bar"]' 'default fn bar()' -// @has - '//*[@id="method.baz"]' 'fn baz()' -// @!has - '//*[@id="method.baz"]' 'default fn baz()' pub trait Item { + // @has - '//*[@id="tymethod.foo"]' 'fn foo()' + // @!has - '//*[@id="tymethod.foo"]' 'default fn foo()' fn foo(); + + // @has - '//*[@id="tymethod.bar"]' 'fn bar()' + // @!has - '//*[@id="tymethod.bar"]' 'default fn bar()' fn bar(); - fn baz() {} + + // @has - '//*[@id="tymethod.baz"]' 'unsafe fn baz()' + // @!has - '//*[@id="tymethod.baz"]' 'default unsafe fn baz()' + unsafe fn baz(); + + // @has - '//*[@id="tymethod.quux"]' 'unsafe fn quux()' + // @!has - '//*[@id="tymethod.quux"]' 'default unsafe fn quux()' + unsafe fn quux(); + + // @has - '//*[@id="method.xyzzy"]' 'fn xyzzy()' + // @!has - '//*[@id="method.xyzzy"]' 'default fn xyzzy()' + fn xyzzy() {} } // @has default_trait_method/struct.Foo.html -// @has - '//*[@id="method.foo"]' 'default fn foo()' -// @has - '//*[@id="method.bar"]' 'fn bar()' -// @!has - '//*[@id="method.bar"]' 'default fn bar()' -// @has - '//*[@id="method.baz"]' 'fn baz()' -// @!has - '//*[@id="method.baz"]' 'default fn baz()' pub struct Foo; impl Item for Foo { + // @has - '//*[@id="method.foo"]' 'default fn foo()' default fn foo() {} + + // @has - '//*[@id="method.bar"]' 'fn bar()' + // @!has - '//*[@id="method.bar"]' 'default fn bar()' fn bar() {} + + // @has - '//*[@id="method.baz"]' 'default unsafe fn baz()' + default unsafe fn baz() {} + + // @has - '//*[@id="method.quux"]' 'unsafe fn quux()' + // @!has - '//*[@id="method.quux"]' 'default unsafe fn quux()' + unsafe fn quux() {} + + // @has - '//*[@id="method.xyzzy"]' 'fn xyzzy()' + // @!has - '//*[@id="method.xyzzy"]' 'default fn xyzzy()' } From 85a98b0452d9c2def6da74939692843e929ee350 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 24 Apr 2023 17:57:41 -0700 Subject: [PATCH 03/34] Add test of --print KIND=PATH --- tests/run-make/print-cfg/Makefile | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/run-make/print-cfg/Makefile b/tests/run-make/print-cfg/Makefile index 126f5768c90f..d382f1562fa4 100644 --- a/tests/run-make/print-cfg/Makefile +++ b/tests/run-make/print-cfg/Makefile @@ -2,7 +2,7 @@ include ../tools.mk -all: default +all: default output_to_file $(RUSTC) --target x86_64-pc-windows-gnu --print cfg | $(CGREP) windows $(RUSTC) --target x86_64-pc-windows-gnu --print cfg | $(CGREP) x86_64 $(RUSTC) --target i686-pc-windows-msvc --print cfg | $(CGREP) msvc @@ -11,6 +11,23 @@ all: default $(RUSTC) --target arm-unknown-linux-gnueabihf --print cfg | $(CGREP) target_abi= $(RUSTC) --target arm-unknown-linux-gnueabihf --print cfg | $(CGREP) eabihf +output_to_file: + # Backend-independent, printed by rustc_driver_impl/src/lib.rs + $(RUSTC) --target x86_64-pc-windows-gnu --print cfg=$(TMPDIR)/cfg.txt + $(CGREP) windows < $(TMPDIR)/cfg.txt + + # Printed from CodegenBackend trait impl in rustc_codegen_llvm/src/lib.rs + $(RUSTC) --print relocation-models=$(TMPDIR)/relocation-models.txt + $(CGREP) dynamic-no-pic < $(TMPDIR)/relocation-models.txt + + # Printed by compiler/rustc_codegen_llvm/src/llvm_util.rs + $(RUSTC) --target wasm32-unknown-unknown --print target-features=$(TMPDIR)/target-features.txt + $(CGREP) reference-types < $(TMPDIR)/target-features.txt + + # Printed by C++ code in rustc_llvm/llvm-wrapper/PassWrapper.cpp + $(RUSTC) --target x86_64-pc-windows-gnu --print target-cpus=$(TMPDIR)/target-cpus.txt + $(CGREP) native < $(TMPDIR)/target-cpus.txt + ifdef IS_WINDOWS default: $(RUSTC) --print cfg | $(CGREP) windows From 2f0174253e8ed1ef2ed6ab1a4da00804e304a8a4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 17:20:28 -0700 Subject: [PATCH 04/34] Store individual output file name with every PrintRequest --- compiler/rustc_codegen_llvm/src/lib.rs | 16 ++--- compiler/rustc_codegen_llvm/src/llvm_util.rs | 10 +-- compiler/rustc_codegen_ssa/src/back/link.rs | 6 +- .../rustc_codegen_ssa/src/traits/backend.rs | 2 +- compiler/rustc_driver_impl/src/lib.rs | 14 ++-- compiler/rustc_session/src/config.rs | 69 ++++++++++--------- 6 files changed, 61 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 24ba28bbc82c..38a32ac845d2 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -40,7 +40,7 @@ use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest}; +use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest}; use rustc_session::Session; use rustc_span::symbol::Symbol; @@ -262,9 +262,9 @@ impl CodegenBackend for LlvmCodegenBackend { |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true) } - fn print(&self, req: PrintRequest, sess: &Session) { - match req { - PrintRequest::RelocationModels => { + fn print(&self, req: &PrintRequest, sess: &Session) { + match req.kind { + PrintKind::RelocationModels => { println!("Available relocation models:"); for name in &[ "static", @@ -280,21 +280,21 @@ impl CodegenBackend for LlvmCodegenBackend { } println!(); } - PrintRequest::CodeModels => { + PrintKind::CodeModels => { println!("Available code models:"); for name in &["tiny", "small", "kernel", "medium", "large"] { println!(" {}", name); } println!(); } - PrintRequest::TlsModels => { + PrintKind::TlsModels => { println!("Available TLS models:"); for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] { println!(" {}", name); } println!(); } - PrintRequest::StackProtectorStrategies => { + PrintKind::StackProtectorStrategies => { println!( r#"Available stack protector strategies: all @@ -319,7 +319,7 @@ impl CodegenBackend for LlvmCodegenBackend { "# ); } - req => llvm_util::print(req, sess), + _other => llvm_util::print(req, sess), } } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 03be0654b50b..84d9acf45de5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_fs_util::path_to_c_string; use rustc_middle::bug; -use rustc_session::config::PrintRequest; +use rustc_session::config::{PrintKind, PrintRequest}; use rustc_session::Session; use rustc_span::symbol::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy}; @@ -400,11 +400,11 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) { println!("and may be renamed or removed in a future version of LLVM or rustc.\n"); } -pub(crate) fn print(req: PrintRequest, sess: &Session) { +pub(crate) fn print(req: &PrintRequest, sess: &Session) { require_inited(); let tm = create_informational_target_machine(sess); - match req { - PrintRequest::TargetCPUs => { + match req.kind { + PrintKind::TargetCPUs => { // SAFETY generate a C compatible string from a byte slice to pass // the target CPU name into LLVM, the lifetime of the reference is // at least as long as the C function @@ -412,7 +412,7 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) { .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e)); unsafe { llvm::LLVMRustPrintTargetCPUs(tm, cpu_cstring.as_ptr()) }; } - PrintRequest::TargetFeatures => print_target_features(sess, tm), + PrintKind::TargetFeatures => print_target_features(sess, tm), _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 0dfb41f42f0d..bb8a520321a1 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -13,7 +13,7 @@ use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, Strip}; -use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind}; +use rustc_session::config::{OutputFilenames, OutputType, PrintKind, SplitDwarfKind}; use rustc_session::cstore::DllImport; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::search_paths::PathKind; @@ -596,7 +596,7 @@ fn link_staticlib<'a>( all_native_libs.extend_from_slice(&codegen_results.crate_info.used_libraries); - if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { + if sess.opts.prints.iter().any(|print| print.kind == PrintKind::NativeStaticLibs) { print_native_static_libs(sess, &all_native_libs, &all_rust_dylibs); } @@ -744,7 +744,7 @@ fn link_natively<'a>( cmd.env_remove(k.as_ref()); } - if sess.opts.prints.contains(&PrintRequest::LinkArgs) { + if sess.opts.prints.iter().any(|print| print.kind == PrintKind::LinkArgs) { println!("{:?}", &cmd); } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index b3c9ecf8b938..f10bbbeb97cc 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -61,7 +61,7 @@ pub trait CodegenBackend { fn locale_resource(&self) -> &'static str; fn init(&self, _sess: &Session) {} - fn print(&self, _req: PrintRequest, _sess: &Session) {} + fn print(&self, _req: &PrintRequest, _sess: &Session) {} fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { vec![] } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 25c043149e81..27dfb6c3bca6 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -35,9 +35,7 @@ use rustc_interface::{interface, Queries}; use rustc_lint::LintStore; use rustc_metadata::locator; use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; -use rustc_session::config::{ - ErrorOutputType, Input, OutFileName, OutputType, PrintRequest, TrimmedDefPaths, -}; +use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType, TrimmedDefPaths}; use rustc_session::cstore::MetadataLoader; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; @@ -714,10 +712,10 @@ fn print_crate_info( sess: &Session, parse_attrs: bool, ) -> Compilation { - use rustc_session::config::PrintRequest::*; + use rustc_session::config::PrintKind::*; // NativeStaticLibs and LinkArgs are special - printed during linking // (empty iterator returns true) - if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) { + if sess.opts.prints.iter().all(|p| p.kind == NativeStaticLibs || p.kind == LinkArgs) { return Compilation::Continue; } @@ -734,7 +732,7 @@ fn print_crate_info( None }; for req in &sess.opts.prints { - match *req { + match req.kind { TargetList => { let mut targets = rustc_target::spec::TARGETS.to_vec(); targets.sort_unstable(); @@ -761,7 +759,7 @@ fn print_crate_info( }; let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); let id = rustc_session::output::find_crate_name(sess, attrs); - if *req == PrintRequest::CrateName { + if req.kind == CrateName { safe_println!("{id}"); continue; } @@ -817,7 +815,7 @@ fn print_crate_info( | TargetCPUs | StackProtectorStrategies | TargetFeatures => { - codegen_backend.print(*req, sess); + codegen_backend.print(req, sess); } // Any output here interferes with Cargo's parsing of other printed output NativeStaticLibs => {} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 593983f117d0..261d3529b141 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -710,8 +710,14 @@ impl ExternEntry { } } +#[derive(Clone, PartialEq, Debug)] +pub struct PrintRequest { + pub kind: PrintKind, + pub out: OutFileName, +} + #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum PrintRequest { +pub enum PrintKind { FileNames, Sysroot, TargetLibdir, @@ -2091,41 +2097,41 @@ fn collect_print_requests( ) -> Vec { let mut prints = Vec::::new(); if cg.target_cpu.as_ref().is_some_and(|s| s == "help") { - prints.push(PrintRequest::TargetCPUs); + prints.push(PrintRequest { kind: PrintKind::TargetCPUs, out: OutFileName::Stdout }); cg.target_cpu = None; }; if cg.target_feature == "help" { - prints.push(PrintRequest::TargetFeatures); + prints.push(PrintRequest { kind: PrintKind::TargetFeatures, out: OutFileName::Stdout }); cg.target_feature = String::new(); } - const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[ - ("crate-name", PrintRequest::CrateName), - ("file-names", PrintRequest::FileNames), - ("sysroot", PrintRequest::Sysroot), - ("target-libdir", PrintRequest::TargetLibdir), - ("cfg", PrintRequest::Cfg), - ("calling-conventions", PrintRequest::CallingConventions), - ("target-list", PrintRequest::TargetList), - ("target-cpus", PrintRequest::TargetCPUs), - ("target-features", PrintRequest::TargetFeatures), - ("relocation-models", PrintRequest::RelocationModels), - ("code-models", PrintRequest::CodeModels), - ("tls-models", PrintRequest::TlsModels), - ("native-static-libs", PrintRequest::NativeStaticLibs), - ("stack-protector-strategies", PrintRequest::StackProtectorStrategies), - ("target-spec-json", PrintRequest::TargetSpec), - ("all-target-specs-json", PrintRequest::AllTargetSpecs), - ("link-args", PrintRequest::LinkArgs), - ("split-debuginfo", PrintRequest::SplitDebuginfo), - ("deployment-target", PrintRequest::DeploymentTarget), + const PRINT_KINDS: &[(&str, PrintKind)] = &[ + ("crate-name", PrintKind::CrateName), + ("file-names", PrintKind::FileNames), + ("sysroot", PrintKind::Sysroot), + ("target-libdir", PrintKind::TargetLibdir), + ("cfg", PrintKind::Cfg), + ("calling-conventions", PrintKind::CallingConventions), + ("target-list", PrintKind::TargetList), + ("target-cpus", PrintKind::TargetCPUs), + ("target-features", PrintKind::TargetFeatures), + ("relocation-models", PrintKind::RelocationModels), + ("code-models", PrintKind::CodeModels), + ("tls-models", PrintKind::TlsModels), + ("native-static-libs", PrintKind::NativeStaticLibs), + ("stack-protector-strategies", PrintKind::StackProtectorStrategies), + ("target-spec-json", PrintKind::TargetSpec), + ("all-target-specs-json", PrintKind::AllTargetSpecs), + ("link-args", PrintKind::LinkArgs), + ("split-debuginfo", PrintKind::SplitDebuginfo), + ("deployment-target", PrintKind::DeploymentTarget), ]; prints.extend(matches.opt_strs("print").into_iter().map(|req| { - match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) { - Some((_, PrintRequest::TargetSpec)) => { + let kind = match PRINT_KINDS.iter().find(|&&(name, _)| name == req) { + Some((_, PrintKind::TargetSpec)) => { if unstable_opts.unstable_options { - PrintRequest::TargetSpec + PrintKind::TargetSpec } else { handler.early_error( "the `-Z unstable-options` flag must also be passed to \ @@ -2133,9 +2139,9 @@ fn collect_print_requests( ); } } - Some((_, PrintRequest::AllTargetSpecs)) => { + Some((_, PrintKind::AllTargetSpecs)) => { if unstable_opts.unstable_options { - PrintRequest::AllTargetSpecs + PrintKind::AllTargetSpecs } else { handler.early_error( "the `-Z unstable-options` flag must also be passed to \ @@ -2143,16 +2149,17 @@ fn collect_print_requests( ); } } - Some(&(_, print_request)) => print_request, + Some(&(_, print_kind)) => print_kind, None => { let prints = - PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::>(); + PRINT_KINDS.iter().map(|(name, _)| format!("`{name}`")).collect::>(); let prints = prints.join(", "); handler.early_error(format!( "unknown print request `{req}`. Valid print requests are: {prints}" )); } - } + }; + PrintRequest { kind, out: OutFileName::Stdout } })); prints From 6dbe5bcc69aee1b8db699603c6635e53062d3e68 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 17:58:46 -0700 Subject: [PATCH 05/34] Parse --print KIND=PATH command line syntax --- compiler/rustc_session/src/config.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 261d3529b141..738625485c49 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2011,13 +2011,7 @@ fn parse_output_types( if !unstable_opts.parse_only { for list in matches.opt_strs("emit") { for output_type in list.split(',') { - let (shorthand, path) = match output_type.split_once('=') { - None => (output_type, None), - Some((shorthand, "-")) => (shorthand, Some(OutFileName::Stdout)), - Some((shorthand, path)) => { - (shorthand, Some(OutFileName::Real(PathBuf::from(path)))) - } - }; + let (shorthand, path) = split_out_file_name(output_type); let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| { handler.early_error(format!( "unknown emission type: `{shorthand}` - expected one of: {display}", @@ -2034,6 +2028,14 @@ fn parse_output_types( OutputTypes(output_types) } +fn split_out_file_name(arg: &str) -> (&str, Option) { + match arg.split_once('=') { + None => (arg, None), + Some((kind, "-")) => (kind, Some(OutFileName::Stdout)), + Some((kind, path)) => (kind, Some(OutFileName::Real(PathBuf::from(path)))), + } +} + fn should_override_cgus_and_disable_thinlto( handler: &EarlyErrorHandler, output_types: &OutputTypes, @@ -2128,6 +2130,8 @@ fn collect_print_requests( ]; prints.extend(matches.opt_strs("print").into_iter().map(|req| { + let (req, out) = split_out_file_name(&req); + let kind = match PRINT_KINDS.iter().find(|&&(name, _)| name == req) { Some((_, PrintKind::TargetSpec)) => { if unstable_opts.unstable_options { @@ -2159,7 +2163,9 @@ fn collect_print_requests( )); } }; - PrintRequest { kind, out: OutFileName::Stdout } + + let out = out.unwrap_or(OutFileName::Stdout); + PrintRequest { kind, out } })); prints From 927a4d609bf3088cdbc23cf210ac03dc93c4944a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 19:06:04 -0700 Subject: [PATCH 06/34] Disallow overlapping prints to the same location --- compiler/rustc_session/src/config.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 738625485c49..ee871dc8005c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2129,6 +2129,12 @@ fn collect_print_requests( ("deployment-target", PrintKind::DeploymentTarget), ]; + // We disallow reusing the same path in multiple prints, such as `--print + // cfg=output.txt --print link-args=output.txt`, because outputs are printed + // by disparate pieces of the compiler, and keeping track of which files + // need to be overwritten vs appended to is annoying. + let mut printed_paths = FxHashSet::default(); + prints.extend(matches.opt_strs("print").into_iter().map(|req| { let (req, out) = split_out_file_name(&req); @@ -2165,6 +2171,15 @@ fn collect_print_requests( }; let out = out.unwrap_or(OutFileName::Stdout); + if let OutFileName::Real(path) = &out { + if !printed_paths.insert(path.clone()) { + handler.early_error(format!( + "cannot print multiple outputs to the same path: {}", + path.display(), + )); + } + } + PrintRequest { kind, out } })); From 11a2b0b3700b7826b6fda28394f1cc37ccbaa914 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 22:13:08 -0700 Subject: [PATCH 07/34] Move OutFileName writing into rustc_session --- compiler/rustc_driver_impl/messages.ftl | 2 -- compiler/rustc_driver_impl/src/pretty.rs | 13 +------------ .../rustc_driver_impl/src/session_diagnostics.rs | 7 ------- compiler/rustc_session/messages.ftl | 2 ++ compiler/rustc_session/src/config.rs | 13 +++++++++++++ compiler/rustc_session/src/errors.rs | 7 +++++++ tests/ui/unpretty/avoid-crash.stderr | 2 +- 7 files changed, 24 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index 22b4ec6b0d1b..f8e25e008008 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -15,5 +15,3 @@ driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc ver driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}` driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file - -driver_impl_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}` diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 24a5f4030b88..222c7b5d6a72 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -1,6 +1,5 @@ //! The various pretty-printing routines. -use crate::session_diagnostics::UnprettyDumpFail; use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_errors::ErrorGuaranteed; @@ -358,17 +357,7 @@ fn get_source(sess: &Session) -> (String, FileName) { } fn write_or_print(out: &str, sess: &Session) { - match &sess.io.output_file { - None | Some(OutFileName::Stdout) => print!("{out}"), - Some(OutFileName::Real(p)) => { - if let Err(e) = std::fs::write(p, out) { - sess.emit_fatal(UnprettyDumpFail { - path: p.display().to_string(), - err: e.to_string(), - }); - } - } - } + sess.io.output_file.as_ref().unwrap_or(&OutFileName::Stdout).overwrite(out, sess); } pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) { diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs index 638b368f7021..8e5347eba96c 100644 --- a/compiler/rustc_driver_impl/src/session_diagnostics.rs +++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs @@ -32,13 +32,6 @@ pub(crate) struct RLinkRustcVersionMismatch<'a> { #[diag(driver_impl_rlink_no_a_file)] pub(crate) struct RlinkNotAFile; -#[derive(Diagnostic)] -#[diag(driver_impl_unpretty_dump_fail)] -pub(crate) struct UnprettyDumpFail { - pub path: String, - pub err: String, -} - #[derive(Diagnostic)] #[diag(driver_impl_ice)] pub(crate) struct Ice; diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 4897bd8d5dae..ee24c6d902fa 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -26,6 +26,8 @@ session_feature_gate_error = {$explain} session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions +session_file_write_fail = failed to write `{$path}` due to error `{$err}` + session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index ee871dc8005c..a8147ede970c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3,6 +3,7 @@ pub use crate::options::*; +use crate::errors::FileWriteFail; use crate::search_paths::SearchPath; use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use crate::{lint, HashStableContext}; @@ -31,6 +32,7 @@ use std::collections::btree_map::{ use std::collections::{BTreeMap, BTreeSet}; use std::ffi::OsStr; use std::fmt; +use std::fs; use std::hash::Hash; use std::iter; use std::path::{Path, PathBuf}; @@ -861,6 +863,17 @@ impl OutFileName { OutFileName::Stdout => outputs.temp_path(flavor, codegen_unit_name), } } + + pub fn overwrite(&self, content: &str, sess: &Session) { + match self { + OutFileName::Stdout => print!("{content}"), + OutFileName::Real(path) => { + if let Err(e) = fs::write(path, content) { + sess.emit_fatal(FileWriteFail { path, err: e.to_string() }); + } + } + } + } } #[derive(Clone, Hash, Debug, HashStable_Generic)] diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 4a3e668da111..dd15ad45145f 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -163,6 +163,13 @@ pub struct FileIsNotWriteable<'a> { pub file: &'a std::path::Path, } +#[derive(Diagnostic)] +#[diag(session_file_write_fail)] +pub(crate) struct FileWriteFail<'a> { + pub path: &'a std::path::Path, + pub err: String, +} + #[derive(Diagnostic)] #[diag(session_crate_name_does_not_match)] pub struct CrateNameDoesNotMatch { diff --git a/tests/ui/unpretty/avoid-crash.stderr b/tests/ui/unpretty/avoid-crash.stderr index 11cd3866fa86..15bcc277e649 100644 --- a/tests/ui/unpretty/avoid-crash.stderr +++ b/tests/ui/unpretty/avoid-crash.stderr @@ -1,4 +1,4 @@ -error: pretty-print failed to write `/tmp/` due to $ERROR_MESSAGE +error: failed to write `/tmp/` due to $ERROR_MESSAGE error: aborting due to previous error From be9881a0f2fb47c81c02c0ea4f6625d0b5382064 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 22:29:05 -0700 Subject: [PATCH 08/34] Implement printing to file in print_crate_info --- compiler/rustc_driver_impl/src/lib.rs | 55 ++++++++++++++++++--------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 27dfb6c3bca6..a17310206323 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -49,6 +49,7 @@ use std::cmp::max; use std::collections::BTreeMap; use std::env; use std::ffi::OsString; +use std::fmt::Write as _; use std::fs; use std::io::{self, IsTerminal, Read, Write}; use std::panic::{self, catch_unwind}; @@ -65,6 +66,11 @@ macro do_not_use_print($($t:tt)*) { ) } +#[allow(unused_macros)] +macro do_not_use_safe_print($($t:tt)*) { + std::compile_error!("Don't use `safe_print` or `safe_println` here, use `println_info` instead") +} + // This import blocks the use of panicking `print` and `println` in all the code // below. Please use `safe_print` and `safe_println` to avoid ICE when // encountering an I/O error during print. @@ -713,6 +719,13 @@ fn print_crate_info( parse_attrs: bool, ) -> Compilation { use rustc_session::config::PrintKind::*; + + // This import prevents the following code from using the printing macros + // used by the rest of the module. Within this function, we only write to + // the output specified by `sess.io.output_file`. + #[allow(unused_imports)] + use {do_not_use_safe_print as safe_print, do_not_use_safe_print as safe_println}; + // NativeStaticLibs and LinkArgs are special - printed during linking // (empty iterator returns true) if sess.opts.prints.iter().all(|p| p.kind == NativeStaticLibs || p.kind == LinkArgs) { @@ -731,17 +744,23 @@ fn print_crate_info( } else { None }; + for req in &sess.opts.prints { + let mut crate_info = String::new(); + macro println_info($($arg:tt)*) { + crate_info.write_fmt(format_args!("{}\n", format_args!($($arg)*))).unwrap() + } + match req.kind { TargetList => { let mut targets = rustc_target::spec::TARGETS.to_vec(); targets.sort_unstable(); - safe_println!("{}", targets.join("\n")); + println_info!("{}", targets.join("\n")); } - Sysroot => safe_println!("{}", sess.sysroot.display()), - TargetLibdir => safe_println!("{}", sess.target_tlib_path.dir.display()), + Sysroot => println_info!("{}", sess.sysroot.display()), + TargetLibdir => println_info!("{}", sess.target_tlib_path.dir.display()), TargetSpec => { - safe_println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); + println_info!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); } AllTargetSpecs => { let mut targets = BTreeMap::new(); @@ -750,7 +769,7 @@ fn print_crate_info( let target = Target::expect_builtin(&triple); targets.insert(name, target.to_json()); } - safe_println!("{}", serde_json::to_string_pretty(&targets).unwrap()); + println_info!("{}", serde_json::to_string_pretty(&targets).unwrap()); } FileNames | CrateName => { let Some(attrs) = attrs.as_ref() else { @@ -760,14 +779,14 @@ fn print_crate_info( let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); let id = rustc_session::output::find_crate_name(sess, attrs); if req.kind == CrateName { - safe_println!("{id}"); - continue; - } - let crate_types = collect_crate_types(sess, attrs); - for &style in &crate_types { - let fname = - rustc_session::output::filename_for_input(sess, style, id, &t_outputs); - safe_println!("{}", fname.as_path().file_name().unwrap().to_string_lossy()); + println_info!("{id}"); + } else { + let crate_types = collect_crate_types(sess, attrs); + for &style in &crate_types { + let fname = + rustc_session::output::filename_for_input(sess, style, id, &t_outputs); + println_info!("{}", fname.as_path().file_name().unwrap().to_string_lossy()); + } } } Cfg => { @@ -801,13 +820,13 @@ fn print_crate_info( cfgs.sort(); for cfg in cfgs { - safe_println!("{cfg}"); + println_info!("{cfg}"); } } CallingConventions => { let mut calling_conventions = rustc_target::spec::abi::all_names(); calling_conventions.sort_unstable(); - safe_println!("{}", calling_conventions.join("\n")); + println_info!("{}", calling_conventions.join("\n")); } RelocationModels | CodeModels @@ -825,7 +844,7 @@ fn print_crate_info( for split in &[Off, Packed, Unpacked] { if sess.target.options.supported_split_debuginfo.contains(split) { - safe_println!("{split}"); + println_info!("{split}"); } } } @@ -833,7 +852,7 @@ fn print_crate_info( use rustc_target::spec::current_apple_deployment_target; if sess.target.is_like_osx { - safe_println!( + println_info!( "deployment_target={}", current_apple_deployment_target(&sess.target) .expect("unknown Apple target OS") @@ -844,6 +863,8 @@ fn print_crate_info( } } } + + req.out.overwrite(&crate_info, sess); } Compilation::Stop } From 74b24f316f8cc64d3d6f002a73be4ada1e0063e3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 22:33:38 -0700 Subject: [PATCH 09/34] Implement printing to file in codegen_backend.print --- compiler/rustc_codegen_llvm/src/lib.rs | 23 ++++++++++--------- .../rustc_codegen_ssa/src/traits/backend.rs | 20 +++++++++++++++- compiler/rustc_codegen_ssa/src/traits/mod.rs | 2 +- compiler/rustc_driver_impl/src/lib.rs | 2 +- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 38a32ac845d2..3ff664136470 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -262,10 +262,10 @@ impl CodegenBackend for LlvmCodegenBackend { |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true) } - fn print(&self, req: &PrintRequest, sess: &Session) { + fn print(&self, req: &PrintRequest, out: &mut dyn PrintBackendInfo, sess: &Session) { match req.kind { PrintKind::RelocationModels => { - println!("Available relocation models:"); + writeln!(out, "Available relocation models:"); for name in &[ "static", "pic", @@ -276,26 +276,27 @@ impl CodegenBackend for LlvmCodegenBackend { "ropi-rwpi", "default", ] { - println!(" {}", name); + writeln!(out, " {}", name); } - println!(); + writeln!(out); } PrintKind::CodeModels => { - println!("Available code models:"); + writeln!(out, "Available code models:"); for name in &["tiny", "small", "kernel", "medium", "large"] { - println!(" {}", name); + writeln!(out, " {}", name); } - println!(); + writeln!(out); } PrintKind::TlsModels => { - println!("Available TLS models:"); + writeln!(out, "Available TLS models:"); for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] { - println!(" {}", name); + writeln!(out, " {}", name); } - println!(); + writeln!(out); } PrintKind::StackProtectorStrategies => { - println!( + writeln!( + out, r#"Available stack protector strategies: all Generate stack canaries in all functions. diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index f10bbbeb97cc..1991b55f1914 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -23,6 +23,8 @@ use rustc_span::symbol::Symbol; use rustc_target::abi::call::FnAbi; use rustc_target::spec::Target; +use std::fmt; + pub trait BackendTypes { type Value: CodegenObject; type Function: CodegenObject; @@ -61,7 +63,7 @@ pub trait CodegenBackend { fn locale_resource(&self) -> &'static str; fn init(&self, _sess: &Session) {} - fn print(&self, _req: &PrintRequest, _sess: &Session) {} + fn print(&self, _req: &PrintRequest, _out: &mut dyn PrintBackendInfo, _sess: &Session) {} fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { vec![] } @@ -162,3 +164,19 @@ pub trait ExtraBackendMethods: std::thread::Builder::new().name(name).spawn(f) } } + +pub trait PrintBackendInfo { + fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>); +} + +impl PrintBackendInfo for String { + fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>) { + fmt::Write::write_fmt(self, args).unwrap(); + } +} + +impl dyn PrintBackendInfo + '_ { + pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) { + self.infallible_write_fmt(args); + } +} diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 8cb58bd4c704..0b69df33d264 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -30,7 +30,7 @@ mod write; pub use self::abi::AbiBuilderMethods; pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; -pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods}; +pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods, PrintBackendInfo}; pub use self::builder::{BuilderMethods, OverflowOp}; pub use self::consts::ConstMethods; pub use self::coverageinfo::CoverageInfoBuilderMethods; diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index a17310206323..9e1d7499a352 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -834,7 +834,7 @@ fn print_crate_info( | TargetCPUs | StackProtectorStrategies | TargetFeatures => { - codegen_backend.print(req, sess); + codegen_backend.print(req, &mut crate_info, sess); } // Any output here interferes with Cargo's parsing of other printed output NativeStaticLibs => {} From 7ea1d4cf4d36623c469aba58a38277ab65cf3009 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 13 Jul 2023 16:54:25 -0700 Subject: [PATCH 10/34] Implement printing to file in llvm_util --- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 25 ++++++++++---------- compiler/rustc_codegen_ssa/src/traits/mod.rs | 4 +++- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 3ff664136470..50cc44bfbb45 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -320,7 +320,7 @@ impl CodegenBackend for LlvmCodegenBackend { "# ); } - _other => llvm_util::print(req, sess), + _other => llvm_util::print(req, out, sess), } } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 84d9acf45de5..844eb58333fc 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -8,6 +8,7 @@ use libc::c_int; use rustc_codegen_ssa::target_features::{ supported_target_features, tied_target_features, RUSTC_SPECIFIC_FEATURES, }; +use rustc_codegen_ssa::traits::PrintBackendInfo; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_fs_util::path_to_c_string; @@ -350,7 +351,7 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> { ret } -fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) { +fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &llvm::TargetMachine) { let mut llvm_target_features = llvm_target_features(tm); let mut known_llvm_target_features = FxHashSet::<&'static str>::default(); let mut rustc_target_features = supported_target_features(sess) @@ -383,24 +384,24 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) { .max() .unwrap_or(0); - println!("Features supported by rustc for this target:"); + writeln!(out, "Features supported by rustc for this target:"); for (feature, desc) in &rustc_target_features { - println!(" {1:0$} - {2}.", max_feature_len, feature, desc); + writeln!(out, " {1:0$} - {2}.", max_feature_len, feature, desc); } - println!("\nCode-generation features supported by LLVM for this target:"); + writeln!(out, "\nCode-generation features supported by LLVM for this target:"); for (feature, desc) in &llvm_target_features { - println!(" {1:0$} - {2}.", max_feature_len, feature, desc); + writeln!(out, " {1:0$} - {2}.", max_feature_len, feature, desc); } if llvm_target_features.is_empty() { - println!(" Target features listing is not supported by this LLVM version."); + writeln!(out, " Target features listing is not supported by this LLVM version."); } - println!("\nUse +feature to enable a feature, or -feature to disable it."); - println!("For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n"); - println!("Code-generation features cannot be used in cfg or #[target_feature],"); - println!("and may be renamed or removed in a future version of LLVM or rustc.\n"); + writeln!(out, "\nUse +feature to enable a feature, or -feature to disable it."); + writeln!(out, "For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n"); + writeln!(out, "Code-generation features cannot be used in cfg or #[target_feature],"); + writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n"); } -pub(crate) fn print(req: &PrintRequest, sess: &Session) { +pub(crate) fn print(req: &PrintRequest, out: &mut dyn PrintBackendInfo, sess: &Session) { require_inited(); let tm = create_informational_target_machine(sess); match req.kind { @@ -412,7 +413,7 @@ pub(crate) fn print(req: &PrintRequest, sess: &Session) { .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e)); unsafe { llvm::LLVMRustPrintTargetCPUs(tm, cpu_cstring.as_ptr()) }; } - PrintKind::TargetFeatures => print_target_features(sess, tm), + PrintKind::TargetFeatures => print_target_features(out, sess, tm), _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), } } diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 0b69df33d264..728c2bc8c49b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -30,7 +30,9 @@ mod write; pub use self::abi::AbiBuilderMethods; pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; -pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods, PrintBackendInfo}; +pub use self::backend::{ + Backend, BackendTypes, CodegenBackend, ExtraBackendMethods, PrintBackendInfo, +}; pub use self::builder::{BuilderMethods, OverflowOp}; pub use self::consts::ConstMethods; pub use self::coverageinfo::CoverageInfoBuilderMethods; From e8cd8c6de9682c5287b2779352e678f72a759932 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 13 Jul 2023 16:56:29 -0700 Subject: [PATCH 11/34] Implement printing to file in PassWrapper --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 7 +++- compiler/rustc_codegen_llvm/src/llvm_util.rs | 18 +++++++++-- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 32 +++++++++++++------ 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 605f0154773a..03b5b45d9a3d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2280,7 +2280,12 @@ extern "C" { pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool; - pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine, cpu: *const c_char); + pub fn LLVMRustPrintTargetCPUs( + T: &TargetMachine, + cpu: *const c_char, + print: unsafe extern "C" fn(out: *mut c_void, string: *const c_char, len: usize), + out: *mut c_void, + ); pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t; pub fn LLVMRustGetTargetFeature( T: &TargetMachine, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 844eb58333fc..8d57f59764fb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -17,8 +17,8 @@ use rustc_session::config::{PrintKind, PrintRequest}; use rustc_session::Session; use rustc_span::symbol::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy}; -use std::ffi::{CStr, CString}; +use std::ffi::{c_char, c_void, CStr, CString}; use std::path::Path; use std::ptr; use std::slice; @@ -401,7 +401,7 @@ fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &ll writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n"); } -pub(crate) fn print(req: &PrintRequest, out: &mut dyn PrintBackendInfo, sess: &Session) { +pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess: &Session) { require_inited(); let tm = create_informational_target_machine(sess); match req.kind { @@ -411,7 +411,19 @@ pub(crate) fn print(req: &PrintRequest, out: &mut dyn PrintBackendInfo, sess: &S // at least as long as the C function let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref())) .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e)); - unsafe { llvm::LLVMRustPrintTargetCPUs(tm, cpu_cstring.as_ptr()) }; + unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) { + let out = &mut *(out as *mut &mut dyn PrintBackendInfo); + let bytes = slice::from_raw_parts(string as *const u8, len); + write!(out, "{}", String::from_utf8_lossy(bytes)); + } + unsafe { + llvm::LLVMRustPrintTargetCPUs( + tm, + cpu_cstring.as_ptr(), + callback, + &mut out as *mut &mut dyn PrintBackendInfo as *mut c_void, + ); + } } PrintKind::TargetFeatures => print_target_features(out, sess, tm), _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index eb3d67e720f2..e5fb6b0953f5 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1,5 +1,6 @@ #include +#include #include #include @@ -306,44 +307,55 @@ static size_t getLongestEntryLength(ArrayRef Table) { return MaxLen; } -extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, const char* TargetCPU) { +using PrintBackendInfo = void(void*, const char* Data, size_t Len); + +extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, + const char* TargetCPU, + PrintBackendInfo Print, + void* Out) { const TargetMachine *Target = unwrap(TM); const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); const Triple::ArchType HostArch = Triple(sys::getDefaultTargetTriple()).getArch(); const Triple::ArchType TargetArch = Target->getTargetTriple().getArch(); + std::ostringstream Buf; + #if LLVM_VERSION_GE(17, 0) const ArrayRef CPUTable = MCInfo->getAllProcessorDescriptions(); #elif defined(LLVM_RUSTLLVM) const ArrayRef CPUTable = MCInfo->getCPUTable(); #else - printf("Full target CPU help is not supported by this LLVM version.\n\n"); + Buf << "Full target CPU help is not supported by this LLVM version.\n\n"; SubtargetSubTypeKV TargetCPUKV = { TargetCPU, {{}}, {{}} }; const ArrayRef CPUTable = TargetCPUKV; #endif unsigned MaxCPULen = getLongestEntryLength(CPUTable); - printf("Available CPUs for this target:\n"); + Buf << "Available CPUs for this target:\n"; // Don't print the "native" entry when the user specifies --target with a // different arch since that could be wrong or misleading. if (HostArch == TargetArch) { MaxCPULen = std::max(MaxCPULen, (unsigned) std::strlen("native")); const StringRef HostCPU = sys::getHostCPUName(); - printf(" %-*s - Select the CPU of the current host (currently %.*s).\n", - MaxCPULen, "native", (int)HostCPU.size(), HostCPU.data()); + Buf << " " << std::left << std::setw(MaxCPULen) << "native" + << " - Select the CPU of the current host " + "(currently " << HostCPU.str() << ").\n"; } for (auto &CPU : CPUTable) { // Compare cpu against current target to label the default if (strcmp(CPU.Key, TargetCPU) == 0) { - printf(" %-*s - This is the default target CPU" - " for the current build target (currently %s).", - MaxCPULen, CPU.Key, Target->getTargetTriple().str().c_str()); + Buf << " " << std::left << std::setw(MaxCPULen) << CPU.Key + << " - This is the default target CPU for the current build target " + "(currently " << Target->getTargetTriple().str() << ")."; } else { - printf(" %-*s", MaxCPULen, CPU.Key); + Buf << " " << CPU.Key; } - printf("\n"); + Buf << "\n"; } + + const auto &BufString = Buf.str(); + Print(Out, BufString.data(), BufString.size()); } extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) { From 8d2167477ac284092cfac05cf39db8bda87c13cf Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 23:08:04 -0700 Subject: [PATCH 12/34] Implement printing to file for link-args and native-static-libs --- compiler/rustc_codegen_ssa/src/back/link.rs | 32 ++++++++++++++------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index bb8a520321a1..ecd58541e992 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -12,7 +12,7 @@ use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME}; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::SymbolExportKind; -use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, Strip}; +use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, OutFileName, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintKind, SplitDwarfKind}; use rustc_session::cstore::DllImport; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; @@ -596,8 +596,10 @@ fn link_staticlib<'a>( all_native_libs.extend_from_slice(&codegen_results.crate_info.used_libraries); - if sess.opts.prints.iter().any(|print| print.kind == PrintKind::NativeStaticLibs) { - print_native_static_libs(sess, &all_native_libs, &all_rust_dylibs); + for print in &sess.opts.prints { + if print.kind == PrintKind::NativeStaticLibs { + print_native_static_libs(sess, &print.out, &all_native_libs, &all_rust_dylibs); + } } Ok(()) @@ -744,8 +746,11 @@ fn link_natively<'a>( cmd.env_remove(k.as_ref()); } - if sess.opts.prints.iter().any(|print| print.kind == PrintKind::LinkArgs) { - println!("{:?}", &cmd); + for print in &sess.opts.prints { + if print.kind == PrintKind::LinkArgs { + let content = format!("{:?}", cmd); + print.out.overwrite(&content, sess); + } } // May have not found libraries in the right formats. @@ -1386,6 +1391,7 @@ enum RlibFlavor { fn print_native_static_libs( sess: &Session, + out: &OutFileName, all_native_libs: &[NativeLib], all_rust_dylibs: &[&Path], ) { @@ -1459,11 +1465,17 @@ fn print_native_static_libs( lib_args.push(format!("-l{}", lib)); } } - if !lib_args.is_empty() { - sess.emit_note(errors::StaticLibraryNativeArtifacts); - // Prefix for greppability - // Note: This must not be translated as tools are allowed to depend on this exact string. - sess.note_without_error(format!("native-static-libs: {}", &lib_args.join(" "))); + + match out { + OutFileName::Real(_) => out.overwrite(&lib_args.join(" "), sess), + OutFileName::Stdout => { + if !lib_args.is_empty() { + sess.emit_note(errors::StaticLibraryNativeArtifacts); + // Prefix for greppability + // Note: This must not be translated as tools are allowed to depend on this exact string. + sess.note_without_error(format!("native-static-libs: {}", &lib_args.join(" "))); + } + } } } From 5d844599bc6f00d24ceffa2351b2c7c55e6b827f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 14 Jul 2023 10:51:54 -0700 Subject: [PATCH 13/34] Add ui test of LLVM print-from-C++ changes --- tests/ui/codegen/target-cpus.rs | 4 ++++ tests/ui/codegen/target-cpus.stdout | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 tests/ui/codegen/target-cpus.rs create mode 100644 tests/ui/codegen/target-cpus.stdout diff --git a/tests/ui/codegen/target-cpus.rs b/tests/ui/codegen/target-cpus.rs new file mode 100644 index 000000000000..1dff3ee6011b --- /dev/null +++ b/tests/ui/codegen/target-cpus.rs @@ -0,0 +1,4 @@ +// needs-llvm-components: webassembly +// min-llvm-version: 17 +// compile-flags: --print=target-cpus --target=wasm32-unknown-unknown +// check-pass diff --git a/tests/ui/codegen/target-cpus.stdout b/tests/ui/codegen/target-cpus.stdout new file mode 100644 index 000000000000..f60ba0f5034b --- /dev/null +++ b/tests/ui/codegen/target-cpus.stdout @@ -0,0 +1,4 @@ +Available CPUs for this target: + bleeding-edge + generic - This is the default target CPU for the current build target (currently wasm32-unknown-unknown). + mvp From 4f5242e82685feaca3cc5d3503eaf0785b2a490f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 23:05:12 -0700 Subject: [PATCH 14/34] Document --print KIND=PATH in Command-line Arguments documentation --- src/doc/rustc/src/command-line-arguments.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 2c7c05c0c4b8..4d32897cc14c 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -260,6 +260,10 @@ The valid types of print values are: This returns rustc's minimum supported deployment target if no `*_DEPLOYMENT_TARGET` variable is present in the environment, or otherwise returns the variable's parsed value. +A filepath may optionally be specified for each requested information kind, in +the format `--print KIND=PATH`, just like for `--emit`. When a path is +specified, information will be written there instead of to stdout. + [conditional compilation]: ../reference/conditional-compilation.html [deployment target]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html From 9e5a67e57f715ec5eda915db1261cdf4c4a04642 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 10 Jul 2023 09:33:34 +0000 Subject: [PATCH 15/34] Permit pre-evaluated constants in simd_shuffle --- .../rustc_codegen_ssa/src/mir/constant.rs | 14 ++++++++++++++ tests/ui/simd/shuffle.rs | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 1c5031dfc4b4..47a166e4e1be 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -67,6 +67,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Result>, ErrorHandled> { let uv = match constant.literal { mir::ConstantKind::Unevaluated(uv, _) => uv.shrink(), + mir::ConstantKind::Ty(c) => match c.kind() { + // A constant that came from a const generic but was then used as an argument to old-style + // simd_shuffle (passing as argument instead of as a generic param). + rustc_type_ir::ConstKind::Value(valtree) => return Ok(Some(valtree)), + other => span_bug!(constant.span, "{other:#?}"), + }, + // We should never encounter `ConstantKind::Val` unless MIR opts (like const prop) evaluate + // a constant and write that value back into `Operand`s. This could happen, but is unlikely. + // Also: all users of `simd_shuffle` are on unstable and already need to take a lot of care + // around intrinsics. For an issue to happen here, it would require a macro expanding to a + // `simd_shuffle` call without wrapping the constant argument in a `const {}` block, but + // the user pass through arbitrary expressions. + // FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a real + // const generic. other => span_bug!(constant.span, "{other:#?}"), }; let uv = self.monomorphize(uv); diff --git a/tests/ui/simd/shuffle.rs b/tests/ui/simd/shuffle.rs index 3592adfdc6ad..de41c9e25ddd 100644 --- a/tests/ui/simd/shuffle.rs +++ b/tests/ui/simd/shuffle.rs @@ -1,14 +1,21 @@ //run-pass #![feature(repr_simd, platform_intrinsics)] +#![allow(incomplete_features)] +#![feature(adt_const_params)] extern "platform-intrinsic" { fn simd_shuffle(a: T, b: T, i: I) -> U; + fn simd_shuffle16(x: T, y: T, idx: [u32; 16]) -> U; } #[derive(Copy, Clone)] #[repr(simd)] struct Simd([T; N]); +pub unsafe fn __shuffle_vector16(x: T, y: T) -> U { + simd_shuffle16(x, y, IDX) +} + fn main() { const I1: [u32; 4] = [0, 2, 4, 6]; const I2: [u32; 2] = [1, 5]; @@ -21,4 +28,16 @@ fn main() { let y: Simd = simd_shuffle(a, b, I2); assert_eq!(y.0, [1, 5]); } + // Test that an indirection (via an unnamed constant) + // through a const generic parameter also works. + // See https://github.com/rust-lang/rust/issues/113500 for details. + let a = Simd::([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + let b = Simd::([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]); + unsafe { + __shuffle_vector16::< + { [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] }, + Simd, + Simd, + >(a, b); + } } From 9b32319205dd207c9bdb501ee353a542fc10674d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 18 Jul 2023 11:18:40 -0300 Subject: [PATCH 16/34] Add Foreign to SMIR --- compiler/rustc_smir/src/rustc_internal/mod.rs | 8 ++++++++ compiler/rustc_smir/src/rustc_smir/mod.rs | 4 +++- compiler/rustc_smir/src/stable_mir/ty.rs | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 527d5220564c..2ac3046ce6d7 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -31,6 +31,10 @@ pub fn adt_def(did: DefId) -> stable_mir::ty::AdtDef { with_tables(|t| t.adt_def(did)) } +pub fn foreign_def(did: DefId) -> stable_mir::ty::ForeignDef { + with_tables(|t| t.foreign_def(did)) +} + impl<'tcx> Tables<'tcx> { pub fn item_def_id(&self, item: &stable_mir::CrateItem) -> DefId { self.def_ids[item.0] @@ -44,6 +48,10 @@ impl<'tcx> Tables<'tcx> { stable_mir::ty::AdtDef(self.create_def_id(did)) } + pub fn foreign_def(&mut self, did: DefId) -> stable_mir::ty::ForeignDef { + stable_mir::ty::ForeignDef(self.create_def_id(did)) + } + fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId { // FIXME: this becomes inefficient when we have too many ids for (i, &d) in self.def_ids.iter().enumerate() { diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 0e5de1e74d32..13bda35d6927 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -113,7 +113,9 @@ impl<'tcx> Tables<'tcx> { .collect(), ), )), - ty::Foreign(_) => todo!(), + ty::Foreign(def_id) => { + TyKind::RigidTy(RigidTy::Foreign(rustc_internal::foreign_def(*def_id))) + } ty::Str => TyKind::RigidTy(RigidTy::Str), ty::Array(ty, constant) => { TyKind::RigidTy(RigidTy::Array(self.intern_ty(*ty), opaque(constant))) diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 7ae07efb729d..162dfe05becd 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -26,6 +26,7 @@ pub enum RigidTy { Uint(UintTy), Float(FloatTy), Adt(AdtDef, AdtSubsts), + Foreign(ForeignDef), Str, Array(Ty, Const), Slice(Ty), @@ -60,6 +61,9 @@ pub enum FloatTy { F64, } +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct ForeignDef(pub(crate) DefId); + #[derive(Clone, PartialEq, Eq, Debug)] pub struct AdtDef(pub(crate) DefId); From caa01adbd061b17e97ada679e87a96da713310fa Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 18 Jul 2023 12:02:35 -0300 Subject: [PATCH 17/34] Add Never to SMIR --- compiler/rustc_smir/src/rustc_smir/mod.rs | 2 +- compiler/rustc_smir/src/stable_mir/ty.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 13bda35d6927..922bbf029387 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -132,7 +132,7 @@ impl<'tcx> Tables<'tcx> { ty::Dynamic(_, _, _) => todo!(), ty::Closure(_, _) => todo!(), ty::Generator(_, _, _) => todo!(), - ty::Never => todo!(), + ty::Never => TyKind::RigidTy(RigidTy::Never), ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple( fields.iter().map(|ty| self.intern_ty(ty)).collect(), )), diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 162dfe05becd..571fd0d74724 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -32,6 +32,7 @@ pub enum RigidTy { Slice(Ty), RawPtr(Ty, Mutability), Ref(Region, Ty, Mutability), + Never, Tuple(Vec), } From 68077d58272901590fb2b1de5dc551a88a1dc36c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 18 Jul 2023 12:11:49 -0300 Subject: [PATCH 18/34] Rename SMIR AdtSubsts to GenericArgs --- compiler/rustc_smir/src/rustc_smir/mod.rs | 8 ++++---- compiler/rustc_smir/src/stable_mir/ty.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 922bbf029387..f624c4dc8ff4 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -8,7 +8,7 @@ //! For now, we are developing everything inside `rustc`, thus, we keep this module private. use crate::rustc_internal::{self, opaque}; -use crate::stable_mir::ty::{AdtSubsts, FloatTy, GenericArgKind, IntTy, RigidTy, TyKind, UintTy}; +use crate::stable_mir::ty::{FloatTy, GenericArgs, GenericArgKind, IntTy, RigidTy, TyKind, UintTy}; use crate::stable_mir::{self, Context}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -94,10 +94,10 @@ impl<'tcx> Tables<'tcx> { ty::FloatTy::F32 => TyKind::RigidTy(RigidTy::Float(FloatTy::F32)), ty::FloatTy::F64 => TyKind::RigidTy(RigidTy::Float(FloatTy::F64)), }, - ty::Adt(adt_def, substs) => TyKind::RigidTy(RigidTy::Adt( + ty::Adt(adt_def, generic_args) => TyKind::RigidTy(RigidTy::Adt( rustc_internal::adt_def(adt_def.did()), - AdtSubsts( - substs + GenericArgs( + generic_args .iter() .map(|arg| match arg.unpack() { ty::GenericArgKind::Lifetime(region) => { diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 571fd0d74724..36b562850e95 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -25,7 +25,7 @@ pub enum RigidTy { Int(IntTy), Uint(UintTy), Float(FloatTy), - Adt(AdtDef, AdtSubsts), + Adt(AdtDef, GenericArgs), Foreign(ForeignDef), Str, Array(Ty, Const), @@ -69,7 +69,7 @@ pub struct ForeignDef(pub(crate) DefId); pub struct AdtDef(pub(crate) DefId); #[derive(Clone, Debug)] -pub struct AdtSubsts(pub Vec); +pub struct GenericArgs(pub Vec); #[derive(Clone, Debug)] pub enum GenericArgKind { From e5c0b96e2408850d6db27a8d69339fa6a6c78455 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 18 Jul 2023 12:16:38 -0300 Subject: [PATCH 19/34] Add FnDef ty to SMIR --- compiler/rustc_smir/src/rustc_internal/mod.rs | 8 +++++++ compiler/rustc_smir/src/rustc_smir/mod.rs | 22 +++++++++++++++++-- compiler/rustc_smir/src/stable_mir/ty.rs | 4 ++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 2ac3046ce6d7..e4f129bc1d6c 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -35,6 +35,10 @@ pub fn foreign_def(did: DefId) -> stable_mir::ty::ForeignDef { with_tables(|t| t.foreign_def(did)) } +pub fn fn_def(did: DefId) -> stable_mir::ty::FnDef { + with_tables(|t| t.fn_def(did)) +} + impl<'tcx> Tables<'tcx> { pub fn item_def_id(&self, item: &stable_mir::CrateItem) -> DefId { self.def_ids[item.0] @@ -52,6 +56,10 @@ impl<'tcx> Tables<'tcx> { stable_mir::ty::ForeignDef(self.create_def_id(did)) } + pub fn fn_def(&mut self, did: DefId) -> stable_mir::ty::FnDef { + stable_mir::ty::FnDef(self.create_def_id(did)) + } + fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId { // FIXME: this becomes inefficient when we have too many ids for (i, &d) in self.def_ids.iter().enumerate() { diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index f624c4dc8ff4..81ca0f985cc7 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -8,7 +8,7 @@ //! For now, we are developing everything inside `rustc`, thus, we keep this module private. use crate::rustc_internal::{self, opaque}; -use crate::stable_mir::ty::{FloatTy, GenericArgs, GenericArgKind, IntTy, RigidTy, TyKind, UintTy}; +use crate::stable_mir::ty::{FloatTy, GenericArgKind, GenericArgs, IntTy, RigidTy, TyKind, UintTy}; use crate::stable_mir::{self, Context}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -127,7 +127,25 @@ impl<'tcx> Tables<'tcx> { ty::Ref(region, ty, mutbl) => { TyKind::RigidTy(RigidTy::Ref(opaque(region), self.intern_ty(*ty), mutbl.stable())) } - ty::FnDef(_, _) => todo!(), + ty::FnDef(def_id, generic_args) => TyKind::RigidTy(RigidTy::FnDef( + rustc_internal::fn_def(*def_id), + GenericArgs( + generic_args + .iter() + .map(|arg| match arg.unpack() { + ty::GenericArgKind::Lifetime(region) => { + GenericArgKind::Lifetime(opaque(®ion)) + } + ty::GenericArgKind::Type(ty) => { + GenericArgKind::Type(self.intern_ty(ty)) + } + ty::GenericArgKind::Const(const_) => { + GenericArgKind::Const(opaque(&const_)) + } + }) + .collect(), + ), + )), ty::FnPtr(_) => todo!(), ty::Dynamic(_, _, _) => todo!(), ty::Closure(_, _) => todo!(), diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 36b562850e95..f3dbde907a03 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -32,6 +32,7 @@ pub enum RigidTy { Slice(Ty), RawPtr(Ty, Mutability), Ref(Region, Ty, Mutability), + FnDef(FnDef, GenericArgs), Never, Tuple(Vec), } @@ -65,6 +66,9 @@ pub enum FloatTy { #[derive(Clone, PartialEq, Eq, Debug)] pub struct ForeignDef(pub(crate) DefId); +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FnDef(pub(crate) DefId); + #[derive(Clone, PartialEq, Eq, Debug)] pub struct AdtDef(pub(crate) DefId); From c5c38cdee80e42c374a0afddeb843851abfd105b Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 18 Jul 2023 12:19:41 -0300 Subject: [PATCH 20/34] Add Closure ty to SMIR --- compiler/rustc_smir/src/rustc_internal/mod.rs | 8 ++++++++ compiler/rustc_smir/src/rustc_smir/mod.rs | 20 ++++++++++++++++++- compiler/rustc_smir/src/stable_mir/ty.rs | 4 ++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index e4f129bc1d6c..d32215186a63 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -39,6 +39,10 @@ pub fn fn_def(did: DefId) -> stable_mir::ty::FnDef { with_tables(|t| t.fn_def(did)) } +pub fn closure_def(did: DefId) -> stable_mir::ty::ClosureDef { + with_tables(|t| t.closure_def(did)) +} + impl<'tcx> Tables<'tcx> { pub fn item_def_id(&self, item: &stable_mir::CrateItem) -> DefId { self.def_ids[item.0] @@ -60,6 +64,10 @@ impl<'tcx> Tables<'tcx> { stable_mir::ty::FnDef(self.create_def_id(did)) } + pub fn closure_def(&mut self, did: DefId) -> stable_mir::ty::ClosureDef { + stable_mir::ty::ClosureDef(self.create_def_id(did)) + } + fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId { // FIXME: this becomes inefficient when we have too many ids for (i, &d) in self.def_ids.iter().enumerate() { diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 81ca0f985cc7..b542cc84f6a7 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -148,7 +148,25 @@ impl<'tcx> Tables<'tcx> { )), ty::FnPtr(_) => todo!(), ty::Dynamic(_, _, _) => todo!(), - ty::Closure(_, _) => todo!(), + ty::Closure(def_id, generic_args) => TyKind::RigidTy(RigidTy::Closure( + rustc_internal::closure_def(*def_id), + GenericArgs( + generic_args + .iter() + .map(|arg| match arg.unpack() { + ty::GenericArgKind::Lifetime(region) => { + GenericArgKind::Lifetime(opaque(®ion)) + } + ty::GenericArgKind::Type(ty) => { + GenericArgKind::Type(self.intern_ty(ty)) + } + ty::GenericArgKind::Const(const_) => { + GenericArgKind::Const(opaque(&const_)) + } + }) + .collect(), + ), + )), ty::Generator(_, _, _) => todo!(), ty::Never => TyKind::RigidTy(RigidTy::Never), ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple( diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index f3dbde907a03..758e0bb7de70 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -33,6 +33,7 @@ pub enum RigidTy { RawPtr(Ty, Mutability), Ref(Region, Ty, Mutability), FnDef(FnDef, GenericArgs), + Closure(ClosureDef, GenericArgs), Never, Tuple(Vec), } @@ -69,6 +70,9 @@ pub struct ForeignDef(pub(crate) DefId); #[derive(Clone, PartialEq, Eq, Debug)] pub struct FnDef(pub(crate) DefId); +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct ClosureDef(pub(crate) DefId); + #[derive(Clone, PartialEq, Eq, Debug)] pub struct AdtDef(pub(crate) DefId); From ed323476891eb948d6c6e6390756f0052c765453 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 18 Jul 2023 13:38:16 -0300 Subject: [PATCH 21/34] Add Generator to SMIR --- compiler/rustc_smir/src/rustc_internal/mod.rs | 8 ++++++ compiler/rustc_smir/src/rustc_smir/mod.rs | 28 +++++++++++++++++-- compiler/rustc_smir/src/stable_mir/ty.rs | 10 +++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index d32215186a63..ccb12c27107e 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -43,6 +43,10 @@ pub fn closure_def(did: DefId) -> stable_mir::ty::ClosureDef { with_tables(|t| t.closure_def(did)) } +pub fn generator_def(did: DefId) -> stable_mir::ty::GeneratorDef { + with_tables(|t| t.generator_def(did)) +} + impl<'tcx> Tables<'tcx> { pub fn item_def_id(&self, item: &stable_mir::CrateItem) -> DefId { self.def_ids[item.0] @@ -68,6 +72,10 @@ impl<'tcx> Tables<'tcx> { stable_mir::ty::ClosureDef(self.create_def_id(did)) } + pub fn generator_def(&mut self, did: DefId) -> stable_mir::ty::GeneratorDef { + stable_mir::ty::GeneratorDef(self.create_def_id(did)) + } + fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId { // FIXME: this becomes inefficient when we have too many ids for (i, &d) in self.def_ids.iter().enumerate() { diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index b542cc84f6a7..8bc7ef325cff 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -8,8 +8,9 @@ //! For now, we are developing everything inside `rustc`, thus, we keep this module private. use crate::rustc_internal::{self, opaque}; -use crate::stable_mir::ty::{FloatTy, GenericArgKind, GenericArgs, IntTy, RigidTy, TyKind, UintTy}; +use crate::stable_mir::ty::{FloatTy, GenericArgKind, GenericArgs, IntTy, Movability, RigidTy, TyKind, UintTy}; use crate::stable_mir::{self, Context}; +use rustc_hir as hir; use rustc_middle::mir; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -167,7 +168,30 @@ impl<'tcx> Tables<'tcx> { .collect(), ), )), - ty::Generator(_, _, _) => todo!(), + ty::Generator(def_id, generic_args, movability) => TyKind::RigidTy(RigidTy::Generator( + rustc_internal::generator_def(*def_id), + GenericArgs( + generic_args + .iter() + .map(|arg| match arg.unpack() { + ty::GenericArgKind::Lifetime(region) => { + GenericArgKind::Lifetime(opaque(®ion)) + } + ty::GenericArgKind::Type(ty) => { + GenericArgKind::Type(self.intern_ty(ty)) + } + ty::GenericArgKind::Const(const_) => { + GenericArgKind::Const(opaque(&const_)) + } + }) + .collect(), + ), + match movability { + hir::Movability::Static => Movability::Static, + hir::Movability::Movable => Movability::Movable, + + } + )), ty::Never => TyKind::RigidTy(RigidTy::Never), ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple( fields.iter().map(|ty| self.intern_ty(ty)).collect(), diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 758e0bb7de70..1ccb30343ed8 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -34,6 +34,7 @@ pub enum RigidTy { Ref(Region, Ty, Mutability), FnDef(FnDef, GenericArgs), Closure(ClosureDef, GenericArgs), + Generator(GeneratorDef, GenericArgs, Movability), Never, Tuple(Vec), } @@ -64,6 +65,12 @@ pub enum FloatTy { F64, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Movability { + Static, + Movable, +} + #[derive(Clone, PartialEq, Eq, Debug)] pub struct ForeignDef(pub(crate) DefId); @@ -73,6 +80,9 @@ pub struct FnDef(pub(crate) DefId); #[derive(Clone, PartialEq, Eq, Debug)] pub struct ClosureDef(pub(crate) DefId); +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct GeneratorDef(pub(crate) DefId); + #[derive(Clone, PartialEq, Eq, Debug)] pub struct AdtDef(pub(crate) DefId); From db35f1de2f7e4a23e6401ee7e2a3335c29d33519 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 19 Jul 2023 11:01:58 -0300 Subject: [PATCH 22/34] Extract generic_args function --- compiler/rustc_smir/src/rustc_smir/mod.rs | 93 +++++++---------------- 1 file changed, 26 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 8bc7ef325cff..f512a98f41a4 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -8,7 +8,9 @@ //! For now, we are developing everything inside `rustc`, thus, we keep this module private. use crate::rustc_internal::{self, opaque}; -use crate::stable_mir::ty::{FloatTy, GenericArgKind, GenericArgs, IntTy, Movability, RigidTy, TyKind, UintTy}; +use crate::stable_mir::ty::{ + FloatTy, GenericArgKind, GenericArgs, IntTy, Movability, RigidTy, TyKind, UintTy, +}; use crate::stable_mir::{self, Context}; use rustc_hir as hir; use rustc_middle::mir; @@ -97,22 +99,7 @@ impl<'tcx> Tables<'tcx> { }, ty::Adt(adt_def, generic_args) => TyKind::RigidTy(RigidTy::Adt( rustc_internal::adt_def(adt_def.did()), - GenericArgs( - generic_args - .iter() - .map(|arg| match arg.unpack() { - ty::GenericArgKind::Lifetime(region) => { - GenericArgKind::Lifetime(opaque(®ion)) - } - ty::GenericArgKind::Type(ty) => { - GenericArgKind::Type(self.intern_ty(ty)) - } - ty::GenericArgKind::Const(const_) => { - GenericArgKind::Const(opaque(&const_)) - } - }) - .collect(), - ), + self.generic_args(generic_args), )), ty::Foreign(def_id) => { TyKind::RigidTy(RigidTy::Foreign(rustc_internal::foreign_def(*def_id))) @@ -130,67 +117,21 @@ impl<'tcx> Tables<'tcx> { } ty::FnDef(def_id, generic_args) => TyKind::RigidTy(RigidTy::FnDef( rustc_internal::fn_def(*def_id), - GenericArgs( - generic_args - .iter() - .map(|arg| match arg.unpack() { - ty::GenericArgKind::Lifetime(region) => { - GenericArgKind::Lifetime(opaque(®ion)) - } - ty::GenericArgKind::Type(ty) => { - GenericArgKind::Type(self.intern_ty(ty)) - } - ty::GenericArgKind::Const(const_) => { - GenericArgKind::Const(opaque(&const_)) - } - }) - .collect(), - ), + self.generic_args(generic_args), )), ty::FnPtr(_) => todo!(), ty::Dynamic(_, _, _) => todo!(), ty::Closure(def_id, generic_args) => TyKind::RigidTy(RigidTy::Closure( rustc_internal::closure_def(*def_id), - GenericArgs( - generic_args - .iter() - .map(|arg| match arg.unpack() { - ty::GenericArgKind::Lifetime(region) => { - GenericArgKind::Lifetime(opaque(®ion)) - } - ty::GenericArgKind::Type(ty) => { - GenericArgKind::Type(self.intern_ty(ty)) - } - ty::GenericArgKind::Const(const_) => { - GenericArgKind::Const(opaque(&const_)) - } - }) - .collect(), - ), + self.generic_args(generic_args), )), ty::Generator(def_id, generic_args, movability) => TyKind::RigidTy(RigidTy::Generator( rustc_internal::generator_def(*def_id), - GenericArgs( - generic_args - .iter() - .map(|arg| match arg.unpack() { - ty::GenericArgKind::Lifetime(region) => { - GenericArgKind::Lifetime(opaque(®ion)) - } - ty::GenericArgKind::Type(ty) => { - GenericArgKind::Type(self.intern_ty(ty)) - } - ty::GenericArgKind::Const(const_) => { - GenericArgKind::Const(opaque(&const_)) - } - }) - .collect(), - ), + self.generic_args(generic_args), match movability { hir::Movability::Static => Movability::Static, hir::Movability::Movable => Movability::Movable, - - } + }, )), ty::Never => TyKind::RigidTy(RigidTy::Never), ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple( @@ -217,6 +158,24 @@ impl<'tcx> Tables<'tcx> { self.types.push(ty); stable_mir::ty::Ty(id) } + + fn generic_args( + &mut self, + generic_args: &ty::GenericArgs<'tcx>, + ) -> stable_mir::ty::GenericArgs { + GenericArgs( + generic_args + .iter() + .map(|arg| match arg.unpack() { + ty::GenericArgKind::Lifetime(region) => { + GenericArgKind::Lifetime(opaque(®ion)) + } + ty::GenericArgKind::Type(ty) => GenericArgKind::Type(self.intern_ty(ty)), + ty::GenericArgKind::Const(const_) => GenericArgKind::Const(opaque(&const_)), + }) + .collect(), + ) + } } /// Build a stable mir crate from a given crate number. From c5819b2b9b51a6be498c11ceadae00ffbed8946d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 19 Jul 2023 11:03:39 -0300 Subject: [PATCH 23/34] Remove FIXMEs a lot of things need fixes --- compiler/rustc_smir/src/stable_mir/ty.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 1ccb30343ed8..ba120be04b2f 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -91,9 +91,7 @@ pub struct GenericArgs(pub Vec); #[derive(Clone, Debug)] pub enum GenericArgKind { - // FIXME add proper region Lifetime(Region), Type(Ty), - // FIXME add proper const Const(Const), } From 705e3e3cb2070829abbb1f6f35493640d20ec683 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jul 2023 15:13:40 -0700 Subject: [PATCH 24/34] Add note about writing native-static-libs to file --- compiler/rustc_codegen_ssa/messages.ftl | 2 ++ compiler/rustc_codegen_ssa/src/back/link.rs | 7 ++++++- compiler/rustc_codegen_ssa/src/errors.rs | 6 ++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index f73080182bfc..b6c70c622497 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -197,6 +197,8 @@ codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libr codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms. +codegen_ssa_static_library_native_artifacts_to_file = Native artifacts to link against have been written to {$path}. The order and any duplication can be significant on some platforms. + codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` failed: {$status} .note = {$output} diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ecd58541e992..eefa4ac34dde 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1467,7 +1467,12 @@ fn print_native_static_libs( } match out { - OutFileName::Real(_) => out.overwrite(&lib_args.join(" "), sess), + OutFileName::Real(path) => { + out.overwrite(&lib_args.join(" "), sess); + if !lib_args.is_empty() { + sess.emit_note(errors::StaticLibraryNativeArtifactsToFile { path }); + } + } OutFileName::Stdout => { if !lib_args.is_empty() { sess.emit_note(errors::StaticLibraryNativeArtifacts); diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 056b4abd2353..c72d37be7481 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -455,6 +455,12 @@ pub struct LinkerFileStem; #[diag(codegen_ssa_static_library_native_artifacts)] pub struct StaticLibraryNativeArtifacts; +#[derive(Diagnostic)] +#[diag(codegen_ssa_static_library_native_artifacts_to_file)] +pub struct StaticLibraryNativeArtifactsToFile<'a> { + pub path: &'a Path, +} + #[derive(Diagnostic)] #[diag(codegen_ssa_link_script_unavailable)] pub struct LinkScriptUnavailable; From 4d5134fb9f1f3bc4ded5ac7522cdba0bed5054eb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jul 2023 15:15:46 -0700 Subject: [PATCH 25/34] Create separate match arms for FileNames and CrateNames This introduces a bit of code duplication, but we don't have the build_output_filenames in the CrateName arm and this seems a little cleaner overall. --- compiler/rustc_driver_impl/src/lib.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9e1d7499a352..f2286fef370a 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -771,24 +771,28 @@ fn print_crate_info( } println_info!("{}", serde_json::to_string_pretty(&targets).unwrap()); } - FileNames | CrateName => { + FileNames => { let Some(attrs) = attrs.as_ref() else { // no crate attributes, print out an error and exit return Compilation::Continue; }; let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); let id = rustc_session::output::find_crate_name(sess, attrs); - if req.kind == CrateName { - println_info!("{id}"); - } else { - let crate_types = collect_crate_types(sess, attrs); - for &style in &crate_types { - let fname = - rustc_session::output::filename_for_input(sess, style, id, &t_outputs); - println_info!("{}", fname.as_path().file_name().unwrap().to_string_lossy()); - } + let crate_types = collect_crate_types(sess, attrs); + for &style in &crate_types { + let fname = + rustc_session::output::filename_for_input(sess, style, id, &t_outputs); + println_info!("{}", fname.as_path().file_name().unwrap().to_string_lossy()); } } + CrateName => { + let Some(attrs) = attrs.as_ref() else { + // no crate attributes, print out an error and exit + return Compilation::Continue; + }; + let id = rustc_session::output::find_crate_name(sess, attrs); + println_info!("{id}"); + } Cfg => { let mut cfgs = sess .parse_sess From 2009b4a5cc1d097188da4396f423a076ac6282a1 Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Thu, 20 Jul 2023 17:46:32 +0900 Subject: [PATCH 26/34] Remove adjustments that used to be necessary for search's crate selector appearance (padding) to look identical on Firefox. New versions of Firefox appear to have changed behavior to agree with Chrome. --- src/librustdoc/html/static/css/rustdoc.css | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 94e778406f8b..b1de8c1529e7 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -776,7 +776,6 @@ table, } #crate-search { min-width: 115px; - /* keep these two in sync with "@-moz-document url-prefix()" below */ padding: 0 23px 0 4px; /* prevents the s */ -@-moz-document url-prefix() { - #crate-search { - padding-left: 0px; /* == 4px - 4px */ - padding-right: 19px; /* == 23px - 4px */ - } -} /* pseudo-element for holding the dropdown-arrow image; needs to be a separate thing so that we can apply CSS-filters to change the arrow color in themes */ #crate-search-div::after { From c7428d50520446ccd44ca89bbbf4ff7a4725570e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 20 Jul 2023 08:53:09 +0000 Subject: [PATCH 27/34] Monomorphize constants before inspecting them --- compiler/rustc_codegen_ssa/src/mir/constant.rs | 2 +- tests/ui/simd/shuffle.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 47a166e4e1be..babcf9bee249 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -65,7 +65,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, constant: &mir::Constant<'tcx>, ) -> Result>, ErrorHandled> { - let uv = match constant.literal { + let uv = match self.monomorphize(constant.literal) { mir::ConstantKind::Unevaluated(uv, _) => uv.shrink(), mir::ConstantKind::Ty(c) => match c.kind() { // A constant that came from a const generic but was then used as an argument to old-style diff --git a/tests/ui/simd/shuffle.rs b/tests/ui/simd/shuffle.rs index de41c9e25ddd..461243d48928 100644 --- a/tests/ui/simd/shuffle.rs +++ b/tests/ui/simd/shuffle.rs @@ -1,4 +1,7 @@ -//run-pass +// run-pass +// revisions: opt noopt +//[noopt] compile-flags: -Copt-level=0 +//[opt] compile-flags: -O #![feature(repr_simd, platform_intrinsics)] #![allow(incomplete_features)] #![feature(adt_const_params)] From fdaec57a28ab6a8cd60fd7a2842d366a9b452a2e Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 18 Jul 2023 17:03:22 +0200 Subject: [PATCH 28/34] XSimplifiedType to SimplifiedType::X --- .../src/coherence/orphan.rs | 10 +- compiler/rustc_middle/src/ty/fast_reject.rs | 112 +++++++++--------- .../src/solve/trait_goals.rs | 2 +- src/librustdoc/clean/inline.rs | 4 +- src/librustdoc/clean/types.rs | 51 ++++---- .../src/utils/internal_lints/invalid_paths.rs | 8 +- src/tools/clippy/clippy_utils/src/lib.rs | 47 ++++---- 7 files changed, 116 insertions(+), 118 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 05c78f570881..21ffbefcd081 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -568,10 +568,10 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: impl<'tcx> TypeVisitor> for DisableAutoTraitVisitor<'tcx> { type BreakTy = (); - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { let tcx = self.tcx; - if t != self.self_ty_root { - for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) { + if ty != self.self_ty_root { + for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, ty) { match tcx.impl_polarity(impl_def_id) { ImplPolarity::Negative => return ControlFlow::Break(()), ImplPolarity::Reservation => {} @@ -584,7 +584,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: } } - match t.kind() { + match ty.kind() { ty::Adt(def, args) if def.is_phantom_data() => args.visit_with(self), ty::Adt(def, args) => { // @lcnr: This is the only place where cycles can happen. We avoid this @@ -599,7 +599,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: ControlFlow::Continue(()) } - _ => t.super_visit_with(self), + _ => ty.super_visit_with(self), } } } diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index e86ff4d26aaa..deb4dcf1f760 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -6,35 +6,33 @@ use std::fmt::Debug; use std::hash::Hash; use std::iter; -use self::SimplifiedType::*; - /// See `simplify_type`. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] pub enum SimplifiedType { - BoolSimplifiedType, - CharSimplifiedType, - IntSimplifiedType(ty::IntTy), - UintSimplifiedType(ty::UintTy), - FloatSimplifiedType(ty::FloatTy), - AdtSimplifiedType(DefId), - ForeignSimplifiedType(DefId), - StrSimplifiedType, - ArraySimplifiedType, - SliceSimplifiedType, - RefSimplifiedType(Mutability), - PtrSimplifiedType(Mutability), - NeverSimplifiedType, - TupleSimplifiedType(usize), + Bool, + Char, + Int(ty::IntTy), + Uint(ty::UintTy), + Float(ty::FloatTy), + Adt(DefId), + Foreign(DefId), + Str, + Array, + Slice, + Ref(Mutability), + Ptr(Mutability), + Never, + Tuple(usize), /// A trait object, all of whose components are markers /// (e.g., `dyn Send + Sync`). - MarkerTraitObjectSimplifiedType, - TraitSimplifiedType(DefId), - ClosureSimplifiedType(DefId), - GeneratorSimplifiedType(DefId), - GeneratorWitnessSimplifiedType(usize), - GeneratorWitnessMIRSimplifiedType(DefId), - FunctionSimplifiedType(usize), - PlaceholderSimplifiedType, + MarkerTraitObject, + Trait(DefId), + Closure(DefId), + Generator(DefId), + GeneratorWitness(usize), + GeneratorWitnessMIR(DefId), + Function(usize), + Placeholder, } /// Generic parameters are pretty much just bound variables, e.g. @@ -110,34 +108,36 @@ pub fn simplify_type<'tcx>( treat_params: TreatParams, ) -> Option { match *ty.kind() { - ty::Bool => Some(BoolSimplifiedType), - ty::Char => Some(CharSimplifiedType), - ty::Int(int_type) => Some(IntSimplifiedType(int_type)), - ty::Uint(uint_type) => Some(UintSimplifiedType(uint_type)), - ty::Float(float_type) => Some(FloatSimplifiedType(float_type)), - ty::Adt(def, _) => Some(AdtSimplifiedType(def.did())), - ty::Str => Some(StrSimplifiedType), - ty::Array(..) => Some(ArraySimplifiedType), - ty::Slice(..) => Some(SliceSimplifiedType), - ty::RawPtr(ptr) => Some(PtrSimplifiedType(ptr.mutbl)), + ty::Bool => Some(SimplifiedType::Bool), + ty::Char => Some(SimplifiedType::Char), + ty::Int(int_type) => Some(SimplifiedType::Int(int_type)), + ty::Uint(uint_type) => Some(SimplifiedType::Uint(uint_type)), + ty::Float(float_type) => Some(SimplifiedType::Float(float_type)), + ty::Adt(def, _) => Some(SimplifiedType::Adt(def.did())), + ty::Str => Some(SimplifiedType::Str), + ty::Array(..) => Some(SimplifiedType::Array), + ty::Slice(..) => Some(SimplifiedType::Slice), + ty::RawPtr(ptr) => Some(SimplifiedType::Ptr(ptr.mutbl)), ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() { Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => { - Some(TraitSimplifiedType(principal_def_id)) + Some(SimplifiedType::Trait(principal_def_id)) } - _ => Some(MarkerTraitObjectSimplifiedType), + _ => Some(SimplifiedType::MarkerTraitObject), }, - ty::Ref(_, _, mutbl) => Some(RefSimplifiedType(mutbl)), - ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)), - ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)), - ty::GeneratorWitness(tys) => Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len())), - ty::GeneratorWitnessMIR(def_id, _) => Some(GeneratorWitnessMIRSimplifiedType(def_id)), - ty::Never => Some(NeverSimplifiedType), - ty::Tuple(tys) => Some(TupleSimplifiedType(tys.len())), - ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())), - ty::Placeholder(..) => Some(PlaceholderSimplifiedType), + ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)), + ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(SimplifiedType::Closure(def_id)), + ty::Generator(def_id, _, _) => Some(SimplifiedType::Generator(def_id)), + ty::GeneratorWitness(tys) => { + Some(SimplifiedType::GeneratorWitness(tys.skip_binder().len())) + } + ty::GeneratorWitnessMIR(def_id, _) => Some(SimplifiedType::GeneratorWitnessMIR(def_id)), + ty::Never => Some(SimplifiedType::Never), + ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())), + ty::FnPtr(f) => Some(SimplifiedType::Function(f.skip_binder().inputs().len())), + ty::Placeholder(..) => Some(SimplifiedType::Placeholder), ty::Param(_) => match treat_params { TreatParams::ForLookup | TreatParams::NextSolverLookup => { - Some(PlaceholderSimplifiedType) + Some(SimplifiedType::Placeholder) } TreatParams::AsCandidateKey => None, }, @@ -147,11 +147,13 @@ pub fn simplify_type<'tcx>( // // We will have to be careful with lazy normalization here. // FIXME(lazy_normalization): This is probably not right... - TreatParams::ForLookup if !ty.has_non_region_infer() => Some(PlaceholderSimplifiedType), - TreatParams::NextSolverLookup => Some(PlaceholderSimplifiedType), + TreatParams::ForLookup if !ty.has_non_region_infer() => { + Some(SimplifiedType::Placeholder) + } + TreatParams::NextSolverLookup => Some(SimplifiedType::Placeholder), TreatParams::ForLookup | TreatParams::AsCandidateKey => None, }, - ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)), + ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)), ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None, } } @@ -159,12 +161,12 @@ pub fn simplify_type<'tcx>( impl SimplifiedType { pub fn def(self) -> Option { match self { - AdtSimplifiedType(d) - | ForeignSimplifiedType(d) - | TraitSimplifiedType(d) - | ClosureSimplifiedType(d) - | GeneratorSimplifiedType(d) - | GeneratorWitnessMIRSimplifiedType(d) => Some(d), + SimplifiedType::Adt(d) + | SimplifiedType::Foreign(d) + | SimplifiedType::Trait(d) + | SimplifiedType::Closure(d) + | SimplifiedType::Generator(d) + | SimplifiedType::GeneratorWitnessMIR(d) => Some(d), _ => None, } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index e7867eead159..29889614620d 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -686,7 +686,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Tuple(_) | ty::Adt(_, _) // FIXME: Handling opaques here is kinda sus. Especially because we - // simplify them to PlaceholderSimplifiedType. + // simplify them to SimplifiedType::Placeholder. | ty::Alias(ty::Opaque, _) => { let mut disqualifying_impl = None; self.tcx().for_each_relevant_impl_treating_projections( diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 5e2e2d249500..cfd9875e1c8f 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -12,6 +12,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId}; use rustc_hir::Mutability; use rustc_metadata::creader::{CStore, LoadedMacro}; +use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; @@ -314,9 +315,8 @@ pub(crate) fn build_impls( // * https://github.com/rust-lang/rust/pull/99917 — where the feature got used // * https://github.com/rust-lang/rust/issues/53487 — overall tracking issue for Error if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) { - use rustc_middle::ty::fast_reject::SimplifiedType::*; let type_ = - if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) }; + if tcx.is_trait(did) { SimplifiedType::Trait(did) } else { SimplifiedType::Adt(did) }; for &did in tcx.incoherent_impls(type_) { build_impl(cx, did, attrs, ret); } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index cfe62407fd35..ddef165a0547 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1776,7 +1776,6 @@ impl PrimitiveType { } pub(crate) fn simplified_types() -> &'static SimplifiedTypes { - use ty::fast_reject::SimplifiedType::*; use ty::{FloatTy, IntTy, UintTy}; use PrimitiveType::*; static CELL: OnceCell = OnceCell::new(); @@ -1784,38 +1783,38 @@ impl PrimitiveType { let single = |x| iter::once(x).collect(); CELL.get_or_init(move || { map! { - Isize => single(IntSimplifiedType(IntTy::Isize)), - I8 => single(IntSimplifiedType(IntTy::I8)), - I16 => single(IntSimplifiedType(IntTy::I16)), - I32 => single(IntSimplifiedType(IntTy::I32)), - I64 => single(IntSimplifiedType(IntTy::I64)), - I128 => single(IntSimplifiedType(IntTy::I128)), - Usize => single(UintSimplifiedType(UintTy::Usize)), - U8 => single(UintSimplifiedType(UintTy::U8)), - U16 => single(UintSimplifiedType(UintTy::U16)), - U32 => single(UintSimplifiedType(UintTy::U32)), - U64 => single(UintSimplifiedType(UintTy::U64)), - U128 => single(UintSimplifiedType(UintTy::U128)), - F32 => single(FloatSimplifiedType(FloatTy::F32)), - F64 => single(FloatSimplifiedType(FloatTy::F64)), - Str => single(StrSimplifiedType), - Bool => single(BoolSimplifiedType), - Char => single(CharSimplifiedType), - Array => single(ArraySimplifiedType), - Slice => single(SliceSimplifiedType), + Isize => single(SimplifiedType::Int(IntTy::Isize)), + I8 => single(SimplifiedType::Int(IntTy::I8)), + I16 => single(SimplifiedType::Int(IntTy::I16)), + I32 => single(SimplifiedType::Int(IntTy::I32)), + I64 => single(SimplifiedType::Int(IntTy::I64)), + I128 => single(SimplifiedType::Int(IntTy::I128)), + Usize => single(SimplifiedType::Uint(UintTy::Usize)), + U8 => single(SimplifiedType::Uint(UintTy::U8)), + U16 => single(SimplifiedType::Uint(UintTy::U16)), + U32 => single(SimplifiedType::Uint(UintTy::U32)), + U64 => single(SimplifiedType::Uint(UintTy::U64)), + U128 => single(SimplifiedType::Uint(UintTy::U128)), + F32 => single(SimplifiedType::Float(FloatTy::F32)), + F64 => single(SimplifiedType::Float(FloatTy::F64)), + Str => single(SimplifiedType::Str), + Bool => single(SimplifiedType::Bool), + Char => single(SimplifiedType::Char), + Array => single(SimplifiedType::Array), + Slice => single(SimplifiedType::Slice), // FIXME: If we ever add an inherent impl for tuples // with different lengths, they won't show in rustdoc. // // Either manually update this arrayvec at this point // or start with a more complex refactoring. - Tuple => [TupleSimplifiedType(1), TupleSimplifiedType(2), TupleSimplifiedType(3)].into(), - Unit => single(TupleSimplifiedType(0)), - RawPointer => [PtrSimplifiedType(Mutability::Not), PtrSimplifiedType(Mutability::Mut)].into_iter().collect(), - Reference => [RefSimplifiedType(Mutability::Not), RefSimplifiedType(Mutability::Mut)].into_iter().collect(), + Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(), + Unit => single(SimplifiedType::Tuple(0)), + RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(), + Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(), // FIXME: This will be wrong if we ever add inherent impls // for function pointers. - Fn => single(FunctionSimplifiedType(1)), - Never => single(NeverSimplifiedType), + Fn => single(SimplifiedType::Function(1)), + Never => single(SimplifiedType::Never), } }) } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 94b56304bcab..e4906944c8d0 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -74,10 +74,10 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { let lang_items = cx.tcx.lang_items(); // This list isn't complete, but good enough for our current list of paths. let incoherent_impls = [ - SimplifiedType::FloatSimplifiedType(FloatTy::F32), - SimplifiedType::FloatSimplifiedType(FloatTy::F64), - SimplifiedType::SliceSimplifiedType, - SimplifiedType::StrSimplifiedType, + SimplifiedType::Float(FloatTy::F32), + SimplifiedType::Float(FloatTy::F64), + SimplifiedType::Slice, + SimplifiedType::Str, ] .iter() .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied()); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 00e893fbdda8..035511e89125 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -100,10 +100,7 @@ use rustc_middle::mir::ConstantKind; use rustc_middle::ty as rustc_ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; -use rustc_middle::ty::fast_reject::SimplifiedType::{ - ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType, - PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType, -}; +use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ BorrowKind, ClosureKind, FloatTy, IntTy, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UintTy, UpvarCapture, @@ -512,30 +509,30 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx> fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { let ty = match name { - "bool" => BoolSimplifiedType, - "char" => CharSimplifiedType, - "str" => StrSimplifiedType, - "array" => ArraySimplifiedType, - "slice" => SliceSimplifiedType, + "bool" => SimplifiedType::Bool, + "char" => SimplifiedType::Char, + "str" => SimplifiedType::Str, + "array" => SimplifiedType::Array, + "slice" => SimplifiedType::Slice, // FIXME: rustdoc documents these two using just `pointer`. // // Maybe this is something we should do here too. - "const_ptr" => PtrSimplifiedType(Mutability::Not), - "mut_ptr" => PtrSimplifiedType(Mutability::Mut), - "isize" => IntSimplifiedType(IntTy::Isize), - "i8" => IntSimplifiedType(IntTy::I8), - "i16" => IntSimplifiedType(IntTy::I16), - "i32" => IntSimplifiedType(IntTy::I32), - "i64" => IntSimplifiedType(IntTy::I64), - "i128" => IntSimplifiedType(IntTy::I128), - "usize" => UintSimplifiedType(UintTy::Usize), - "u8" => UintSimplifiedType(UintTy::U8), - "u16" => UintSimplifiedType(UintTy::U16), - "u32" => UintSimplifiedType(UintTy::U32), - "u64" => UintSimplifiedType(UintTy::U64), - "u128" => UintSimplifiedType(UintTy::U128), - "f32" => FloatSimplifiedType(FloatTy::F32), - "f64" => FloatSimplifiedType(FloatTy::F64), + "const_ptr" => SimplifiedType::Ptr(Mutability::Not), + "mut_ptr" => SimplifiedType::Ptr(Mutability::Mut), + "isize" => SimplifiedType::Int(IntTy::Isize), + "i8" => SimplifiedType::Int(IntTy::I8), + "i16" => SimplifiedType::Int(IntTy::I16), + "i32" => SimplifiedType::Int(IntTy::I32), + "i64" => SimplifiedType::Int(IntTy::I64), + "i128" => SimplifiedType::Int(IntTy::I128), + "usize" => SimplifiedType::Uint(UintTy::Usize), + "u8" => SimplifiedType::Uint(UintTy::U8), + "u16" => SimplifiedType::Uint(UintTy::U16), + "u32" => SimplifiedType::Uint(UintTy::U32), + "u64" => SimplifiedType::Uint(UintTy::U64), + "u128" => SimplifiedType::Uint(UintTy::U128), + "f32" => SimplifiedType::Float(FloatTy::F32), + "f64" => SimplifiedType::Float(FloatTy::F64), _ => return [].iter().copied(), }; From 2d99f40ec5ee10df8f7325e4e71d8249f8dacd92 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 18 Jul 2023 18:07:42 +0200 Subject: [PATCH 29/34] assembly: only consider blanket impls once --- .../src/solve/assembly/mod.rs | 273 +++++++++++++----- .../src/solve/project_goals.rs | 12 +- .../src/solve/trait_goals.rs | 9 +- ...mble-normalizing-self-ty-impl-ambiguity.rs | 25 ++ ...-normalizing-self-ty-impl-ambiguity.stderr | 23 ++ 5 files changed, 274 insertions(+), 68 deletions(-) create mode 100644 tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs create mode 100644 tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 1e7989988955..73cf15ff94b5 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -10,9 +10,11 @@ use rustc_infer::traits::util::elaborate; use rustc_infer::traits::Reveal; use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult}; -use rustc_middle::ty::fast_reject::TreatProjections; -use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams}; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{fast_reject, TypeFoldable}; +use rustc_span::ErrorGuaranteed; use std::fmt::Debug; pub(super) mod structural_traits; @@ -109,10 +111,10 @@ pub(super) trait GoalKind<'tcx>: fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId; - // Try equating an assumption predicate against a goal's predicate. If it - // holds, then execute the `then` callback, which should do any additional - // work, then produce a response (typically by executing - // [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). + /// Try equating an assumption predicate against a goal's predicate. If it + /// holds, then execute the `then` callback, which should do any additional + /// work, then produce a response (typically by executing + /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -120,9 +122,9 @@ pub(super) trait GoalKind<'tcx>: then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx>; - // Consider a clause, which consists of a "assumption" and some "requirements", - // to satisfy a goal. If the requirements hold, then attempt to satisfy our - // goal by equating it with the assumption. + /// Consider a clause, which consists of a "assumption" and some "requirements", + /// to satisfy a goal. If the requirements hold, then attempt to satisfy our + /// goal by equating it with the assumption. fn consider_implied_clause( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -149,9 +151,9 @@ pub(super) trait GoalKind<'tcx>: }) } - // Consider a clause specifically for a `dyn Trait` self type. This requires - // additionally checking all of the supertraits and object bounds to hold, - // since they're not implied by the well-formedness of the object type. + /// Consider a clause specifically for a `dyn Trait` self type. This requires + /// additionally checking all of the supertraits and object bounds to hold, + /// since they're not implied by the well-formedness of the object type. fn consider_object_bound_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -182,96 +184,106 @@ pub(super) trait GoalKind<'tcx>: impl_def_id: DefId, ) -> QueryResult<'tcx>; - // A type implements an `auto trait` if its components do as well. These components - // are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`]. + /// If the predicate contained an error, we want to avoid emitting unnecessary trait errors but + /// still want to emit errors for other trait goals. We have some special handling for this case. + /// + /// Trait goals always hold while projection goals never do. This is a bit arbitrary but prevents + /// incorrect normalization while hiding any trait errors. + fn consider_error_guaranteed_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + guar: ErrorGuaranteed, + ) -> QueryResult<'tcx>; + + /// A type implements an `auto trait` if its components do as well. These components + /// are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`]. fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // A trait alias holds if the RHS traits and `where` clauses hold. + /// A trait alias holds if the RHS traits and `where` clauses hold. fn consider_trait_alias_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // A type is `Copy` or `Clone` if its components are `Sized`. These components - // are given by built-in rules from [`instantiate_constituent_tys_for_sized_trait`]. + /// A type is `Copy` or `Clone` if its components are `Sized`. These components + /// are given by built-in rules from [`instantiate_constituent_tys_for_sized_trait`]. fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. These - // components are given by built-in rules from [`instantiate_constituent_tys_for_copy_clone_trait`]. + /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. These + /// components are given by built-in rules from [`instantiate_constituent_tys_for_copy_clone_trait`]. fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // A type is `PointerLike` if we can compute its layout, and that layout - // matches the layout of `usize`. + /// A type is `PointerLike` if we can compute its layout, and that layout + /// matches the layout of `usize`. fn consider_builtin_pointer_like_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // A type is a `FnPtr` if it is of `FnPtr` type. + /// A type is a `FnPtr` if it is of `FnPtr` type. fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn` - // family of traits where `A` is given by the signature of the type. + /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn` + /// family of traits where `A` is given by the signature of the type. fn consider_builtin_fn_trait_candidates( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, kind: ty::ClosureKind, ) -> QueryResult<'tcx>; - // `Tuple` is implemented if the `Self` type is a tuple. + /// `Tuple` is implemented if the `Self` type is a tuple. fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // `Pointee` is always implemented. - // - // See the projection implementation for the `Metadata` types for all of - // the built-in types. For structs, the metadata type is given by the struct - // tail. + /// `Pointee` is always implemented. + /// + /// See the projection implementation for the `Metadata` types for all of + /// the built-in types. For structs, the metadata type is given by the struct + /// tail. fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // A generator (that comes from an `async` desugaring) is known to implement - // `Future`, where `O` is given by the generator's return type - // that was computed during type-checking. + /// A generator (that comes from an `async` desugaring) is known to implement + /// `Future`, where `O` is given by the generator's return type + /// that was computed during type-checking. fn consider_builtin_future_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // A generator (that doesn't come from an `async` desugaring) is known to - // implement `Generator`, given the resume, yield, - // and return types of the generator computed during type-checking. + /// A generator (that doesn't come from an `async` desugaring) is known to + /// implement `Generator`, given the resume, yield, + /// and return types of the generator computed during type-checking. fn consider_builtin_generator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // The most common forms of unsizing are array to slice, and concrete (Sized) - // type into a `dyn Trait`. ADTs and Tuples can also have their final field - // unsized if it's generic. + /// The most common forms of unsizing are array to slice, and concrete (Sized) + /// type into a `dyn Trait`. ADTs and Tuples can also have their final field + /// unsized if it's generic. fn consider_builtin_unsize_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - // `dyn Trait1` can be unsized to `dyn Trait2` if they are the same trait, or - // if `Trait2` is a (transitive) supertrait of `Trait2`. + /// `dyn Trait1` can be unsized to `dyn Trait2` if they are the same trait, or + /// if `Trait2` is a (transitive) supertrait of `Trait2`. fn consider_builtin_dyn_upcast_candidates( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -299,35 +311,60 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, ) -> Vec> { debug_assert_eq!(goal, self.resolve_vars_if_possible(goal)); + if let Some(ambig) = self.self_ty_infer_ambiguity_hack(goal) { + return ambig; + } + + let mut candidates = self.assemble_candidates_via_self_ty(goal); + + self.assemble_blanket_impl_candidates(goal, &mut candidates); + + self.assemble_param_env_candidates(goal, &mut candidates); - // HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule, - // object bound, alias bound, etc. We are unable to determine this until we can at - // least structurally resolve the type one layer. - if goal.predicate.self_ty().is_ty_var() { - return vec![Candidate { + candidates + } + + fn self_ty_infer_ambiguity_hack>( + &mut self, + goal: Goal<'tcx, G>, + ) -> Option>> { + goal.predicate.self_ty().is_ty_var().then(|| { + vec![Candidate { source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity), result: self .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) .unwrap(), - }]; + }] + }) + } + + /// Assemble candidates which apply to the self type. This only looks at candidate which + /// apply to the specific self type and ignores all others. + /// + /// Returns `None` if the self type is still ambiguous. + fn assemble_candidates_via_self_ty>( + &mut self, + goal: Goal<'tcx, G>, + ) -> Vec> { + debug_assert_eq!(goal, self.resolve_vars_if_possible(goal)); + if let Some(ambig) = self.self_ty_infer_ambiguity_hack(goal) { + return ambig; } let mut candidates = Vec::new(); - self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates); - - self.assemble_impl_candidates(goal, &mut candidates); + self.assemble_non_blanket_impl_candidates(goal, &mut candidates); self.assemble_builtin_impl_candidates(goal, &mut candidates); - self.assemble_param_env_candidates(goal, &mut candidates); - self.assemble_alias_bound_candidates(goal, &mut candidates); self.assemble_object_bound_candidates(goal, &mut candidates); self.assemble_coherence_unknowable_candidates(goal, &mut candidates); + self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates); + candidates } @@ -385,7 +422,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // have a `Normalized` candidate. This doesn't work as long as we // use `CandidateSource` in winnowing. let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - Ok(ecx.assemble_and_evaluate_candidates(goal)) + Ok(ecx.assemble_candidates_via_self_ty(goal)) }, ) }); @@ -396,22 +433,125 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } #[instrument(level = "debug", skip_all)] - fn assemble_impl_candidates>( + fn assemble_non_blanket_impl_candidates>( &mut self, goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { let tcx = self.tcx(); - tcx.for_each_relevant_impl_treating_projections( - goal.predicate.trait_def_id(tcx), - goal.predicate.self_ty(), - TreatProjections::NextSolverLookup, - |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) { + let self_ty = goal.predicate.self_ty(); + let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); + let mut consider_impls_for_simplified_type = |simp| { + if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) { + for &impl_def_id in impls_for_type { + match G::consider_impl_candidate(self, goal, impl_def_id) { + Ok(result) => candidates + .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }), + Err(NoSolution) => (), + } + } + } + }; + + match self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::Generator(_, _, _) + | ty::Never + | ty::Tuple(_) => { + let simp = + fast_reject::simplify_type(tcx, self_ty, TreatParams::ForLookup).unwrap(); + consider_impls_for_simplified_type(simp); + } + + // HACK: For integer and float variables we have to manually look at all impls + // which have some integer or float as a self type. + ty::Infer(ty::IntVar(_)) => { + use ty::IntTy::*; + use ty::UintTy::*; + // This causes a compiler error if any new integer kinds are added. + let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy; + let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy; + let possible_integers = [ + // signed integers + SimplifiedType::Int(I8), + SimplifiedType::Int(I16), + SimplifiedType::Int(I32), + SimplifiedType::Int(I64), + SimplifiedType::Int(I128), + SimplifiedType::Int(Isize), + // unsigned integers + SimplifiedType::Uint(U8), + SimplifiedType::Uint(U16), + SimplifiedType::Uint(U32), + SimplifiedType::Uint(U64), + SimplifiedType::Uint(U128), + SimplifiedType::Uint(Usize), + ]; + for simp in possible_integers { + consider_impls_for_simplified_type(simp); + } + } + + ty::Infer(ty::FloatVar(_)) => { + // This causes a compiler error if any new float kinds are added. + let (ty::FloatTy::F32 | ty::FloatTy::F64); + let possible_floats = [ + SimplifiedType::Float(ty::FloatTy::F32), + SimplifiedType::Float(ty::FloatTy::F64), + ]; + + for simp in possible_floats { + consider_impls_for_simplified_type(simp); + } + } + + // The only traits applying to aliases and placeholders are blanket impls. + // + // Impls which apply to an alias after normalization are handled by + // `assemble_candidates_after_normalizing_self_ty`. + ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (), + + // FIXME: These should ideally not exist as a self type. It would be nice for + // the builtin auto trait impls of generators should instead directly recurse + // into the witness. + ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(_, _) => (), + + // These variants should not exist as a self type. + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) + | ty::Param(_) + | ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"), + } + } + + fn assemble_blanket_impl_candidates>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + let tcx = self.tcx(); + let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); + for &impl_def_id in trait_impls.blanket_impls() { + match G::consider_impl_candidate(self, goal, impl_def_id) { Ok(result) => candidates .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }), Err(NoSolution) => (), - }, - ); + } + } } #[instrument(level = "debug", skip_all)] @@ -420,8 +560,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - let lang_items = self.tcx().lang_items(); - let trait_def_id = goal.predicate.trait_def_id(self.tcx()); + let tcx = self.tcx(); + let lang_items = tcx.lang_items(); + let trait_def_id = goal.predicate.trait_def_id(tcx); // N.B. When assembling built-in candidates for lang items that are also // `auto` traits, then the auto trait candidate that is assembled in @@ -430,9 +571,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // Instead of adding the logic here, it's a better idea to add it in // `EvalCtxt::disqualify_auto_trait_candidate_due_to_possible_impl` in // `solve::trait_goals` instead. - let result = if self.tcx().trait_is_auto(trait_def_id) { + let result = if let Err(guar) = goal.predicate.error_reported() { + G::consider_error_guaranteed_candidate(self, guar) + } else if tcx.trait_is_auto(trait_def_id) { G::consider_auto_trait_candidate(self, goal) - } else if self.tcx().trait_is_alias(trait_def_id) { + } else if tcx.trait_is_alias(trait_def_id) { G::consider_trait_alias_candidate(self, goal) } else if lang_items.sized_trait() == Some(trait_def_id) { G::consider_builtin_sized_candidate(self, goal) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index d677fbdc7f42..222ed9939ba2 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -2,7 +2,6 @@ use crate::traits::specialization_graph; use super::assembly::{self, structural_traits}; use super::EvalCtxt; -use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; @@ -15,7 +14,7 @@ use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::ProjectionPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; -use rustc_span::{sym, DUMMY_SP}; +use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self), ret)] @@ -246,6 +245,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { }) } + /// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error` + /// and succeed. Can experiment with this to figure out what results in better error messages. + fn consider_error_guaranteed_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + _guar: ErrorGuaranteed, + ) -> QueryResult<'tcx> { + Err(NoSolution) + } + fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 29889614620d..930e62d63883 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -11,7 +11,7 @@ use rustc_middle::traits::Reveal; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; -use rustc_span::DUMMY_SP; +use rustc_span::{ErrorGuaranteed, DUMMY_SP}; impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn self_ty(self) -> Ty<'tcx> { @@ -78,6 +78,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }) } + fn consider_error_guaranteed_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + _guar: ErrorGuaranteed, + ) -> QueryResult<'tcx> { + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs new file mode 100644 index 000000000000..727ce84ba359 --- /dev/null +++ b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs @@ -0,0 +1,25 @@ +// compile-flags: -Ztrait-solver=next + +// Checks that we do not get ambiguity by considering an impl +// multiple times if we're able to normalize the self type. +trait Trait<'a> {} + +impl<'a, T: 'a> Trait<'a> for T {} + +fn impls_trait<'a, T: Trait<'a>>() {} + +trait Id { + type Assoc; +} +impl Id for T { + type Assoc = T; +} + +fn call() { + impls_trait::<::Assoc>(); +} + +fn main() { + call::<()>(); + impls_trait::<<<() as Id>::Assoc as Id>::Assoc>(); +} diff --git a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr new file mode 100644 index 000000000000..91b635b35eb6 --- /dev/null +++ b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr @@ -0,0 +1,23 @@ +error[E0283]: type annotations needed: cannot satisfy `::Assoc: Trait<'_>` + --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:19:5 + | +LL | impls_trait::<::Assoc>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: cannot satisfy `::Assoc: Trait<'_>` +note: required by a bound in `impls_trait` + --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:9:23 + | +LL | fn impls_trait<'a, T: Trait<'a>>() {} + | ^^^^^^^^^ required by this bound in `impls_trait` + +error[E0282]: type annotations needed + --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:24:5 + | +LL | impls_trait::<<<() as Id>::Assoc as Id>::Assoc>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_trait` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0282, E0283. +For more information about an error, try `rustc --explain E0282`. From aa28b77b5a362a70e4c1e4f99047f903f735954d Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 18 Jul 2023 18:15:14 +0200 Subject: [PATCH 30/34] add FIXME --- compiler/rustc_middle/src/ty/fast_reject.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index deb4dcf1f760..668aa4521c10 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -62,6 +62,9 @@ pub enum TreatParams { /// correct mode for *lookup*, as during candidate selection. /// /// N.B. during deep rejection, this acts identically to `ForLookup`. + /// + /// FIXME(-Ztrait-solver=next): Remove this variant and cleanup + /// the code. NextSolverLookup, } From 7c97a76b76120bd982762a982d4254ece32c43dc Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 18 Jul 2023 18:18:32 +0200 Subject: [PATCH 31/34] re-add comment --- compiler/rustc_trait_selection/src/solve/assembly/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 73cf15ff94b5..68e931aac8c1 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -324,6 +324,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates } + /// HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule, + /// object bound, alias bound, etc. We are unable to determine this until we can at + /// least structurally resolve the type one layer. + /// + /// It would also require us to consider all impls of the trait, which is both pretty + /// bad for perf and would also constrain the self type if there is just a single impl. fn self_ty_infer_ambiguity_hack>( &mut self, goal: Goal<'tcx, G>, From 7de9b654b7888ee387a9907f7a5f9b824ca053be Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 17 Jul 2023 17:42:59 +0000 Subject: [PATCH 32/34] Avoid another gha group nesting --- src/bootstrap/test.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 44b8c2d8c013..c69b21488d23 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -2087,10 +2087,11 @@ impl Step for ErrorIndex { let mut tool = tool::ErrorIndex::command(builder); tool.arg("markdown").arg(&output); - let _guard = + let guard = builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host); let _time = util::timeit(&builder); builder.run_quiet(&mut tool); + drop(guard); // The tests themselves need to link to std, so make sure it is // available. builder.ensure(compile::Std::new(compiler, compiler.host)); From 2062f2ca8261b521caa9c34c195bf472dcb59e98 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 20 Jul 2023 10:40:59 +0200 Subject: [PATCH 33/34] review --- .../src/solve/assembly/mod.rs | 8 +++---- ...mble-normalizing-self-ty-impl-ambiguity.rs | 2 ++ ...-normalizing-self-ty-impl-ambiguity.stderr | 23 ------------------- .../dont-normalize-proj-with-error.rs | 22 ++++++++++++++++++ .../dont-normalize-proj-with-error.stderr | 9 ++++++++ 5 files changed, 37 insertions(+), 27 deletions(-) delete mode 100644 tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr create mode 100644 tests/ui/traits/new-solver/dont-normalize-proj-with-error.rs create mode 100644 tests/ui/traits/new-solver/dont-normalize-proj-with-error.stderr diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 68e931aac8c1..b661ff481a0a 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -311,7 +311,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, ) -> Vec> { debug_assert_eq!(goal, self.resolve_vars_if_possible(goal)); - if let Some(ambig) = self.self_ty_infer_ambiguity_hack(goal) { + if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) { return ambig; } @@ -324,13 +324,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates } - /// HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule, + /// `?0: Trait` is ambiguous, because it may be satisfied via a builtin rule, /// object bound, alias bound, etc. We are unable to determine this until we can at /// least structurally resolve the type one layer. /// /// It would also require us to consider all impls of the trait, which is both pretty /// bad for perf and would also constrain the self type if there is just a single impl. - fn self_ty_infer_ambiguity_hack>( + fn assemble_self_ty_infer_ambiguity_response>( &mut self, goal: Goal<'tcx, G>, ) -> Option>> { @@ -353,7 +353,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, ) -> Vec> { debug_assert_eq!(goal, self.resolve_vars_if_possible(goal)); - if let Some(ambig) = self.self_ty_infer_ambiguity_hack(goal) { + if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) { return ambig; } diff --git a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs index 727ce84ba359..826e8c1e0b13 100644 --- a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs +++ b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs @@ -1,7 +1,9 @@ // compile-flags: -Ztrait-solver=next +// check-pass // Checks that we do not get ambiguity by considering an impl // multiple times if we're able to normalize the self type. + trait Trait<'a> {} impl<'a, T: 'a> Trait<'a> for T {} diff --git a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr deleted file mode 100644 index 91b635b35eb6..000000000000 --- a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0283]: type annotations needed: cannot satisfy `::Assoc: Trait<'_>` - --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:19:5 - | -LL | impls_trait::<::Assoc>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: cannot satisfy `::Assoc: Trait<'_>` -note: required by a bound in `impls_trait` - --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:9:23 - | -LL | fn impls_trait<'a, T: Trait<'a>>() {} - | ^^^^^^^^^ required by this bound in `impls_trait` - -error[E0282]: type annotations needed - --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:24:5 - | -LL | impls_trait::<<<() as Id>::Assoc as Id>::Assoc>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_trait` - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0282, E0283. -For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/new-solver/dont-normalize-proj-with-error.rs b/tests/ui/traits/new-solver/dont-normalize-proj-with-error.rs new file mode 100644 index 000000000000..19a6fa990ff1 --- /dev/null +++ b/tests/ui/traits/new-solver/dont-normalize-proj-with-error.rs @@ -0,0 +1,22 @@ +// compile-flags: -Ztrait-solver=next + +// Test that we don't incorrectly leak unconstrained inference variables +// if the projection contained an error. This caused an ICE in writeback. + +trait Mirror { + type Assoc: ?Sized; +} + +struct Wrapper(T); +impl Mirror for Wrapper { + type Assoc = T; +} + +fn mirror(_: W) -> Box { todo!() } + +fn type_error() -> TypeError { todo!() } +//~^ ERROR cannot find type `TypeError` in this scope + +fn main() { + let x = mirror(type_error()); +} diff --git a/tests/ui/traits/new-solver/dont-normalize-proj-with-error.stderr b/tests/ui/traits/new-solver/dont-normalize-proj-with-error.stderr new file mode 100644 index 000000000000..5a7459ec1fde --- /dev/null +++ b/tests/ui/traits/new-solver/dont-normalize-proj-with-error.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `TypeError` in this scope + --> $DIR/dont-normalize-proj-with-error.rs:17:20 + | +LL | fn type_error() -> TypeError { todo!() } + | ^^^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. From 5c75bc5317b4326bdc3d8a4708d0602bd0ec219d Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 20 Jul 2023 11:26:22 +0200 Subject: [PATCH 34/34] update doc comments --- .../src/solve/assembly/mod.rs | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index b661ff481a0a..6920e790e71a 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -184,18 +184,21 @@ pub(super) trait GoalKind<'tcx>: impl_def_id: DefId, ) -> QueryResult<'tcx>; - /// If the predicate contained an error, we want to avoid emitting unnecessary trait errors but - /// still want to emit errors for other trait goals. We have some special handling for this case. + /// If the predicate contained an error, we want to avoid emitting unnecessary trait + /// errors but still want to emit errors for other trait goals. We have some special + /// handling for this case. /// - /// Trait goals always hold while projection goals never do. This is a bit arbitrary but prevents - /// incorrect normalization while hiding any trait errors. + /// Trait goals always hold while projection goals never do. This is a bit arbitrary + /// but prevents incorrect normalization while hiding any trait errors. fn consider_error_guaranteed_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, guar: ErrorGuaranteed, ) -> QueryResult<'tcx>; - /// A type implements an `auto trait` if its components do as well. These components - /// are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`]. + /// A type implements an `auto trait` if its components do as well. + /// + /// These components are given by built-in rules from + /// [`structural_traits::instantiate_constituent_tys_for_auto_trait`]. fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -207,15 +210,19 @@ pub(super) trait GoalKind<'tcx>: goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - /// A type is `Copy` or `Clone` if its components are `Sized`. These components - /// are given by built-in rules from [`instantiate_constituent_tys_for_sized_trait`]. + /// A type is `Copy` or `Clone` if its components are `Sized`. + /// + /// These components are given by built-in rules from + /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`]. fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. These - /// components are given by built-in rules from [`instantiate_constituent_tys_for_copy_clone_trait`]. + /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. + /// + /// These components are given by built-in rules from + /// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`]. fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>,