diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index a6ecfa4520608..0a96e60d4d3af 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -196,6 +196,54 @@ impl<'a> PostExpansionVisitor<'a> { "thiscall-unwind ABI is experimental and subject to change" ); } + "cdecl-unwind" => { + gate_feature_post!( + &self, + c_unwind, + span, + "cdecl-unwind ABI is experimental and subject to change" + ); + } + "fastcall-unwind" => { + gate_feature_post!( + &self, + c_unwind, + span, + "fastcall-unwind ABI is experimental and subject to change" + ); + } + "vectorcall-unwind" => { + gate_feature_post!( + &self, + c_unwind, + span, + "vectorcall-unwind ABI is experimental and subject to change" + ); + } + "aapcs-unwind" => { + gate_feature_post!( + &self, + c_unwind, + span, + "aapcs-unwind ABI is experimental and subject to change" + ); + } + "win64-unwind" => { + gate_feature_post!( + &self, + c_unwind, + span, + "win64-unwind ABI is experimental and subject to change" + ); + } + "sysv64-unwind" => { + gate_feature_post!( + &self, + c_unwind, + span, + "sysv64-unwind ABI is experimental and subject to change" + ); + } "wasm" => { gate_feature_post!( &self, diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index 26d600cefc7c0..d567c8dae43a4 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -132,6 +132,7 @@ //! methods called `Printer::scan_*`, and the 'PRINT' process is the //! method called `Printer::print`. +mod convenience; mod ring; use ring::RingBuffer; @@ -186,12 +187,6 @@ pub enum Token { End, } -impl Token { - pub fn is_hardbreak_tok(&self) -> bool { - matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY })) - } -} - #[derive(Copy, Clone)] enum PrintFrame { Fits, @@ -441,73 +436,4 @@ impl Printer { self.out.push_str(string); self.space -= string.len() as isize; } - - // Convenience functions to talk to the printer. - - /// "raw box" - pub fn rbox(&mut self, indent: usize, breaks: Breaks) { - self.scan_begin(BeginToken { - indent: IndentStyle::Block { offset: indent as isize }, - breaks, - }) - } - - /// Inconsistent breaking box - pub fn ibox(&mut self, indent: usize) { - self.rbox(indent, Breaks::Inconsistent) - } - - /// Consistent breaking box - pub fn cbox(&mut self, indent: usize) { - self.rbox(indent, Breaks::Consistent) - } - - pub fn visual_align(&mut self) { - self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent }); - } - - pub fn break_offset(&mut self, n: usize, off: isize) { - self.scan_break(BreakToken { offset: off, blank_space: n as isize }) - } - - pub fn end(&mut self) { - self.scan_end() - } - - pub fn eof(mut self) -> String { - self.scan_eof(); - self.out - } - - pub fn word>>(&mut self, wrd: S) { - let string = wrd.into(); - self.scan_string(string) - } - - fn spaces(&mut self, n: usize) { - self.break_offset(n, 0) - } - - pub fn zerobreak(&mut self) { - self.spaces(0) - } - - pub fn space(&mut self) { - self.spaces(1) - } - - pub fn hardbreak(&mut self) { - self.spaces(SIZE_INFINITY as usize) - } - - pub fn is_beginning_of_line(&self) -> bool { - match self.last_token() { - Some(last_token) => last_token.is_hardbreak_tok(), - None => true, - } - } - - pub fn hardbreak_tok_offset(off: isize) -> Token { - Token::Break(BreakToken { offset: off, blank_space: SIZE_INFINITY }) - } } diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs new file mode 100644 index 0000000000000..1b9ac705883af --- /dev/null +++ b/compiler/rustc_ast_pretty/src/pp/convenience.rs @@ -0,0 +1,77 @@ +use crate::pp::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, Token, SIZE_INFINITY}; +use std::borrow::Cow; + +impl Printer { + /// "raw box" + pub fn rbox(&mut self, indent: usize, breaks: Breaks) { + self.scan_begin(BeginToken { + indent: IndentStyle::Block { offset: indent as isize }, + breaks, + }) + } + + /// Inconsistent breaking box + pub fn ibox(&mut self, indent: usize) { + self.rbox(indent, Breaks::Inconsistent) + } + + /// Consistent breaking box + pub fn cbox(&mut self, indent: usize) { + self.rbox(indent, Breaks::Consistent) + } + + pub fn visual_align(&mut self) { + self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent }); + } + + pub fn break_offset(&mut self, n: usize, off: isize) { + self.scan_break(BreakToken { offset: off, blank_space: n as isize }) + } + + pub fn end(&mut self) { + self.scan_end() + } + + pub fn eof(mut self) -> String { + self.scan_eof(); + self.out + } + + pub fn word>>(&mut self, wrd: S) { + let string = wrd.into(); + self.scan_string(string) + } + + fn spaces(&mut self, n: usize) { + self.break_offset(n, 0) + } + + pub fn zerobreak(&mut self) { + self.spaces(0) + } + + pub fn space(&mut self) { + self.spaces(1) + } + + pub fn hardbreak(&mut self) { + self.spaces(SIZE_INFINITY as usize) + } + + pub fn is_beginning_of_line(&self) -> bool { + match self.last_token() { + Some(last_token) => last_token.is_hardbreak_tok(), + None => true, + } + } + + pub fn hardbreak_tok_offset(off: isize) -> Token { + Token::Break(BreakToken { offset: off, blank_space: SIZE_INFINITY }) + } +} + +impl Token { + pub fn is_hardbreak_tok(&self) -> bool { + matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY })) + } +} diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 3014d2f1930ee..58f391692c49c 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -39,7 +39,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { // LLVM 12. let version = coverageinfo::mapping_version(); if version < 4 { - tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 12 or higher."); + tcx.sess.fatal("rustc option `-C instrument-coverage` requires LLVM 12 or higher."); } debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name()); @@ -274,7 +274,7 @@ fn save_function_record( /// (functions referenced by other "used" or public items). Any other functions considered unused, /// or "Unreachable", were still parsed and processed through the MIR stage, but were not /// codegenned. (Note that `-Clink-dead-code` can force some unused code to be codegenned, but -/// that flag is known to cause other errors, when combined with `-Z instrument-coverage`; and +/// that flag is known to cause other errors, when combined with `-C instrument-coverage`; and /// `-Clink-dead-code` will not generate code for unused generic functions.) /// /// We can find the unused functions (including generic functions) by the set difference of all MIR diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs index cbf570dba4c3e..e77201cf0c800 100644 --- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs @@ -22,7 +22,7 @@ pub trait CoverageInfoMethods<'tcx>: BackendTypes { pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { /// Returns true if the function source hash was added to the coverage map (even if it had - /// already been added, for this instance). Returns false *only* if `-Z instrument-coverage` is + /// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is /// not enabled (a coverage map is not being generated). fn set_function_source_hash( &mut self, @@ -30,7 +30,7 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { function_source_hash: u64, ) -> bool; - /// Returns true if the counter was added to the coverage map; false if `-Z instrument-coverage` + /// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage` /// is not enabled (a coverage map is not being generated). fn add_coverage_counter( &mut self, @@ -40,7 +40,7 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { ) -> bool; /// Returns true if the expression was added to the coverage map; false if - /// `-Z instrument-coverage` is not enabled (a coverage map is not being generated). + /// `-C instrument-coverage` is not enabled (a coverage map is not being generated). fn add_coverage_counter_expression( &mut self, instance: Instance<'tcx>, @@ -51,7 +51,7 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { region: Option, ) -> bool; - /// Returns true if the region was added to the coverage map; false if `-Z instrument-coverage` + /// Returns true if the region was added to the coverage map; false if `-C instrument-coverage` /// is not enabled (a coverage map is not being generated). fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool; } diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 87298023980ed..89a0f8245e5fb 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -156,9 +156,37 @@ impl<'tcx> ConstEvalErr<'tcx> { } // Add spans for the stacktrace. Don't print a single-line backtrace though. if self.stacktrace.len() > 1 { + // Helper closure to print duplicated lines. + let mut flush_last_line = |last_frame, times| { + if let Some((line, span)) = last_frame { + err.span_label(span, &line); + // Don't print [... additional calls ...] if the number of lines is small + if times < 3 { + for _ in 0..times { + err.span_label(span, &line); + } + } else { + err.span_label( + span, + format!("[... {} additional calls {} ...]", times, &line), + ); + } + } + }; + + let mut last_frame = None; + let mut times = 0; for frame_info in &self.stacktrace { - err.span_label(frame_info.span, frame_info.to_string()); + let frame = (frame_info.to_string(), frame_info.span); + if last_frame.as_ref() == Some(&frame) { + times += 1; + } else { + flush_last_line(last_frame, times); + last_frame = Some(frame); + times = 0; + } } + flush_last_line(last_frame, times); } // Let the caller finish the job. emit(err) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 0f490c3310245..acf221a08eeb2 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -66,7 +66,7 @@ pub const EXIT_FAILURE: i32 = 1; const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\ ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md"; -const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["Z", "C", "crate-type"]; +const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"]; const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename"]; @@ -1100,31 +1100,31 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec Option<(Vec, bool)> { - let args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).collect::>(); + let mut args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).peekable(); - // Avoid printing help because of empty args. This can suggest the compiler - // itself is not the program root (consider RLS). - if args.len() < 2 { - return None; - } - - let matches = handle_options(&args)?; let mut result = Vec::new(); let mut excluded_cargo_defaults = false; - for flag in ICE_REPORT_COMPILER_FLAGS { - let prefix = if flag.len() == 1 { "-" } else { "--" }; - - for content in &matches.opt_strs(flag) { - // Split always returns the first element - let name = if let Some(first) = content.split('=').next() { first } else { &content }; - - let content = - if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { name } else { content }; - - if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&name) { - result.push(format!("{}{} {}", prefix, flag, content)); + while let Some(arg) = args.next() { + if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) { + let content = if arg.len() == a.len() { + match args.next() { + Some(arg) => arg.to_string(), + None => continue, + } + } else if arg.get(a.len()..a.len() + 1) == Some("=") { + arg[a.len() + 1..].to_string() } else { + arg[a.len()..].to_string() + }; + if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| content.starts_with(exc)) { excluded_cargo_defaults = true; + } else { + result.push(a.to_string()); + match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| content.starts_with(*s)) + { + Some(s) => result.push(s.to_string()), + None => result.push(content), + } } } } @@ -1240,6 +1240,15 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { /// /// A custom rustc driver can skip calling this to set up a custom ICE hook. pub fn install_ice_hook() { + // If the user has not explicitly overriden "RUST_BACKTRACE", then produce + // full backtraces. When a compiler ICE happens, we want to gather + // as much information as possible to present in the issue opened + // by the user. Compiler developers and other rustc users can + // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE" + // (e.g. `RUST_BACKTRACE=1`) + if std::env::var("RUST_BACKTRACE").is_err() { + std::env::set_var("RUST_BACKTRACE", "full"); + } SyncLazy::force(&DEFAULT_HOOK); } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 44acbd3cf2159..5e28818775635 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -575,6 +575,7 @@ fn test_codegen_options_tracking_hash() { tracked!(force_frame_pointers, Some(false)); tracked!(force_unwind_tables, Some(true)); tracked!(inline_threshold, Some(0xf007ba11)); + tracked!(instrument_coverage, Some(InstrumentCoverage::All)); tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto); tracked!(link_dead_code, Some(true)); tracked!(llvm_args, vec![String::from("1"), String::from("2")]); diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 13cd8e4a046b0..88292a4422419 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -404,11 +404,13 @@ impl Collector<'_> { fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport { let calling_convention = if self.tcx.sess.target.arch == "x86" { match abi { - Abi::C { .. } | Abi::Cdecl => DllCallingConvention::C, + Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C, Abi::Stdcall { .. } | Abi::System { .. } => { DllCallingConvention::Stdcall(self.i686_arg_list_size(item)) } - Abi::Fastcall => DllCallingConvention::Fastcall(self.i686_arg_list_size(item)), + Abi::Fastcall { .. } => { + DllCallingConvention::Fastcall(self.i686_arg_list_size(item)) + } // Vectorcall is intentionally not supported at this time. _ => { self.tcx.sess.span_fatal( @@ -419,7 +421,7 @@ impl Collector<'_> { } } else { match abi { - Abi::C { .. } | Abi::Win64 | Abi::System { .. } => DllCallingConvention::C, + Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C, _ => { self.tcx.sess.span_fatal( item.span, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e9e6d61331077..33fb1e570b1c0 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1577,7 +1577,7 @@ pub enum StatementKind<'tcx> { /// - `Bivariant` -- no effect AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), - /// Marks the start of a "coverage region", injected with '-Zinstrument-coverage'. A + /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A /// `Coverage` statement carries metadata about the coverage region, used to inject a coverage /// map into the binary. If `Coverage::kind` is a `Counter`, the statement also generates /// executable code, to increment a counter variable at runtime, each time the code region is diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index cb3f3850958ec..4b8eb3fbd9607 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -390,7 +390,7 @@ pub struct DestructuredConst<'tcx> { } /// Coverage information summarized from a MIR if instrumented for source code coverage (see -/// compiler option `-Zinstrument-coverage`). This information is generated by the +/// compiler option `-Cinstrument-coverage`). This information is generated by the /// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query. #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)] pub struct CoverageInfo { diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 8c930fd161efb..480f28620dc8f 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -4,8 +4,9 @@ use super::*; /// Preorder traversal of a graph. /// -/// Preorder traversal is when each node is visited before any of its -/// successors +/// Preorder traversal is when each node is visited after at least one of its predecessors. If you +/// are familar with some basic graph theory, then this performs a depth first search and returns +/// nodes in order of discovery time. /// /// ```text /// @@ -82,8 +83,9 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { /// Postorder traversal of a graph. /// -/// Postorder traversal is when each node is visited after all of its -/// successors, except when the successor is only reachable by a back-edge +/// Postorder traversal is when each node is visited after all of its successors, except when the +/// successor is only reachable by a back-edge. If you are familiar with some basic graph theory, +/// then this performs a depth first search and returns nodes in order of completion time. /// /// /// ```text diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 2e7dfb73c2cf4..e0448c3fe1c43 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -384,7 +384,7 @@ rustc_queries! { } /// Returns coverage summary info for a function, after executing the `InstrumentCoverage` - /// MIR pass (assuming the -Zinstrument-coverage option is enabled). + /// MIR pass (assuming the -Cinstrument-coverage option is enabled). query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo { desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) } storage(ArenaCacheSelector<'tcx>) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index caf33fa5d213b..c2aa83b8a7f9b 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2773,17 +2773,20 @@ pub fn fn_can_unwind<'tcx>( // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md use SpecAbi::*; match abi { - C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => { + C { unwind } + | System { unwind } + | Cdecl { unwind } + | Stdcall { unwind } + | Fastcall { unwind } + | Vectorcall { unwind } + | Thiscall { unwind } + | Aapcs { unwind } + | Win64 { unwind } + | SysV64 { unwind } => { unwind || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind) } - Cdecl - | Fastcall - | Vectorcall - | Aapcs - | Win64 - | SysV64 - | PtxKernel + PtxKernel | Msp430Interrupt | X86Interrupt | AmdGpuKernel @@ -2810,14 +2813,14 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv { EfiApi => bug!("eficall abi should be selected elsewhere"), Stdcall { .. } => Conv::X86Stdcall, - Fastcall => Conv::X86Fastcall, - Vectorcall => Conv::X86VectorCall, + Fastcall { .. } => Conv::X86Fastcall, + Vectorcall { .. } => Conv::X86VectorCall, Thiscall { .. } => Conv::X86ThisCall, C { .. } => Conv::C, Unadjusted => Conv::C, - Win64 => Conv::X86_64Win64, - SysV64 => Conv::X86_64SysV, - Aapcs => Conv::ArmAapcs, + Win64 { .. } => Conv::X86_64Win64, + SysV64 { .. } => Conv::X86_64SysV, + Aapcs { .. } => Conv::ArmAapcs, CCmseNonSecureCall => Conv::CCmseNonSecureCall, PtxKernel => Conv::PtxKernel, Msp430Interrupt => Conv::Msp430Intr, @@ -2828,7 +2831,7 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv { Wasm => Conv::C, // These API constants ought to be more specific... - Cdecl => Conv::C, + Cdecl { .. } => Conv::C, } } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 6329bcee4fa3f..a4e100973b675 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // The set of places that we are creating fake borrows of. If there are // no match guards then we don't need any fake borrows, so don't track // them. - let mut fake_borrows = if match_has_guard { Some(FxHashSet::default()) } else { None }; + let mut fake_borrows = match_has_guard.then(FxHashSet::default); let mut otherwise = None; diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index ce8b187a74443..62e060c8e0c6c 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -3,7 +3,7 @@ //! //! To enable coverage, include the rustc command line option: //! -//! * `-Z instrument-coverage` +//! * `-C instrument-coverage` //! //! MIR Dump Files, with additional `CoverageGraph` graphviz and `CoverageSpan` spanview //! ------------------------------------------------------------------------------------ diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 7e0c8e233e9e8..4651e1f4ed059 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -303,7 +303,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { /// evaluation: `if false { ... }`. /// /// Those statements are bypassed by redirecting paths in the CFG around the -/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually +/// `dead blocks`; but with `-C instrument-coverage`, the dead blocks usually /// include `Coverage` statements representing the Rust source code regions to /// be counted at runtime. Without these `Coverage` statements, the regions are /// lost, and the Rust source code will show no coverage information. diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 283eda7c85e64..c95dff13d6615 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -182,7 +182,7 @@ impl EncoderState { total_edge_count: 0, total_node_count: 0, result: Ok(()), - stats: if record_stats { Some(FxHashMap::default()) } else { None }, + stats: record_stats.then(FxHashMap::default), } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index d2d5b06ad67b6..8630ffec241f9 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -127,16 +127,16 @@ pub enum MirSpanview { Block, } -/// The different settings that the `-Z instrument-coverage` flag can have. +/// The different settings that the `-C instrument-coverage` flag can have. /// -/// Coverage instrumentation now supports combining `-Z instrument-coverage` +/// Coverage instrumentation now supports combining `-C instrument-coverage` /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1` /// and higher). Nevertheless, there are many variables, depending on options /// selected, code structure, and enabled attributes. If errors are encountered, /// either while compiling or when generating `llvm-cov show` reports, consider /// lowering the optimization level, including or excluding `-C link-dead-code`, -/// or using `-Z instrument-coverage=except-unused-functions` or `-Z -/// instrument-coverage=except-unused-generics`. +/// or using `-Zunstable-options -C instrument-coverage=except-unused-functions` +/// or `-Zunstable-options -C instrument-coverage=except-unused-generics`. /// /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the /// coverage map, it will not attempt to generate synthetic functions for unused @@ -148,13 +148,13 @@ pub enum MirSpanview { /// unless the function has type parameters. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum InstrumentCoverage { - /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement` + /// Default `-C instrument-coverage` or `-C instrument-coverage=statement` All, - /// `-Z instrument-coverage=except-unused-generics` + /// `-Zunstable-options -C instrument-coverage=except-unused-generics` ExceptUnusedGenerics, - /// `-Z instrument-coverage=except-unused-functions` + /// `-Zunstable-options -C instrument-coverage=except-unused-functions` ExceptUnusedFunctions, - /// `-Z instrument-coverage=off` (or `no`, etc.) + /// `-C instrument-coverage=off` (or `no`, etc.) Off, } @@ -2195,18 +2195,44 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { _ => {} } - if debugging_opts.instrument_coverage.is_some() - && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off) - { + // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes + // precedence. + match (cg.instrument_coverage, debugging_opts.instrument_coverage) { + (Some(ic_c), Some(ic_z)) if ic_c != ic_z => { + early_error( + error_format, + "incompatible values passed for `-C instrument-coverage` \ + and `-Z instrument-coverage`", + ); + } + (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {} + (Some(_), _) if !debugging_opts.unstable_options => { + early_error( + error_format, + "`-C instrument-coverage=except-*` requires `-Z unstable-options`", + ); + } + (None, None) => {} + (None, ic) => { + early_warn( + error_format, + "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`", + ); + cg.instrument_coverage = ic; + } + _ => {} + } + + if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) { if cg.profile_generate.enabled() || cg.profile_use.is_some() { early_error( error_format, - "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \ + "option `-C instrument-coverage` is not compatible with either `-C profile-use` \ or `-C profile-generate`", ); } - // `-Z instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent + // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over // multiple runs, including some changes to source code; so mangled names must be consistent // across compilations. @@ -2215,7 +2241,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { Some(SymbolManglingVersion::Legacy) => { early_warn( error_format, - "-Z instrument-coverage requires symbol mangling version `v0`, \ + "-C instrument-coverage requires symbol mangling version `v0`, \ but `-C symbol-mangling-version=legacy` was specified", ); } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index e7ab8fffdf35c..90eba3d688e43 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -109,17 +109,16 @@ impl Options { } pub fn instrument_coverage(&self) -> bool { - self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off) - != InstrumentCoverage::Off + self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off) != InstrumentCoverage::Off } pub fn instrument_coverage_except_unused_generics(&self) -> bool { - self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off) + self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off) == InstrumentCoverage::ExceptUnusedGenerics } pub fn instrument_coverage_except_unused_functions(&self) -> bool { - self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off) + self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off) == InstrumentCoverage::ExceptUnusedFunctions } } @@ -1031,6 +1030,14 @@ options! { "enable incremental compilation"), inline_threshold: Option = (None, parse_opt_number, [TRACKED], "set the threshold for inlining a function"), + instrument_coverage: Option = (None, parse_instrument_coverage, [TRACKED], + "instrument the generated code to support LLVM source-based code coverage \ + reports (note, the compiler build config must include `profiler = true`); \ + implies `-C symbol-mangling-version=v0`. Optional values are: + `=all` (implicit value) + `=except-unused-generics` + `=except-unused-functions` + `=off` (default)"), link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED], "a single extra argument to append to the linker invocation (can be used several times)"), link_args: Vec = (Vec::new(), parse_list, [UNTRACKED], diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 735b7e76e3862..43eb7ab05e0bf 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -658,22 +658,24 @@ impl<'a, Ty> FnAbi<'a, Ty> { match &cx.target_spec().arch[..] { "x86" => { - let flavor = if abi == spec::abi::Abi::Fastcall { + let flavor = if let spec::abi::Abi::Fastcall { .. } = abi { x86::Flavor::Fastcall } else { x86::Flavor::General }; x86::compute_abi_info(cx, self, flavor); } - "x86_64" => { - if abi == spec::abi::Abi::SysV64 { - x86_64::compute_abi_info(cx, self); - } else if abi == spec::abi::Abi::Win64 || cx.target_spec().is_like_windows { - x86_win64::compute_abi_info(self); - } else { - x86_64::compute_abi_info(cx, self); + "x86_64" => match abi { + spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self), + spec::abi::Abi::Win64 { .. } => x86_win64::compute_abi_info(self), + _ => { + if cx.target_spec().is_like_windows { + x86_win64::compute_abi_info(self) + } else { + x86_64::compute_abi_info(cx, self) + } } - } + }, "aarch64" => aarch64::compute_abi_info(cx, self), "amdgpu" => amdgpu::compute_abi_info(cx, self), "arm" => arm::compute_abi_info(cx, self), diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index e3a2226eb9d15..d9e571c72e53a 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -13,14 +13,14 @@ pub enum Abi { // churn. The specific values are meaningless. Rust, C { unwind: bool }, - Cdecl, + Cdecl { unwind: bool }, Stdcall { unwind: bool }, - Fastcall, - Vectorcall, + Fastcall { unwind: bool }, + Vectorcall { unwind: bool }, Thiscall { unwind: bool }, - Aapcs, - Win64, - SysV64, + Aapcs { unwind: bool }, + Win64 { unwind: bool }, + SysV64 { unwind: bool }, PtxKernel, Msp430Interrupt, X86Interrupt, @@ -50,16 +50,22 @@ const AbiDatas: &[AbiData] = &[ AbiData { abi: Abi::Rust, name: "Rust" }, AbiData { abi: Abi::C { unwind: false }, name: "C" }, AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" }, - AbiData { abi: Abi::Cdecl, name: "cdecl" }, + AbiData { abi: Abi::Cdecl { unwind: false }, name: "cdecl" }, + AbiData { abi: Abi::Cdecl { unwind: true }, name: "cdecl-unwind" }, AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall" }, AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind" }, - AbiData { abi: Abi::Fastcall, name: "fastcall" }, - AbiData { abi: Abi::Vectorcall, name: "vectorcall" }, + AbiData { abi: Abi::Fastcall { unwind: false }, name: "fastcall" }, + AbiData { abi: Abi::Fastcall { unwind: true }, name: "fastcall-unwind" }, + AbiData { abi: Abi::Vectorcall { unwind: false }, name: "vectorcall" }, + AbiData { abi: Abi::Vectorcall { unwind: true }, name: "vectorcall-unwind" }, AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall" }, AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind" }, - AbiData { abi: Abi::Aapcs, name: "aapcs" }, - AbiData { abi: Abi::Win64, name: "win64" }, - AbiData { abi: Abi::SysV64, name: "sysv64" }, + AbiData { abi: Abi::Aapcs { unwind: false }, name: "aapcs" }, + AbiData { abi: Abi::Aapcs { unwind: true }, name: "aapcs-unwind" }, + AbiData { abi: Abi::Win64 { unwind: false }, name: "win64" }, + AbiData { abi: Abi::Win64 { unwind: true }, name: "win64-unwind" }, + AbiData { abi: Abi::SysV64 { unwind: false }, name: "sysv64" }, + AbiData { abi: Abi::SysV64 { unwind: true }, name: "sysv64-unwind" }, AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" }, AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" }, AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" }, @@ -101,32 +107,38 @@ impl Abi { C { unwind: false } => 1, C { unwind: true } => 2, // Platform-specific ABIs - Cdecl => 3, - Stdcall { unwind: false } => 4, - Stdcall { unwind: true } => 5, - Fastcall => 6, - Vectorcall => 7, - Thiscall { unwind: false } => 8, - Thiscall { unwind: true } => 9, - Aapcs => 10, - Win64 => 11, - SysV64 => 12, - PtxKernel => 13, - Msp430Interrupt => 14, - X86Interrupt => 15, - AmdGpuKernel => 16, - EfiApi => 17, - AvrInterrupt => 18, - AvrNonBlockingInterrupt => 19, - CCmseNonSecureCall => 20, - Wasm => 21, + Cdecl { unwind: false } => 3, + Cdecl { unwind: true } => 4, + Stdcall { unwind: false } => 5, + Stdcall { unwind: true } => 6, + Fastcall { unwind: false } => 7, + Fastcall { unwind: true } => 8, + Vectorcall { unwind: false } => 9, + Vectorcall { unwind: true } => 10, + Thiscall { unwind: false } => 11, + Thiscall { unwind: true } => 12, + Aapcs { unwind: false } => 13, + Aapcs { unwind: true } => 14, + Win64 { unwind: false } => 15, + Win64 { unwind: true } => 16, + SysV64 { unwind: false } => 17, + SysV64 { unwind: true } => 18, + PtxKernel => 19, + Msp430Interrupt => 20, + X86Interrupt => 21, + AmdGpuKernel => 22, + EfiApi => 23, + AvrInterrupt => 24, + AvrNonBlockingInterrupt => 25, + CCmseNonSecureCall => 26, + Wasm => 27, // Cross-platform ABIs - System { unwind: false } => 22, - System { unwind: true } => 23, - RustIntrinsic => 24, - RustCall => 25, - PlatformIntrinsic => 26, - Unadjusted => 27, + System { unwind: false } => 28, + System { unwind: true } => 29, + RustIntrinsic => 30, + RustCall => 31, + PlatformIntrinsic => 32, + Unadjusted => 33, }; debug_assert!( AbiDatas diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 4effb8bacf6d6..06d38670a63b2 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1556,15 +1556,15 @@ impl Target { Abi::Stdcall { unwind } } Abi::System { unwind } => Abi::C { unwind }, - Abi::EfiApi if self.arch == "x86_64" => Abi::Win64, + Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false }, Abi::EfiApi => Abi::C { unwind: false }, // See commentary in `is_abi_supported`. Abi::Stdcall { .. } | Abi::Thiscall { .. } if self.arch == "x86" => abi, Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => Abi::C { unwind }, - Abi::Fastcall if self.arch == "x86" => abi, - Abi::Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => abi, - Abi::Fastcall | Abi::Vectorcall => Abi::C { unwind: false }, + Abi::Fastcall { .. } if self.arch == "x86" => abi, + Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi, + Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind }, abi => abi, } @@ -1581,12 +1581,12 @@ impl Target { | RustCall | PlatformIntrinsic | Unadjusted - | Cdecl + | Cdecl { .. } | EfiApi => true, X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]), - Aapcs => "arm" == self.arch, + Aapcs { .. } => "arm" == self.arch, CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]), - Win64 | SysV64 => self.arch == "x86_64", + Win64 { .. } | SysV64 { .. } => self.arch == "x86_64", PtxKernel => self.arch == "nvptx64", Msp430Interrupt => self.arch == "msp430", AmdGpuKernel => self.arch == "amdgcn", @@ -1623,13 +1623,13 @@ impl Target { // > convention is used. // // -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions - Stdcall { .. } | Fastcall | Vectorcall if self.is_like_windows => true, + Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true, // Outside of Windows we want to only support these calling conventions for the // architectures for which these calling conventions are actually well defined. - Stdcall { .. } | Fastcall if self.arch == "x86" => true, - Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => true, + Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true, + Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true, // Return a `None` for other cases so that we know to emit a future compat lint. - Stdcall { .. } | Fastcall | Vectorcall => return None, + Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => return None, }) } diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 7b004fa086bf3..d415e37ff0116 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -122,7 +122,7 @@ use bounds::Bounds; fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { match (decl.c_variadic, abi) { // The function has the correct calling convention, or isn't a "C-variadic" function. - (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl) => {} + (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {} // The function is a "C-variadic" function with an incorrect calling convention. (true, _) => { let mut err = struct_span_err!( diff --git a/config.toml.example b/config.toml.example index f24f8e81a7944..98688ca65b7e2 100644 --- a/config.toml.example +++ b/config.toml.example @@ -289,7 +289,7 @@ changelog-seen = 2 #sanitizers = false # Build the profiler runtime (required when compiling with options that depend -# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`). +# on this runtime, such as `-C profile-generate` or `-C instrument-coverage`). #profiler = false # Indicates whether the native libraries linked into Cargo will be statically @@ -671,7 +671,7 @@ changelog-seen = 2 #sanitizers = build.sanitizers (bool) # Build the profiler runtime for this target(required when compiling with options that depend -# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`). +# on this runtime, such as `-C profile-generate` or `-C instrument-coverage`). # This option will override the same option under [build] section. #profiler = build.profiler (bool) diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index fa23cf2689671..f940a9ff8f1d9 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -33,7 +33,6 @@ impl OutputFormatter for JunitFormatter { _shuffle_seed: Option, ) -> io::Result<()> { // We write xml header on run start - self.out.write_all(b"\n")?; self.write_message("") } @@ -138,7 +137,7 @@ impl OutputFormatter for JunitFormatter { self.write_message("")?; self.write_message("")?; - self.out.write_all(b"\n\n")?; + self.out.write_all(b"\n")?; Ok(state.failed == 0) } diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index c547e12f5b6ce..1c5961c4e0429 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" # https://github.com/puppeteer/puppeteer/issues/375 # # We also specify the version in case we need to update it to go around cache limitations. -RUN npm install -g browser-ui-test@0.5.8 --unsafe-perm=true +RUN npm install -g browser-ui-test@0.7.0 --unsafe-perm=true ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 146408900ab24..2fc94005b80f8 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -26,6 +26,7 @@ - [Custom Targets](targets/custom.md) - [Known Issues](targets/known-issues.md) - [Profile-guided Optimization](profile-guided-optimization.md) +- [Instrumentation-based Code Coverage](instrument-coverage.md) - [Linker-plugin based LTO](linker-plugin-lto.md) - [Exploit Mitigations](exploit-mitigations.md) - [Contributing to `rustc`](contributing.md) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 0201b88417a8b..3b0cf92bbb763 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -177,6 +177,15 @@ The default depends on the [opt-level](#opt-level): | s | 75 | | z | 25 | +## instrument-coverage + +This option enables instrumentation-based code coverage support. See the +chapter on [instrumentation-based code coverage] for more information. + +Note that while the `-C instrument-coverage` option is stable, the profile data +format produced by the resulting instrumentation may change, and may not work +with coverage tools other than those built and shipped with the compiler. + ## link-arg This flag lets you append a single extra argument to the linker invocation. @@ -597,5 +606,6 @@ effective only for x86 targets. [option-emit]: ../command-line-arguments.md#option-emit [option-o-optimize]: ../command-line-arguments.md#option-o-optimize +[instrumentation-based code coverage]: ../instrument-coverage.md [profile-guided optimization]: ../profile-guided-optimization.md [option-g-debug]: ../command-line-arguments.md#option-g-debug diff --git a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md similarity index 80% rename from src/doc/unstable-book/src/compiler-flags/instrument-coverage.md rename to src/doc/rustc/src/instrument-coverage.md index 39eb407269c11..b94989161ccfc 100644 --- a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md +++ b/src/doc/rustc/src/instrument-coverage.md @@ -1,23 +1,17 @@ # `instrument-coverage` -The tracking issue for this feature is: [#79121]. - -[#79121]: https://github.com/rust-lang/rust/issues/79121 - ---- - ## Introduction The Rust compiler includes two code coverage implementations: - A GCC-compatible, gcov-based coverage implementation, enabled with `-Z profile`, which derives coverage data based on DebugInfo. -- A source-based code coverage implementation, enabled with `-Z instrument-coverage`, which uses LLVM's native, efficient coverage instrumentation to generate very precise coverage data. +- A source-based code coverage implementation, enabled with `-C instrument-coverage`, which uses LLVM's native, efficient coverage instrumentation to generate very precise coverage data. -This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-Z instrument-coverage` compiler flag. +This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-C instrument-coverage` compiler flag. ## How it works -When `-Z instrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by: +When `-C instrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by: - Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed. - Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 5_, if compiling with LLVM 12, or _Version 6_, if compiling with LLVM 13 or higher), to define the code regions (start and end positions in the source code) being counted. @@ -27,13 +21,13 @@ When running a coverage-instrumented program, the counter values are written to [`llvm.instrprof.increment`]: https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic [llvm code coverage mapping format]: https://llvm.org/docs/CoverageMappingFormat.html -> **Note**: `-Z instrument-coverage` also automatically enables `-C symbol-mangling-version=v0` (tracking issue [#60705]). The `v0` symbol mangler is strongly recommended, but be aware that this demangler is also experimental. The `v0` demangler can be overridden by explicitly adding `-Z unstable-options -C symbol-mangling-version=legacy`. +> **Note**: `-C instrument-coverage` also automatically enables `-C symbol-mangling-version=v0` (tracking issue [#60705]). The `v0` symbol mangler is strongly recommended. The `v0` demangler can be overridden by explicitly adding `-Z unstable-options -C symbol-mangling-version=legacy`. [#60705]: https://github.com/rust-lang/rust/issues/60705 ## Enable coverage profiling in the Rust compiler -Rust's source-based code coverage requires the Rust "profiler runtime". Without it, compiling with `-Z instrument-coverage` generates an error that the profiler runtime is missing. +Rust's source-based code coverage requires the Rust "profiler runtime". Without it, compiling with `-C instrument-coverage` generates an error that the profiler runtime is missing. The Rust `nightly` distribution channel includes the profiler runtime, by default. @@ -41,7 +35,7 @@ The Rust `nightly` distribution channel includes the profiler runtime, by defaul > > ```toml > # Build the profiler runtime (required when compiling with options that depend -> # on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`). +> # on this runtime, such as `-C profile-generate` or `-C instrument-coverage`). > profiler = true > ``` @@ -65,9 +59,9 @@ $ ./x.py build rust-demangler ## Compiling with coverage enabled -Set the `-Z instrument-coverage` compiler flag in order to enable LLVM source-based code coverage profiling. +Set the `-C instrument-coverage` compiler flag in order to enable LLVM source-based code coverage profiling. -The default option generates coverage for all functions, including unused (never called) functions and generics. The compiler flag supports an optional value to tailor this behavior. (See [`-Z instrument-coverage=`](#-z-instrument-coverageoptions), below.) +The default option generates coverage for all functions, including unused (never called) functions and generics. The compiler flag supports an optional value to tailor this behavior. (See [`-C instrument-coverage=`](#-c-instrument-coverageoptions), below.) With `cargo`, you can instrument your program binary _and_ dependencies at the same time. @@ -76,18 +70,18 @@ For example (if your project's Cargo.toml builds a binary by default): ```shell $ cd your-project $ cargo clean -$ RUSTFLAGS="-Z instrument-coverage" cargo build +$ RUSTFLAGS="-C instrument-coverage" cargo build ``` If `cargo` is not configured to use your `profiler`-enabled version of `rustc`, set the path explicitly via the `RUSTC` environment variable. Here is another example, using a `stage1` build of `rustc` to compile an `example` binary (from the [`json5format`] crate): ```shell $ RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \ - RUSTFLAGS="-Z instrument-coverage" \ + RUSTFLAGS="-C instrument-coverage" \ cargo build --example formatjson5 ``` -> **Note**: that some compiler options, combined with `-Z instrument-coverage`, can produce LLVM IR and/or linked binaries that are incompatible with LLVM coverage maps. For example, coverage requires references to actual functions in LLVM IR. If any covered function is optimized out, the coverage tools may not be able to process the coverage results. If you need to pass additional options, with coverage enabled, test them early, to confirm you will get the coverage results you expect. +> **Note**: that some compiler options, combined with `-C instrument-coverage`, can produce LLVM IR and/or linked binaries that are incompatible with LLVM coverage maps. For example, coverage requires references to actual functions in LLVM IR. If any covered function is optimized out, the coverage tools may not be able to process the coverage results. If you need to pass additional options, with coverage enabled, test them early, to confirm you will get the coverage results you expect. ## Running the instrumented binary to generate raw coverage profiling data @@ -123,31 +117,23 @@ If `LLVM_PROFILE_FILE` contains a path to a non-existent directory, the missing ## Installing LLVM coverage tools -LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 12 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.): +LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 12 or higher, and processing the *raw* data may require exactly the LLVM version used by the compiler. (`llvm-cov --version` typically shows the tool's LLVM version number, and `rustc --verbose --version` shows the version of LLVM used by the Rust compiler.) -- The LLVM tools may be installed (or installable) directly to your OS (such as via `apt-get`, for Linux). +- You can install compatible versions of these tools via the `rustup` component `llvm-tools-preview`. This component is the recommended path, though the specific tools available and their interface is not currently subject to Rust's usual stability guarantees. In this case, you may also find `cargo-binutils` useful as a wrapper around these tools. +- You can install a compatible version of LLVM tools from your operating system distribution, or from your distribution of LLVM. - If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`. -- You can install compatible versions of these tools via `rustup`. - -The `rustup` option is guaranteed to install a compatible version of the LLVM tools, but they can be hard to find. We recommend [`cargo-binutils`], which installs Rust-specific wrappers around these and other LLVM tools, so you can invoke them via `cargo` commands! - -```shell -$ rustup component add llvm-tools-preview -$ cargo install cargo-binutils -$ cargo profdata -- --help # note the additional "--" preceding the tool-specific arguments -``` -[`cargo-binutils`]: https://crates.io/crates/cargo-binutils +The examples in this document show how to use the llvm tools directly. ## Creating coverage reports -Raw profiles have to be indexed before they can be used to generate coverage reports. This is done using [`llvm-profdata merge`] (or `cargo profdata -- merge`), which can combine multiple raw profiles and index them at the same time: +Raw profiles have to be indexed before they can be used to generate coverage reports. This is done using [`llvm-profdata merge`], which can combine multiple raw profiles and index them at the same time: ```shell $ llvm-profdata merge -sparse formatjson5.profraw -o formatjson5.profdata ``` -Finally, the `.profdata` file is used, in combination with the coverage map (from the program binary) to generate coverage reports using [`llvm-cov report`] (or `cargo cov -- report`), for a coverage summaries; and [`llvm-cov show`] (or `cargo cov -- show`), to see detailed coverage of lines and regions (character ranges) overlaid on the original source code. +Finally, the `.profdata` file is used, in combination with the coverage map (from the program binary) to generate coverage reports using [`llvm-cov report`], for a coverage summaries; and [`llvm-cov show`], to see detailed coverage of lines and regions (character ranges) overlaid on the original source code. These commands have several display and filtering options. For example: @@ -176,7 +162,7 @@ Some of the more notable options in this example include: > **Note**: Coverage can also be disabled on an individual function by annotating the function with the [`no_coverage` attribute] (which requires the feature flag `#![feature(no_coverage)]`). -[`no_coverage` attribute]: ../language-features/no-coverage.md +[`no_coverage` attribute]: ../unstable-book/language-features/no-coverage.html ## Interpreting reports @@ -195,10 +181,10 @@ A typical use case for coverage analysis is test coverage. Rust's source-based c The following example (using the [`json5format`] crate, for demonstration purposes) show how to generate and analyze coverage results for all tests in a crate. -Since `cargo test` both builds and runs the tests, we set both the additional `RUSTFLAGS`, to add the `-Z instrument-coverage` flag, and `LLVM_PROFILE_FILE`, to set a custom filename for the raw profiling data generated during the test runs. Since there may be more than one test binary, apply `%m` in the filename pattern. This generates unique names for each test binary. (Otherwise, each executed test binary would overwrite the coverage results from the previous binary.) +Since `cargo test` both builds and runs the tests, we set both the additional `RUSTFLAGS`, to add the `-C instrument-coverage` flag, and `LLVM_PROFILE_FILE`, to set a custom filename for the raw profiling data generated during the test runs. Since there may be more than one test binary, apply `%m` in the filename pattern. This generates unique names for each test binary. (Otherwise, each executed test binary would overwrite the coverage results from the previous binary.) ```shell -$ RUSTFLAGS="-Z instrument-coverage" \ +$ RUSTFLAGS="-C instrument-coverage" \ LLVM_PROFILE_FILE="json5format-%m.profraw" \ cargo test --tests ``` @@ -224,19 +210,18 @@ test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out You should have one or more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them: ```shell -$ cargo profdata -- merge \ - -sparse json5format-*.profraw -o json5format.profdata +$ llvm-profdata merge -sparse json5format-*.profraw -o json5format.profdata ``` Then run the `cov` tool, with the `profdata` file and all test binaries: ```shell -$ cargo cov -- report \ +$ llvm-cov report \ --use-color --ignore-filename-regex='/.cargo/registry' \ --instr-profile=json5format.profdata \ --object target/debug/deps/lib-30768f9c53506dc5 \ --object target/debug/deps/json5format-fececd4653271682 -$ cargo cov -- show \ +$ llvm-cov show \ --use-color --ignore-filename-regex='/.cargo/registry' \ --instr-profile=json5format.profdata \ --object target/debug/deps/lib-30768f9c53506dc5 \ @@ -252,11 +237,11 @@ $ cargo cov -- show \ For `bash` users, one suggested way to automatically complete the `cov` command with the list of binaries is with a command like: ```bash -$ cargo cov -- report \ +$ llvm-cov report \ $( \ for file in \ $( \ - RUSTFLAGS="-Z instrument-coverage" \ + RUSTFLAGS="-C instrument-coverage" \ cargo test --tests --no-run --message-format=json \ | jq -r "select(.profile.test == true) | .filenames[]" \ | grep -v dSYM - \ @@ -280,28 +265,27 @@ for each listed test binary. The previous examples run `cargo test` with `--tests`, which excludes doc tests.[^79417] To include doc tests in the coverage results, drop the `--tests` flag, and apply the -`-Z instrument-coverage` flag, and some doc-test-specific options in the -`RUSTDOCFLAGS` environment variable. (The `cargo profdata` command does not change.) +`-C instrument-coverage` flag, and some doc-test-specific options in the +`RUSTDOCFLAGS` environment variable. (The `llvm-profdata` command does not change.) ```bash -$ RUSTFLAGS="-Z instrument-coverage" \ - RUSTDOCFLAGS="-Z instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \ +$ RUSTFLAGS="-C instrument-coverage" \ + RUSTDOCFLAGS="-C instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \ LLVM_PROFILE_FILE="json5format-%m.profraw" \ cargo test -$ cargo profdata -- merge \ - -sparse json5format-*.profraw -o json5format.profdata +$ llvm-profdata merge -sparse json5format-*.profraw -o json5format.profdata ``` The `-Z unstable-options --persist-doctests` flag is required, to save the test binaries (with their coverage maps) for `llvm-cov`. ```bash -$ cargo cov -- report \ +$ llvm-cov report \ $( \ for file in \ $( \ - RUSTFLAGS="-Z instrument-coverage" \ - RUSTDOCFLAGS="-Z instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \ + RUSTFLAGS="-C instrument-coverage" \ + RUSTDOCFLAGS="-C instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \ cargo test --no-run --message-format=json \ | jq -r "select(.profile.test == true) | .filenames[]" \ | grep -v dSYM - \ @@ -314,8 +298,8 @@ $ cargo cov -- report \ --instr-profile=json5format.profdata --summary-only # and/or other options ``` -> **Note**: The differences in this `cargo cov` command, compared with the version without -> doc tests, include: +> **Note**: The differences in this `llvm-cov` invocation, compared with the +> version without doc tests, include: - The `cargo test ... --no-run` command is updated with the same environment variables and flags used to _build_ the tests, _including_ the doc tests. (`LLVM_PROFILE_FILE` @@ -331,12 +315,12 @@ $ cargo cov -- report \ [(#79417)](https://github.com/rust-lang/rust/issues/79417) that doc test coverage generates incorrect source line numbers in `llvm-cov show` results. -## `-Z instrument-coverage=` +## `-C instrument-coverage=` -- `-Z instrument-coverage=all`: Instrument all functions, including unused functions and unused generics. (This is the same as `-Z instrument-coverage`, with no value.) -- `-Z instrument-coverage=except-unused-generics`: Instrument all functions except unused generics. -- `-Z instrument-coverage=except-unused-functions`: Instrument only used (called) functions and instantiated generic functions. -- `-Z instrument-coverage=off`: Do not instrument any functions. (This is the same as simply not including the `-Z instrument-coverage` option.) +- `-C instrument-coverage=all`: Instrument all functions, including unused functions and unused generics. (This is the same as `-C instrument-coverage`, with no value.) +- `-C instrument-coverage=off`: Do not instrument any functions. (This is the same as simply not including the `-C instrument-coverage` option.) +- `-Zunstable-options -C instrument-coverage=except-unused-generics`: Instrument all functions except unused generics. +- `-Zunstable-options -C instrument-coverage=except-unused-functions`: Instrument only used (called) functions and instantiated generic functions. ## Other references diff --git a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md deleted file mode 100644 index cb65978e0a07e..0000000000000 --- a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md +++ /dev/null @@ -1,5 +0,0 @@ -# `source-based-code-coverage` - -See compiler flag [`-Z instrument-coverage`]. - -[`-z instrument-coverage`]: ./instrument-coverage.html diff --git a/src/doc/unstable-book/src/language-features/c-unwind.md b/src/doc/unstable-book/src/language-features/c-unwind.md index 2801d9b5e7778..fb32918d5e439 100644 --- a/src/doc/unstable-book/src/language-features/c-unwind.md +++ b/src/doc/unstable-book/src/language-features/c-unwind.md @@ -6,9 +6,20 @@ The tracking issue for this feature is: [#74990] ------------------------ -Introduces four new ABI strings: "C-unwind", "stdcall-unwind", -"thiscall-unwind", and "system-unwind". These enable unwinding from other -languages (such as C++) into Rust frames and from Rust into other languages. +Introduces new ABI strings: +- "C-unwind" +- "cdecl-unwind" +- "stdcall-unwind" +- "fastcall-unwind" +- "vectorcall-unwind" +- "thiscall-unwind" +- "aapcs-unwind" +- "win64-unwind" +- "sysv64-unwind" +- "system-unwind" + +These enable unwinding from other languages (such as C++) into Rust frames and +from Rust into other languages. See [RFC 2945] for more information. diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 024fe6345d295..d16383723f563 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -659,7 +659,7 @@ crate fn make_test( } else { let returns_result = everything_else.trim_end().ends_with("(())"); // Give each doctest main function a unique name. - // This is for example needed for the tooling around `-Z instrument-coverage`. + // This is for example needed for the tooling around `-C instrument-coverage`. let inner_fn_name = if let Some(test_id) = test_id { format!("_doctest_main_{}", test_id) } else { @@ -684,7 +684,7 @@ crate fn make_test( }; // Note on newlines: We insert a line/newline *before*, and *after* // the doctest and adjust the `line_offset` accordingly. - // In the case of `-Z instrument-coverage`, this means that the generated + // In the case of `-C instrument-coverage`, this means that the generated // inner `main` function spans from the doctest opening codeblock to the // closing one. For example // /// ``` <- start of the inner main diff --git a/src/test/codegen/unwind-abis/aapcs-unwind-abi.rs b/src/test/codegen/unwind-abis/aapcs-unwind-abi.rs new file mode 100644 index 0000000000000..1fe048068601d --- /dev/null +++ b/src/test/codegen/unwind-abis/aapcs-unwind-abi.rs @@ -0,0 +1,31 @@ +// needs-llvm-components: arm +// compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items, c_unwind)] +#[lang="sized"] +trait Sized { } + +// Test that `nounwind` atributes are correctly applied to exported `aapcs` and +// `aapcs-unwind` extern functions. `aapcs-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "aapcs" fn rust_item_that_cannot_unwind() { +} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "aapcs-unwind" fn rust_item_that_can_unwind() { +} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/src/test/codegen/unwind-abis/cdecl-unwind-abi.rs b/src/test/codegen/unwind-abis/cdecl-unwind-abi.rs new file mode 100644 index 0000000000000..52e0d2d6e0252 --- /dev/null +++ b/src/test/codegen/unwind-abis/cdecl-unwind-abi.rs @@ -0,0 +1,29 @@ +// compile-flags: -C opt-level=0 + +// Test that `nounwind` atributes are correctly applied to exported `cdecl` and +// `cdecl-unwind` extern functions. `cdecl-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +#![crate_type = "lib"] +#![feature(c_unwind)] + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "cdecl" fn rust_item_that_cannot_unwind() { +} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "cdecl-unwind" fn rust_item_that_can_unwind() { +} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/src/test/codegen/unwind-abis/fastcall-unwind-abi.rs b/src/test/codegen/unwind-abis/fastcall-unwind-abi.rs new file mode 100644 index 0000000000000..ed23235ebfa80 --- /dev/null +++ b/src/test/codegen/unwind-abis/fastcall-unwind-abi.rs @@ -0,0 +1,31 @@ +// needs-llvm-components: x86 +// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items, c_unwind)] +#[lang="sized"] +trait Sized { } + +// Test that `nounwind` atributes are correctly applied to exported `fastcall` and +// `fastcall-unwind` extern functions. `fastcall-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "fastcall" fn rust_item_that_cannot_unwind() { +} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "fastcall-unwind" fn rust_item_that_can_unwind() { +} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/src/test/codegen/unwind-abis/sysv64-unwind-abi.rs b/src/test/codegen/unwind-abis/sysv64-unwind-abi.rs new file mode 100644 index 0000000000000..a38736f2a1f95 --- /dev/null +++ b/src/test/codegen/unwind-abis/sysv64-unwind-abi.rs @@ -0,0 +1,31 @@ +// needs-llvm-components: x86 +// compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items, c_unwind)] +#[lang="sized"] +trait Sized { } + +// Test that `nounwind` atributes are correctly applied to exported `sysv64` and +// `sysv64-unwind` extern functions. `sysv64-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "sysv64" fn rust_item_that_cannot_unwind() { +} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "sysv64-unwind" fn rust_item_that_can_unwind() { +} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs b/src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs new file mode 100644 index 0000000000000..0fb9612a5e4e8 --- /dev/null +++ b/src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs @@ -0,0 +1,31 @@ +// needs-llvm-components: x86 +// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items, c_unwind, abi_vectorcall)] +#[lang="sized"] +trait Sized { } + +// Test that `nounwind` atributes are correctly applied to exported `vectorcall` and +// `vectorcall-unwind` extern functions. `vectorcall-unwind` functions MUST NOT have this attribute. +// We disable optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "vectorcall" fn rust_item_that_cannot_unwind() { +} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "vectorcall-unwind" fn rust_item_that_can_unwind() { +} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/src/test/codegen/unwind-abis/win64-unwind-abi.rs b/src/test/codegen/unwind-abis/win64-unwind-abi.rs new file mode 100644 index 0000000000000..5d8482da63056 --- /dev/null +++ b/src/test/codegen/unwind-abis/win64-unwind-abi.rs @@ -0,0 +1,31 @@ +// needs-llvm-components: x86 +// compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items, c_unwind)] +#[lang="sized"] +trait Sized { } + +// Test that `nounwind` atributes are correctly applied to exported `win64` and +// `win64-unwind` extern functions. `win64-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "win64" fn rust_item_that_cannot_unwind() { +} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "win64-unwind" fn rust_item_that_can_unwind() { +} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/src/test/mir-opt/coverage_graphviz.rs b/src/test/mir-opt/coverage_graphviz.rs index b3c90c528377d..09403bb3a7926 100644 --- a/src/test/mir-opt/coverage_graphviz.rs +++ b/src/test/mir-opt/coverage_graphviz.rs @@ -1,9 +1,9 @@ -// Test that `-Z instrument-coverage` with `-Z dump-mir-graphviz` generates a graphviz (.dot file) +// Test that `-C instrument-coverage` with `-Z dump-mir-graphviz` generates a graphviz (.dot file) // rendering of the `BasicCoverageBlock` coverage control flow graph, with counters and // expressions. // needs-profiler-support -// compile-flags: -Z instrument-coverage -Z dump-mir-graphviz +// compile-flags: -C instrument-coverage -Z dump-mir-graphviz // EMIT_MIR coverage_graphviz.main.InstrumentCoverage.0.dot // EMIT_MIR coverage_graphviz.bar.InstrumentCoverage.0.dot fn main() { diff --git a/src/test/mir-opt/instrument_coverage.rs b/src/test/mir-opt/instrument_coverage.rs index 18863edac97e4..a748f2c5ccc9b 100644 --- a/src/test/mir-opt/instrument_coverage.rs +++ b/src/test/mir-opt/instrument_coverage.rs @@ -1,9 +1,9 @@ -// Test that `-Z instrument-coverage` injects Coverage statements. The Coverage Counter statements +// Test that `-C instrument-coverage` injects Coverage statements. The Coverage Counter statements // are later converted into LLVM instrprof.increment intrinsics, during codegen. // needs-profiler-support // ignore-windows -// compile-flags: -Z instrument-coverage --remap-path-prefix={{src-base}}=/the/src +// compile-flags: -C instrument-coverage --remap-path-prefix={{src-base}}=/the/src // EMIT_MIR instrument_coverage.main.InstrumentCoverage.diff // EMIT_MIR instrument_coverage.bar.InstrumentCoverage.diff diff --git a/src/test/run-make-fulldeps/coverage-llvmir/Makefile b/src/test/run-make-fulldeps/coverage-llvmir/Makefile index 3c4df3533e147..fbe0a5cb1bb8c 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir/Makefile +++ b/src/test/run-make-fulldeps/coverage-llvmir/Makefile @@ -57,7 +57,7 @@ all: test_llvm_ir test_llvm_ir: # Compile the test program with non-experimental coverage instrumentation, and generate LLVM IR $(RUSTC) $(BASEDIR)/testprog.rs \ - -Zinstrument-coverage \ + -Cinstrument-coverage \ --emit=llvm-ir cat "$(TMPDIR)"/testprog.ll | \ diff --git a/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt b/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt index 8e5f210468773..1e2ecc2fbb1cc 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt +++ b/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt @@ -1,5 +1,5 @@ # Check for metadata, variables, declarations, and function definitions injected -# into LLVM IR when compiling with -Zinstrument-coverage. +# into LLVM IR when compiling with -Cinstrument-coverage. WINDOWS: $__llvm_profile_runtime_user = comdat any diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index 094d6b3ebf5f8..78723e78e772f 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -81,13 +81,13 @@ endif # Compile the test library with coverage instrumentation $(RUSTC) $(SOURCEDIR)/lib/$@.rs \ $$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/lib/$@.rs ) \ - --crate-type rlib -Zinstrument-coverage + --crate-type rlib -Cinstrument-coverage %: $(SOURCEDIR)/%.rs # Compile the test program with coverage instrumentation $(RUSTC) $(SOURCEDIR)/$@.rs \ $$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/$@.rs ) \ - -L "$(TMPDIR)" -Zinstrument-coverage + -L "$(TMPDIR)" -Cinstrument-coverage # Run it in order to generate some profiling data, # with `LLVM_PROFILE_FILE=` environment variable set to @@ -109,7 +109,7 @@ endif LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p-%m.profraw \ $(RUSTDOC) --crate-name workaround_for_79771 --test $(SOURCEDIR)/$@.rs \ $$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/$@.rs ) \ - -L "$(TMPDIR)" -Zinstrument-coverage \ + -L "$(TMPDIR)" -Cinstrument-coverage \ -Z unstable-options --persist-doctests=$(TMPDIR)/rustdoc-$@ # Postprocess the profiling data so it can be used by the llvm-cov tool diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index c2d5143a61816..55a49548cb5e0 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -125,7 +125,7 @@ 78| |// generic functions with: 79| |// 80| |// ```shell - 81| |// $ `rustc -Z instrument-coverage=except-unused-generics ...` + 81| |// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...` 82| |// ``` 83| |// 84| |// Even though this function is used by `uses_crate.rs` (and diff --git a/src/test/run-make-fulldeps/coverage/lib/used_crate.rs b/src/test/run-make-fulldeps/coverage/lib/used_crate.rs index eaa93115ae8d2..8b8b1f7f351fd 100644 --- a/src/test/run-make-fulldeps/coverage/lib/used_crate.rs +++ b/src/test/run-make-fulldeps/coverage/lib/used_crate.rs @@ -78,7 +78,7 @@ fn use_this_lib_crate() { // generic functions with: // // ```shell -// $ `rustc -Z instrument-coverage=except-unused-generics ...` +// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...` // ``` // // Even though this function is used by `uses_crate.rs` (and diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index 357dd25389ecb..e5aef04b6894e 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `路濫狼á́́` LL | extern "路濫狼á́́" fn foo() {} | ^^^^^^^^^ invalid ABI | - = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted + = help: valid ABIs: Rust, C, C-unwind, cdecl, cdecl-unwind, stdcall, stdcall-unwind, fastcall, fastcall-unwind, vectorcall, vectorcall-unwind, thiscall, thiscall-unwind, aapcs, aapcs-unwind, win64, win64-unwind, sysv64, sysv64-unwind, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted error: aborting due to previous error diff --git a/src/test/ui/consts/recursive.rs b/src/test/ui/consts/recursive.rs new file mode 100644 index 0000000000000..664940c52cfc5 --- /dev/null +++ b/src/test/ui/consts/recursive.rs @@ -0,0 +1,11 @@ +#![allow(unused)] + +const fn f(x: T) { //~ WARN function cannot return without recursing + f(x); + //~^ ERROR any use of this value will cause an error + //~| WARN this was previously accepted by the compiler +} + +const X: () = f(1); + +fn main() {} diff --git a/src/test/ui/consts/recursive.stderr b/src/test/ui/consts/recursive.stderr new file mode 100644 index 0000000000000..31ac1fff4e84e --- /dev/null +++ b/src/test/ui/consts/recursive.stderr @@ -0,0 +1,31 @@ +warning: function cannot return without recursing + --> $DIR/recursive.rs:3:1 + | +LL | const fn f(x: T) { + | ^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | f(x); + | ---- recursive call site + | + = note: `#[warn(unconditional_recursion)]` on by default + = help: a `loop` may express intention better if this is on purpose + +error: any use of this value will cause an error + --> $DIR/recursive.rs:4:5 + | +LL | f(x); + | ^^^^ + | | + | reached the configured maximum number of stack frames + | inside `f::` at $DIR/recursive.rs:4:5 + | [... 126 additional calls inside `f::` at $DIR/recursive.rs:4:5 ...] + | inside `X` at $DIR/recursive.rs:9:15 +... +LL | const X: () = f(1); + | ------------------- + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/panics/default-backtrace-ice.rs b/src/test/ui/panics/default-backtrace-ice.rs new file mode 100644 index 0000000000000..fd86a3f9dfaff --- /dev/null +++ b/src/test/ui/panics/default-backtrace-ice.rs @@ -0,0 +1,9 @@ +// unset-rustc-env:RUST_BACKTRACE +// compile-flags:-Z treat-err-as-bug=1 +// error-pattern:stack backtrace: +// failure-status:101 +// normalize-stderr-test "note: .*" -> "" +// normalize-stderr-test "thread 'rustc' .*" -> "" +// normalize-stderr-test " .*\n" -> "" + +fn main() { missing_ident; } diff --git a/src/test/ui/panics/default-backtrace-ice.stderr b/src/test/ui/panics/default-backtrace-ice.stderr new file mode 100644 index 0000000000000..a0025d7e221ae --- /dev/null +++ b/src/test/ui/panics/default-backtrace-ice.stderr @@ -0,0 +1,18 @@ +error[E0425]: cannot find value `missing_ident` in this scope +LL | fn main() { missing_ident; } + + +stack backtrace: + +error: internal compiler error: unexpected panic + + + + + + + + + +query stack during panic: +end of query stack diff --git a/src/test/ui/parser/issues/issue-8537.stderr b/src/test/ui/parser/issues/issue-8537.stderr index 5a29ce2221fc2..5f8d4315de829 100644 --- a/src/test/ui/parser/issues/issue-8537.stderr +++ b/src/test/ui/parser/issues/issue-8537.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `invalid-ab_isize` LL | "invalid-ab_isize" | ^^^^^^^^^^^^^^^^^^ invalid ABI | - = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted + = help: valid ABIs: Rust, C, C-unwind, cdecl, cdecl-unwind, stdcall, stdcall-unwind, fastcall, fastcall-unwind, vectorcall, vectorcall-unwind, thiscall, thiscall-unwind, aapcs, aapcs-unwind, win64, win64-unwind, sysv64, sysv64-unwind, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted error: aborting due to previous error