diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index d779089eeaa4c..a1e14b5245137 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -10,7 +10,7 @@ use rustc_parse_format as parse; use rustc_session::lint; use rustc_span::{ErrorGuaranteed, InnerSpan, Span, Symbol, sym}; use rustc_target::asm::InlineAsmArch; -use smallvec::{SmallVec, smallvec}; +use smallvec::smallvec; use crate::errors; use crate::util::{ExprToSpannedString, expr_to_spanned_string}; @@ -26,24 +26,6 @@ struct ValidatedAsmArgs { pub options_spans: Vec, } -struct MacGlobalAsm { - item: ast::Item, -} - -impl MacResult for MacGlobalAsm { - fn make_items(self: Box) -> Option; 1]>> { - Some(smallvec![Box::new(self.item)]) - } - - fn make_stmts(self: Box) -> Option> { - Some(smallvec![ast::Stmt { - id: ast::DUMMY_NODE_ID, - span: self.item.span, - kind: ast::StmtKind::Item(Box::new(self.item)), - }]) - } -} - fn parse_args<'a>( ecx: &ExtCtxt<'a>, sp: Span, @@ -668,20 +650,18 @@ pub(super) fn expand_global_asm<'cx>( return ExpandResult::Retry(()); }; match mac { - Ok(inline_asm) => Box::new(MacGlobalAsm { - item: ast::Item { - attrs: ast::AttrVec::new(), - id: ast::DUMMY_NODE_ID, - kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), - vis: ast::Visibility { - span: sp.shrink_to_lo(), - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - span: sp, + Ok(inline_asm) => MacEager::items(smallvec![Box::new(ast::Item { + attrs: ast::AttrVec::new(), + id: ast::DUMMY_NODE_ID, + kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), + vis: ast::Visibility { + span: sp.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, tokens: None, }, - }), + span: sp, + tokens: None, + })]), Err(guar) => DummyResult::any(sp, guar), } } diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 426ead704ab83..8138fb6a2ff40 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -239,7 +239,6 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { let annotation: Box = match s { Normal => Box::new(AstNoAnn), Expanded => Box::new(AstNoAnn), - Identified => Box::new(AstIdentifiedAnn), ExpandedIdentified => Box::new(AstIdentifiedAnn), ExpandedHygiene => Box::new(AstHygieneAnn { sess }), }; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 323f0fb040d6b..6a9a2065f4d31 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2707,12 +2707,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(CtorKind::Const) => unreachable!("unit variants don't have fields"), }; - // Suggest constructor as deep into the block tree as possible. - // This fixes https://github.com/rust-lang/rust/issues/101065, - // and also just helps make the most minimal suggestions. + // Suggest constructor as deep into the block tree as possible, + // but don't cross macro contexts. This fixes #101065 while + // keeping suggestions out of macro definitions (#142359). let mut expr = expr; while let hir::ExprKind::Block(block, _) = &expr.kind && let Some(expr_) = &block.expr + && expr_.span.eq_ctxt(expr.span) { expr = expr_ } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 523d7c9eeeda4..e9853abee406c 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -249,7 +249,7 @@ pub(crate) enum UnusedVariableSugg { shorthands: Vec, #[suggestion_part(code = "_")] non_shorthands: Vec, - name: Symbol, + name: String, }, #[multipart_suggestion( diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index a1b2a2853c0bd..c449cf6867395 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -1068,7 +1068,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { let sugg = if any_shorthand { errors::UnusedVariableSugg::TryIgnore { - name, + name: name.to_ident_string(), shorthands: introductions .iter() .filter_map( diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 2040cd48ec44f..e82f67eac5e9f 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2787,7 +2787,6 @@ fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> O let first = match unstable_opts.unpretty.as_deref()? { "normal" => Source(PpSourceMode::Normal), - "identified" => Source(PpSourceMode::Identified), "expanded" => Source(PpSourceMode::Expanded), "expanded,identified" => Source(PpSourceMode::ExpandedIdentified), "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene), @@ -2803,7 +2802,7 @@ fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> O "stable-mir" => StableMir, "mir-cfg" => MirCFG, name => early_dcx.early_fatal(format!( - "argument to `unpretty` must be one of `normal`, `identified`, \ + "argument to `unpretty` must be one of `normal`, \ `expanded`, `expanded,identified`, `expanded,hygiene`, \ `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \ `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir`, `stable-mir`, or \ @@ -2933,8 +2932,6 @@ pub enum PpSourceMode { Normal, /// `-Zunpretty=expanded` Expanded, - /// `-Zunpretty=identified` - Identified, /// `-Zunpretty=expanded,identified` ExpandedIdentified, /// `-Zunpretty=expanded,hygiene` @@ -2982,7 +2979,7 @@ impl PpMode { use PpMode::*; use PpSourceMode::*; match *self { - Source(Normal | Identified) | AstTree => false, + Source(Normal) | AstTree => false, Source(Expanded | ExpandedIdentified | ExpandedHygiene) | AstTreeExpanded diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index aa9331ee8f659..1b2e24a684bc9 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2723,7 +2723,7 @@ written to standard error output)"), "take the brakes off const evaluation. NOTE: this is unsound (default: no)"), unpretty: Option = (None, parse_unpretty, [UNTRACKED], "present the input source, unstable (and less-pretty) variants; - `normal`, `identified`, + `normal`, `expanded`, `expanded,identified`, `expanded,hygiene` (with internal representations), `ast-tree` (raw AST before expansion), diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 7600da856a18d..49b860d9cd4cf 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -16,7 +16,7 @@ use crate::directives::directive_names::{ pub(crate) use crate::directives::file::FileDirectives; use crate::directives::handlers::DIRECTIVE_HANDLERS_MAP; use crate::directives::line::DirectiveLine; -use crate::directives::needs::CachedNeedsConditions; +use crate::directives::needs::PreparedNeedsConditions; use crate::edition::{Edition, parse_edition}; use crate::errors::ErrorKind; use crate::executor::{CollectedTestDesc, ShouldFail}; @@ -40,14 +40,14 @@ pub(crate) struct DirectivesCache { /// "Conditions" used by `ignore-*` and `only-*` directives, prepared in /// advance so that they don't have to be evaluated repeatedly. cfg_conditions: cfg::PreparedConditions, - needs: CachedNeedsConditions, + needs: PreparedNeedsConditions, } impl DirectivesCache { pub(crate) fn load(config: &Config) -> Self { Self { cfg_conditions: cfg::prepare_conditions(config), - needs: CachedNeedsConditions::load(config), + needs: needs::prepare_needs_conditions(config), } } } diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index 88ca347edd0a5..64c488aaa7935 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -1,16 +1,182 @@ +use std::collections::HashMap; + use crate::common::{ Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer, query_rustc_output, }; -use crate::directives::{DirectiveLine, IgnoreDecision}; +use crate::directives::{DirectiveLine, IgnoreDecision, KNOWN_DIRECTIVE_NAMES_SET}; pub(super) fn handle_needs( - cache: &CachedNeedsConditions, + conditions: &PreparedNeedsConditions, config: &Config, ln: &DirectiveLine<'_>, ) -> IgnoreDecision { + let &DirectiveLine { name, .. } = ln; + + if !name.starts_with("needs-") { + return IgnoreDecision::Continue; + } + + if name == "needs-target-has-atomic" { + let Some(rest) = ln.value_after_colon() else { + return IgnoreDecision::Error { + message: "expected `needs-target-has-atomic` to have a comma-separated list of atomic widths".to_string(), + }; + }; + + // Expect directive value to be a list of comma-separated atomic widths. + let specified_widths = rest + .split(',') + .map(|width| width.trim()) + .map(ToString::to_string) + .collect::>(); + + for width in &specified_widths { + if !KNOWN_TARGET_HAS_ATOMIC_WIDTHS.contains(&width.as_str()) { + return IgnoreDecision::Error { + message: format!( + "unknown width specified in `needs-target-has-atomic`: `{width}` is not a \ + known `target_has_atomic_width`, known values are `{:?}`", + KNOWN_TARGET_HAS_ATOMIC_WIDTHS + ), + }; + } + } + + let satisfies_all_specified_widths = specified_widths + .iter() + .all(|specified| config.target_cfg().target_has_atomic.contains(specified)); + if satisfies_all_specified_widths { + return IgnoreDecision::Continue; + } else { + return IgnoreDecision::Ignore { + reason: format!( + "skipping test as target does not support all of the required `target_has_atomic` widths `{:?}`", + specified_widths + ), + }; + } + } + + // FIXME(jieyouxu): share multi-value directive logic with `needs-target-has-atomic` above. + if name == "needs-crate-type" { + let Some(rest) = ln.value_after_colon() else { + return IgnoreDecision::Error { + message: + "expected `needs-crate-type` to have a comma-separated list of crate types" + .to_string(), + }; + }; + + // Expect directive value to be a list of comma-separated crate-types. + let specified_crate_types = rest + .split(',') + .map(|crate_type| crate_type.trim()) + .map(ToString::to_string) + .collect::>(); + + for crate_type in &specified_crate_types { + if !KNOWN_CRATE_TYPES.contains(&crate_type.as_str()) { + return IgnoreDecision::Error { + message: format!( + "unknown crate type specified in `needs-crate-type`: `{crate_type}` is not \ + a known crate type, known values are `{:?}`", + KNOWN_CRATE_TYPES + ), + }; + } + } + + let satisfies_all_crate_types = specified_crate_types + .iter() + .all(|specified| config.supported_crate_types().contains(specified)); + if satisfies_all_crate_types { + return IgnoreDecision::Continue; + } else { + return IgnoreDecision::Ignore { + reason: format!( + "skipping test as target does not support all of the crate types `{:?}`", + specified_crate_types + ), + }; + } + } + + if name == "needs-asm-mnemonic" { + let Some(rest) = ln.value_after_colon() else { + return IgnoreDecision::Error { + message: "expected `needs-asm-mnemonic` to have a mnemonic name after colon" + .to_string(), + }; + }; + + if !config.default_codegen_backend.is_llvm() { + return IgnoreDecision::Ignore { + reason: "skipping test as non-LLVM backend does not support mnemonic queries" + .to_string(), + }; + } + + let mnemonic = rest.trim(); + let has_mnemonic = match mnemonic { + "ret" => conditions.has_ret_mnemonic, + "nop" => conditions.has_nop_mnemonic, + _ => has_mnemonic(config, mnemonic), + }; + + if has_mnemonic { + return IgnoreDecision::Continue; + } else { + return IgnoreDecision::Ignore { + reason: format!("skipping test as target does not have `{mnemonic}` mnemonic"), + }; + } + } + + // Handled elsewhere. + if name == "needs-llvm-components" || name == "needs-backends" { + return IgnoreDecision::Continue; + } + + if let Some(need) = conditions.simple_needs.get(name) { + if need.condition { + IgnoreDecision::Continue + } else { + IgnoreDecision::Ignore { + reason: if let Some(comment) = ln.remark_after_space() { + format!("{} ({})", need.ignore_reason, comment.trim()) + } else { + need.ignore_reason.into() + }, + } + } + } else { + IgnoreDecision::Error { message: format!("invalid needs directive: {name}") } + } +} + +struct Need { + name: &'static str, + condition: bool, + ignore_reason: &'static str, +} + +pub(crate) struct PreparedNeedsConditions { + /// The `//@ needs-*` conditions that can be treated as a simple name->boolean mapping. + simple_needs: HashMap<&'static str, Need>, + + /// Might add particular other mnemonics heavily needed by tests here. + /// Otherwise call into llvm for every check + has_ret_mnemonic: bool, + has_nop_mnemonic: bool, +} + +pub(crate) fn prepare_needs_conditions(config: &Config) -> PreparedNeedsConditions { + let target = config.target.as_str(); + let sanitizers = config.target_cfg().sanitizers.as_slice(); + // Note that we intentionally still put the needs- prefix here to make the file show up when // grepping for a directive name, even though we could technically strip that. - let needs = &[ + let simple_needs = vec![ Need { name: "needs-asm-support", condition: config.has_asm_support(), @@ -18,77 +184,77 @@ pub(super) fn handle_needs( }, Need { name: "needs-sanitizer-support", - condition: cache.sanitizer_support, + condition: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(), ignore_reason: "ignored on targets without sanitizers support", }, Need { name: "needs-sanitizer-address", - condition: cache.sanitizer_address, + condition: sanitizers.contains(&Sanitizer::Address), ignore_reason: "ignored on targets without address sanitizer", }, Need { name: "needs-sanitizer-cfi", - condition: cache.sanitizer_cfi, + condition: sanitizers.contains(&Sanitizer::Cfi), ignore_reason: "ignored on targets without CFI sanitizer", }, Need { name: "needs-sanitizer-dataflow", - condition: cache.sanitizer_dataflow, + condition: sanitizers.contains(&Sanitizer::Dataflow), ignore_reason: "ignored on targets without dataflow sanitizer", }, Need { name: "needs-sanitizer-kcfi", - condition: cache.sanitizer_kcfi, + condition: sanitizers.contains(&Sanitizer::Kcfi), ignore_reason: "ignored on targets without kernel CFI sanitizer", }, Need { name: "needs-sanitizer-kasan", - condition: cache.sanitizer_kasan, + condition: sanitizers.contains(&Sanitizer::KernelAddress), ignore_reason: "ignored on targets without kernel address sanitizer", }, Need { name: "needs-sanitizer-khwasan", - condition: cache.sanitizer_khwasan, + condition: sanitizers.contains(&Sanitizer::KernelHwaddress), ignore_reason: "ignored on targets without kernel hardware-assisted address sanitizer", }, Need { name: "needs-sanitizer-leak", - condition: cache.sanitizer_leak, + condition: sanitizers.contains(&Sanitizer::Leak), ignore_reason: "ignored on targets without leak sanitizer", }, Need { name: "needs-sanitizer-memory", - condition: cache.sanitizer_memory, + condition: sanitizers.contains(&Sanitizer::Memory), ignore_reason: "ignored on targets without memory sanitizer", }, Need { name: "needs-sanitizer-thread", - condition: cache.sanitizer_thread, + condition: sanitizers.contains(&Sanitizer::Thread), ignore_reason: "ignored on targets without thread sanitizer", }, Need { name: "needs-sanitizer-hwaddress", - condition: cache.sanitizer_hwaddress, + condition: sanitizers.contains(&Sanitizer::Hwaddress), ignore_reason: "ignored on targets without hardware-assisted address sanitizer", }, Need { name: "needs-sanitizer-memtag", - condition: cache.sanitizer_memtag, + condition: sanitizers.contains(&Sanitizer::Memtag), ignore_reason: "ignored on targets without memory tagging sanitizer", }, Need { name: "needs-sanitizer-realtime", - condition: cache.sanitizer_realtime, + condition: sanitizers.contains(&Sanitizer::Realtime), ignore_reason: "ignored on targets without realtime sanitizer", }, Need { name: "needs-sanitizer-shadow-call-stack", - condition: cache.sanitizer_shadow_call_stack, + condition: sanitizers.contains(&Sanitizer::ShadowCallStack), ignore_reason: "ignored on targets without shadow call stacks", }, Need { name: "needs-sanitizer-safestack", - condition: cache.sanitizer_safestack, + condition: sanitizers.contains(&Sanitizer::Safestack), ignore_reason: "ignored on targets without SafeStack support", }, Need { @@ -133,17 +299,37 @@ pub(super) fn handle_needs( }, Need { name: "needs-xray", - condition: cache.xray, + condition: config.target_cfg().xray, ignore_reason: "ignored on targets without xray tracing", }, Need { name: "needs-rust-lld", - condition: cache.rust_lld, + condition: { + // For tests using the `needs-rust-lld` directive (e.g. for `-Clink-self-contained=+linker`), + // we need to find whether `rust-lld` is present in the compiler under test. + // + // The --compile-lib-path is the path to host shared libraries, but depends on the OS. For + // example: + // - on linux, it can be /lib + // - on windows, it can be /bin + // + // However, `rust-lld` is only located under the lib path, so we look for it there. + config + .host_compile_lib_path + .parent() + .expect("couldn't traverse to the parent of the specified --compile-lib-path") + .join("lib") + .join("rustlib") + .join(target) + .join("bin") + .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" }) + .exists() + }, ignore_reason: "ignored on targets without Rust's LLD", }, Need { name: "needs-dlltool", - condition: cache.dlltool, + condition: find_dlltool(config), ignore_reason: "ignored when dlltool for the current architecture is not present", }, Need { @@ -173,12 +359,12 @@ pub(super) fn handle_needs( }, Need { name: "needs-symlink", - condition: cache.symlinks, + condition: has_symlinks(), ignore_reason: "ignored if symlinks are unavailable", }, Need { name: "needs-llvm-zstd", - condition: cache.llvm_zstd && config.default_codegen_backend.is_llvm(), + condition: config.default_codegen_backend.is_llvm() && llvm_has_zstd(config), ignore_reason: "ignored if LLVM wasn't build with zstd for ELF section compression or LLVM is not the default codegen backend", }, Need { @@ -202,241 +388,20 @@ pub(super) fn handle_needs( ignore_reason: "ignored if target does not support std", }, ]; - - let &DirectiveLine { name, .. } = ln; - - if name == "needs-target-has-atomic" { - let Some(rest) = ln.value_after_colon() else { - return IgnoreDecision::Error { - message: "expected `needs-target-has-atomic` to have a comma-separated list of atomic widths".to_string(), - }; - }; - - // Expect directive value to be a list of comma-separated atomic widths. - let specified_widths = rest - .split(',') - .map(|width| width.trim()) - .map(ToString::to_string) - .collect::>(); - - for width in &specified_widths { - if !KNOWN_TARGET_HAS_ATOMIC_WIDTHS.contains(&width.as_str()) { - return IgnoreDecision::Error { - message: format!( - "unknown width specified in `needs-target-has-atomic`: `{width}` is not a \ - known `target_has_atomic_width`, known values are `{:?}`", - KNOWN_TARGET_HAS_ATOMIC_WIDTHS - ), - }; - } - } - - let satisfies_all_specified_widths = specified_widths - .iter() - .all(|specified| config.target_cfg().target_has_atomic.contains(specified)); - if satisfies_all_specified_widths { - return IgnoreDecision::Continue; - } else { - return IgnoreDecision::Ignore { - reason: format!( - "skipping test as target does not support all of the required `target_has_atomic` widths `{:?}`", - specified_widths - ), - }; - } - } - - // FIXME(jieyouxu): share multi-value directive logic with `needs-target-has-atomic` above. - if name == "needs-crate-type" { - let Some(rest) = ln.value_after_colon() else { - return IgnoreDecision::Error { - message: - "expected `needs-crate-type` to have a comma-separated list of crate types" - .to_string(), - }; - }; - - // Expect directive value to be a list of comma-separated crate-types. - let specified_crate_types = rest - .split(',') - .map(|crate_type| crate_type.trim()) - .map(ToString::to_string) - .collect::>(); - - for crate_type in &specified_crate_types { - if !KNOWN_CRATE_TYPES.contains(&crate_type.as_str()) { - return IgnoreDecision::Error { - message: format!( - "unknown crate type specified in `needs-crate-type`: `{crate_type}` is not \ - a known crate type, known values are `{:?}`", - KNOWN_CRATE_TYPES - ), - }; - } - } - - let satisfies_all_crate_types = specified_crate_types - .iter() - .all(|specified| config.supported_crate_types().contains(specified)); - if satisfies_all_crate_types { - return IgnoreDecision::Continue; - } else { - return IgnoreDecision::Ignore { - reason: format!( - "skipping test as target does not support all of the crate types `{:?}`", - specified_crate_types - ), - }; - } - } - - if name == "needs-asm-mnemonic" { - let Some(rest) = ln.value_after_colon() else { - return IgnoreDecision::Error { - message: "expected `needs-asm-mnemonic` to have a mnemonic name after colon" - .to_string(), - }; - }; - - if !config.default_codegen_backend.is_llvm() { - return IgnoreDecision::Ignore { - reason: "skipping test as non-LLVM backend does not support mnemonic queries" - .to_string(), - }; - } - - let mnemonic = rest.trim(); - let has_mnemonic = match mnemonic { - "ret" => cache.has_ret_mnemonic, - "nop" => cache.has_nop_mnemonic, - _ => has_mnemonic(config, mnemonic), - }; - - if has_mnemonic { - return IgnoreDecision::Continue; - } else { - return IgnoreDecision::Ignore { - reason: format!("skipping test as target does not have `{mnemonic}` mnemonic"), - }; - } - } - - if !name.starts_with("needs-") { - return IgnoreDecision::Continue; - } - - // Handled elsewhere. - if name == "needs-llvm-components" || name == "needs-backends" { - return IgnoreDecision::Continue; - } - - let mut found_valid = false; - for need in needs { - if need.name == name { - if need.condition { - found_valid = true; - break; - } else { - return IgnoreDecision::Ignore { - reason: if let Some(comment) = ln.remark_after_space() { - format!("{} ({})", need.ignore_reason, comment.trim()) - } else { - need.ignore_reason.into() - }, - }; - } - } - } - - if found_valid { - IgnoreDecision::Continue - } else { - IgnoreDecision::Error { message: format!("invalid needs directive: {name}") } - } -} - -struct Need { - name: &'static str, - condition: bool, - ignore_reason: &'static str, -} - -pub(super) struct CachedNeedsConditions { - sanitizer_support: bool, - sanitizer_address: bool, - sanitizer_cfi: bool, - sanitizer_dataflow: bool, - sanitizer_kcfi: bool, - sanitizer_kasan: bool, - sanitizer_khwasan: bool, - sanitizer_leak: bool, - sanitizer_memory: bool, - sanitizer_thread: bool, - sanitizer_hwaddress: bool, - sanitizer_memtag: bool, - sanitizer_realtime: bool, - sanitizer_shadow_call_stack: bool, - sanitizer_safestack: bool, - xray: bool, - rust_lld: bool, - dlltool: bool, - symlinks: bool, - /// Whether LLVM built with zstd, for the `needs-llvm-zstd` directive. - llvm_zstd: bool, - /// Might add particular other mnemonics heavily needed by tests here. - /// Otherwise call into llvm for every check - has_ret_mnemonic: bool, - has_nop_mnemonic: bool, -} - -impl CachedNeedsConditions { - pub(super) fn load(config: &Config) -> Self { - let target = &&*config.target; - let sanitizers = &config.target_cfg().sanitizers; - Self { - sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(), - sanitizer_address: sanitizers.contains(&Sanitizer::Address), - sanitizer_cfi: sanitizers.contains(&Sanitizer::Cfi), - sanitizer_dataflow: sanitizers.contains(&Sanitizer::Dataflow), - sanitizer_kcfi: sanitizers.contains(&Sanitizer::Kcfi), - sanitizer_kasan: sanitizers.contains(&Sanitizer::KernelAddress), - sanitizer_khwasan: sanitizers.contains(&Sanitizer::KernelHwaddress), - sanitizer_leak: sanitizers.contains(&Sanitizer::Leak), - sanitizer_memory: sanitizers.contains(&Sanitizer::Memory), - sanitizer_thread: sanitizers.contains(&Sanitizer::Thread), - sanitizer_hwaddress: sanitizers.contains(&Sanitizer::Hwaddress), - sanitizer_memtag: sanitizers.contains(&Sanitizer::Memtag), - sanitizer_realtime: sanitizers.contains(&Sanitizer::Realtime), - sanitizer_shadow_call_stack: sanitizers.contains(&Sanitizer::ShadowCallStack), - sanitizer_safestack: sanitizers.contains(&Sanitizer::Safestack), - xray: config.target_cfg().xray, - - // For tests using the `needs-rust-lld` directive (e.g. for `-Clink-self-contained=+linker`), - // we need to find whether `rust-lld` is present in the compiler under test. - // - // The --compile-lib-path is the path to host shared libraries, but depends on the OS. For - // example: - // - on linux, it can be /lib - // - on windows, it can be /bin - // - // However, `rust-lld` is only located under the lib path, so we look for it there. - rust_lld: config - .host_compile_lib_path - .parent() - .expect("couldn't traverse to the parent of the specified --compile-lib-path") - .join("lib") - .join("rustlib") - .join(target) - .join("bin") - .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" }) - .exists(), - - llvm_zstd: llvm_has_zstd(&config), - dlltool: find_dlltool(&config), - symlinks: has_symlinks(), - has_ret_mnemonic: has_mnemonic(config, "ret"), - has_nop_mnemonic: has_mnemonic(config, "nop"), - } + let simple_needs = simple_needs + .into_iter() + .map(|need| { + let name = need.name; + assert!(name.starts_with("needs-"), "must start with `needs-`: {name:?}"); + assert!(KNOWN_DIRECTIVE_NAMES_SET.contains(name), "unknown directive name: {name:?}"); + (name, need) + }) + .collect::>(); + + PreparedNeedsConditions { + simple_needs, + has_ret_mnemonic: has_mnemonic(config, "ret"), + has_nop_mnemonic: has_mnemonic(config, "nop"), } } diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index abe26ca91e5d8..55f2f552ad31c 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -6,7 +6,7 @@ #![feature(asm_unwind, linkage, rustc_attrs, cfg_target_object_format)] #![crate_type = "lib"] -use std::arch::{asm, global_asm, naked_asm}; +use std::arch::{asm, naked_asm}; #[unsafe(naked)] pub extern "C" fn inline_asm_macro() { @@ -14,12 +14,6 @@ pub extern "C" fn inline_asm_macro() { //~^ERROR the `asm!` macro is not allowed in naked functions } -#[unsafe(naked)] -pub extern "C" fn global_asm_macro() { - //~^ERROR naked functions must contain a single `naked_asm!` invocation - global_asm!(""); -} - #[repr(C)] pub struct P { x: u8, diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index e8963f7e1d52c..2b67c3aecd73c 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -1,71 +1,71 @@ error: the `in` operand cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:53:29 + --> $DIR/naked-functions.rs:47:29 | LL | naked_asm!("/* {0} */", in(reg) a) | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it error: the `in` operand cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:74:10 + --> $DIR/naked-functions.rs:68:10 | LL | in(reg) a, | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it error: the `noreturn` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:94:28 + --> $DIR/naked-functions.rs:88:28 | LL | naked_asm!("", options(noreturn)); | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly error: the `nomem` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:111:28 + --> $DIR/naked-functions.rs:105:28 | LL | naked_asm!("", options(nomem, preserves_flags)); | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly error: the `preserves_flags` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:111:35 + --> $DIR/naked-functions.rs:105:35 | LL | naked_asm!("", options(nomem, preserves_flags)); | ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly error: the `readonly` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:118:28 + --> $DIR/naked-functions.rs:112:28 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly error: the `nostack` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:118:38 + --> $DIR/naked-functions.rs:112:38 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly error: the `pure` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:118:56 + --> $DIR/naked-functions.rs:112:56 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^ the `pure` option is not meaningful for global-scoped inline assembly error: the `may_unwind` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:126:28 + --> $DIR/naked-functions.rs:120:28 | LL | naked_asm!("", options(may_unwind)); | ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly error: this is a user specified error - --> $DIR/naked-functions.rs:157:5 + --> $DIR/naked-functions.rs:151:5 | LL | compile_error!("this is a user specified error") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:163:5 + --> $DIR/naked-functions.rs:157:5 | LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:170:16 + --> $DIR/naked-functions.rs:164:16 | LL | naked_asm!(invalid_syntax) | ^^^^^^^^^^^^^^ @@ -76,38 +76,32 @@ error[E0787]: the `asm!` macro is not allowed in naked functions LL | unsafe { asm!("", options(raw)) }; | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead -error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:18:1 - | -LL | pub extern "C" fn global_asm_macro() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:31:5 + --> $DIR/naked-functions.rs:25:5 | LL | mut a: u32, | ^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:33:5 + --> $DIR/naked-functions.rs:27:5 | LL | &b: &i32, | ^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:35:6 + --> $DIR/naked-functions.rs:29:6 | LL | (None | Some(_)): Option>, | ^^^^^^^^^^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:37:5 + --> $DIR/naked-functions.rs:31:5 | LL | P { x, y }: P, | ^^^^^^^^^^ error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:46:5 + --> $DIR/naked-functions.rs:40:5 | LL | a + 1 | ^ @@ -115,7 +109,7 @@ LL | a + 1 = help: follow the calling convention in asm block to use parameters error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:44:1 + --> $DIR/naked-functions.rs:38:1 | LL | pub extern "C" fn inc(a: u32) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,7 +118,7 @@ LL | a + 1 | ----- not allowed in naked functions error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:58:1 + --> $DIR/naked-functions.rs:52:1 | LL | pub extern "C" fn inc_closure(a: u32) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +127,7 @@ LL | (|| a + 1)() | ------------ not allowed in naked functions error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:64:1 + --> $DIR/naked-functions.rs:58:1 | LL | pub extern "C" fn unsupported_operands() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -150,13 +144,13 @@ LL | let mut e = 0usize; | ------------------- not allowed in naked functions error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:86:1 + --> $DIR/naked-functions.rs:80:1 | LL | pub extern "C" fn missing_assembly() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:91:1 + --> $DIR/naked-functions.rs:85:1 | LL | pub extern "C" fn too_many_asm_blocks() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +159,7 @@ LL | naked_asm!(""); | -------------- multiple `naked_asm!` invocations are not allowed in naked functions error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:103:11 + --> $DIR/naked-functions.rs:97:11 | LL | *&y | ^ @@ -173,7 +167,7 @@ LL | *&y = help: follow the calling convention in asm block to use parameters error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:101:5 + --> $DIR/naked-functions.rs:95:5 | LL | pub extern "C" fn inner(y: usize) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,6 +175,6 @@ LL | LL | *&y | --- not allowed in naked functions -error: aborting due to 26 previous errors +error: aborting due to 25 previous errors For more information about this error, try `rustc --explain E0787`. diff --git a/tests/ui/asm/statement-global-asm-error.rs b/tests/ui/asm/statement-global-asm-error.rs deleted file mode 100644 index f32ba73357a19..0000000000000 --- a/tests/ui/asm/statement-global-asm-error.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ needs-asm-support - -use std::arch::global_asm; - -fn main() { - let x = 42; - global_asm!("{}", in(x)); - //~^ ERROR the `in` operand cannot be used with `global_asm!` - //~^^ NOTE the `in` operand is not meaningful for global-scoped inline assembly, remove it - - let y = global_asm!(""); - //~^ ERROR non-expression macro in expression position: global_asm -} diff --git a/tests/ui/asm/statement-global-asm-error.stderr b/tests/ui/asm/statement-global-asm-error.stderr deleted file mode 100644 index 35dde6ac1a781..0000000000000 --- a/tests/ui/asm/statement-global-asm-error.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: the `in` operand cannot be used with `global_asm!` - --> $DIR/statement-global-asm-error.rs:7:23 - | -LL | global_asm!("{}", in(x)); - | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it - -error: non-expression macro in expression position: global_asm - --> $DIR/statement-global-asm-error.rs:11:13 - | -LL | let y = global_asm!(""); - | ^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/asm/statement-global-asm.rs b/tests/ui/asm/statement-global-asm.rs deleted file mode 100644 index 597495546d955..0000000000000 --- a/tests/ui/asm/statement-global-asm.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ needs-asm-support -//@ run-pass - -use std::arch::global_asm; - -fn main() { - global_asm!(""); -} diff --git a/tests/ui/lint/unused/unused-variable-with-raw-identifier-in-struct-pattern.fixed b/tests/ui/lint/unused/unused-variable-with-raw-identifier-in-struct-pattern.fixed new file mode 100644 index 0000000000000..9e188cfdcc0e3 --- /dev/null +++ b/tests/ui/lint/unused/unused-variable-with-raw-identifier-in-struct-pattern.fixed @@ -0,0 +1,19 @@ +//@ check-pass +//@ run-rustfix + +#![warn(unused)] +#![allow(dead_code)] + +struct Foo { + r#move: u32 +} + +fn main() { + let y = Foo { r#move: 3 }; + + let _ = match y { + Foo { r#move: _ } => 0 //~ WARNING unused variable: `r#move` + //~| HELP try ignoring the field + //~| SUGGESTION r#move: _ + }; +} diff --git a/tests/ui/lint/unused/unused-variable-with-raw-identifier-in-struct-pattern.rs b/tests/ui/lint/unused/unused-variable-with-raw-identifier-in-struct-pattern.rs new file mode 100644 index 0000000000000..514ba4f7df418 --- /dev/null +++ b/tests/ui/lint/unused/unused-variable-with-raw-identifier-in-struct-pattern.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ run-rustfix + +#![warn(unused)] +#![allow(dead_code)] + +struct Foo { + r#move: u32 +} + +fn main() { + let y = Foo { r#move: 3 }; + + let _ = match y { + Foo { r#move } => 0 //~ WARNING unused variable: `r#move` + //~| HELP try ignoring the field + //~| SUGGESTION r#move: _ + }; +} diff --git a/tests/ui/lint/unused/unused-variable-with-raw-identifier-in-struct-pattern.stderr b/tests/ui/lint/unused/unused-variable-with-raw-identifier-in-struct-pattern.stderr new file mode 100644 index 0000000000000..0f96605651616 --- /dev/null +++ b/tests/ui/lint/unused/unused-variable-with-raw-identifier-in-struct-pattern.stderr @@ -0,0 +1,15 @@ +warning: unused variable: `r#move` + --> $DIR/unused-variable-with-raw-identifier-in-struct-pattern.rs:15:16 + | +LL | Foo { r#move } => 0 + | ^^^^^^ help: try ignoring the field: `r#move: _` + | +note: the lint level is defined here + --> $DIR/unused-variable-with-raw-identifier-in-struct-pattern.rs:4:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: 1 warning emitted + diff --git a/tests/ui/typeck/suggestions/auxiliary/suggest-compatible-variants-macro-issue-142359.rs b/tests/ui/typeck/suggestions/auxiliary/suggest-compatible-variants-macro-issue-142359.rs new file mode 100644 index 0000000000000..a94f6244b17e7 --- /dev/null +++ b/tests/ui/typeck/suggestions/auxiliary/suggest-compatible-variants-macro-issue-142359.rs @@ -0,0 +1,6 @@ +#[macro_export] +macro_rules! unit { + () => {{ + () + }}; +} diff --git a/tests/ui/typeck/suggestions/suggest-compatible-variants-macro-issue-142359.rs b/tests/ui/typeck/suggestions/suggest-compatible-variants-macro-issue-142359.rs new file mode 100644 index 0000000000000..f84ebd6f9ea50 --- /dev/null +++ b/tests/ui/typeck/suggestions/suggest-compatible-variants-macro-issue-142359.rs @@ -0,0 +1,16 @@ +// Make sure we don't suggest compatible variants cross macro context. (issue #142359) +//@ aux-crate:ext=suggest-compatible-variants-macro-issue-142359.rs + +extern crate ext; + +use std::ops::ControlFlow; + +fn main() { + let x: Result = Err(1); + + let _ = match x { + Err(r) => ControlFlow::Break(r), + Ok(r) => { ext::unit!() } //~ ERROR `match` arms have incompatible types [E0308] + + }; +} diff --git a/tests/ui/typeck/suggestions/suggest-compatible-variants-macro-issue-142359.stderr b/tests/ui/typeck/suggestions/suggest-compatible-variants-macro-issue-142359.stderr new file mode 100644 index 0000000000000..7344060a91e4e --- /dev/null +++ b/tests/ui/typeck/suggestions/suggest-compatible-variants-macro-issue-142359.stderr @@ -0,0 +1,24 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/suggest-compatible-variants-macro-issue-142359.rs:13:20 + | +LL | let _ = match x { + | _____________- +LL | | Err(r) => ControlFlow::Break(r), + | | --------------------- this is found to be of type `ControlFlow` +LL | | Ok(r) => { ext::unit!() } + | | ^^^^^^^^^^^^ expected `ControlFlow`, found `()` +LL | | +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected enum `ControlFlow` + found unit type `()` + = note: this error originates in the macro `ext::unit` (in Nightly builds, run with -Z macro-backtrace for more info) +help: try wrapping the expression in `std::ops::ControlFlow::Continue` + | +LL | Ok(r) => std::ops::ControlFlow::Continue({ ext::unit!() }) + | ++++++++++++++++++++++++++++++++ + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`.