From 11dcd1d3d7e805a555a41992312137700ee370a1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 24 Apr 2023 17:57:41 -0700 Subject: [PATCH 01/14] 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 126f5768c90f2..6b153e5b54edd 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 wasm32-unknown-unknown --print target-cpus=$(TMPDIR)/target-cpus.txt + $(CGREP) generic < $(TMPDIR)/target-cpus.txt + ifdef IS_WINDOWS default: $(RUSTC) --print cfg | $(CGREP) windows From c0dc0c6875e1907f1a8d690bae800c9d0c89b4f1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 17:20:28 -0700 Subject: [PATCH 02/14] 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 24ba28bbc82c2..38a32ac845d26 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 03be0654b50bb..84d9acf45de57 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 0dfb41f42f0dc..bb8a520321a11 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 b3c9ecf8b938b..f10bbbeb97cc2 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 25c043149e81c..27dfb6c3bca60 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 593983f117d03..261d3529b141e 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 f72bdb150180f3fb9ccd6447f13e9e37b3e33e79 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 17:58:46 -0700 Subject: [PATCH 03/14] 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 261d3529b141e..738625485c494 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 32cac2e0024aa4d02661859f9bfc69d33e6e8ba9 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 19:06:04 -0700 Subject: [PATCH 04/14] 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 738625485c494..ee871dc8005cf 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 f2e3d3fc63ea238385aecbb77f633fd451b9470a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 22:13:08 -0700 Subject: [PATCH 05/14] 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 22b4ec6b0d1b1..f8e25e0080086 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 24a5f4030b88d..222c7b5d6a72a 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 638b368f70214..8e5347eba96cc 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 4897bd8d5daec..ee24c6d902fa5 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 ee871dc8005cf..a8147ede970c3 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 4a3e668da111a..dd15ad45145f1 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 11cd3866fa869..15bcc277e6491 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 5a60660ff8c35e2f270658900073443bbb984180 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 22:29:05 -0700 Subject: [PATCH 06/14] 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 27dfb6c3bca60..a173102063234 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 c80cbe4baedfe1ef8ea6f88f3cf2f8db06c8c399 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 22:33:38 -0700 Subject: [PATCH 07/14] 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 38a32ac845d26..3ff6641364709 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 f10bbbeb97cc2..1991b55f19141 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 8cb58bd4c704d..0b69df33d2645 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 a173102063234..9e1d7499a3524 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 6e734fce633fa5de1140f8e5d1dc981c40be1f92 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 13 Jul 2023 16:54:25 -0700 Subject: [PATCH 08/14] 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 3ff6641364709..50cc44bfbb450 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 84d9acf45de57..844eb58333fc4 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 0b69df33d2645..728c2bc8c49bc 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 815a114974debd5b9c6a19a8d94f96b675a27347 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 13 Jul 2023 16:56:29 -0700 Subject: [PATCH 09/14] 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 605f0154773a7..03b5b45d9a3db 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 844eb58333fc4..8d57f59764fbd 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 eb3d67e720f2d..e5fb6b0953f5a 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 dcfe94a009369734c9c84930f42afc1f6d17998d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 23:08:04 -0700 Subject: [PATCH 10/14] 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 bb8a520321a11..ecd58541e992e 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 7ee059b8ac986f5c127063870336e934f898530e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 14 Jul 2023 10:51:54 -0700 Subject: [PATCH 11/14] 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 0000000000000..1dff3ee6011bf --- /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 0000000000000..f60ba0f5034ba --- /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 5ca0946ac0ae7c75feb3474039c7fb9a5348601d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 16 Jul 2023 23:05:12 -0700 Subject: [PATCH 12/14] 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 2c7c05c0c4b88..4d32897cc14c7 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 26fd6b15b058df4b53fd95109a92316a74e7e94a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jul 2023 15:13:40 -0700 Subject: [PATCH 13/14] 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 f73080182bfcd..b6c70c6224977 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 ecd58541e992e..eefa4ac34dde2 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 056b4abd23533..c72d37be74815 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 11ae0afc931b00f921818eb99dd894768558bdcf Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jul 2023 15:15:46 -0700 Subject: [PATCH 14/14] 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 9e1d7499a3524..f2286fef370a6 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