From 5601490c9d889ff8d964d4aafd44dcdeea40bfef Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Wed, 15 Jan 2025 20:43:02 +0700 Subject: [PATCH 01/14] -Zretpoline and -Zretpoline-external-thunk flags (target modifiers) to enable retpoline-related target features --- compiler/rustc_codegen_gcc/messages.ftl | 7 --- compiler/rustc_codegen_gcc/src/errors.rs | 15 ----- compiler/rustc_codegen_gcc/src/gcc_util.rs | 27 ++++----- compiler/rustc_codegen_llvm/messages.ftl | 9 --- compiler/rustc_codegen_llvm/src/errors.rs | 17 ------ compiler/rustc_codegen_llvm/src/llvm_util.rs | 25 ++++---- .../rustc_codegen_ssa/src/target_features.rs | 3 +- compiler/rustc_session/messages.ftl | 8 +++ compiler/rustc_session/src/config.rs | 9 +++ compiler/rustc_session/src/errors.rs | 17 ++++++ compiler/rustc_session/src/features.rs | 59 +++++++++++++++++++ compiler/rustc_session/src/lib.rs | 1 + compiler/rustc_session/src/options.rs | 13 ++++ compiler/rustc_target/src/target_features.rs | 39 ++++++++---- src/librustdoc/json/mod.rs | 5 +- tests/codegen/retpoline.rs | 29 +++++++++ tests/ui/check-cfg/target_feature.stderr | 3 + ...line-target-feature-flag.by_feature.stderr | 7 +++ ...ine-target-feature-flag.by_feature1.stderr | 7 +++ ...ine-target-feature-flag.by_feature2.stderr | 7 +++ ...ine-target-feature-flag.by_feature3.stderr | 7 +++ .../retpoline-target-feature-flag.rs | 23 ++++++++ 22 files changed, 244 insertions(+), 93 deletions(-) create mode 100644 compiler/rustc_session/src/features.rs create mode 100644 tests/codegen/retpoline.rs create mode 100644 tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr create mode 100644 tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr create mode 100644 tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr create mode 100644 tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr create mode 100644 tests/ui/target-feature/retpoline-target-feature-flag.rs diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl index 546bfc87b689c..18a8a5a1e048a 100644 --- a/compiler/rustc_codegen_gcc/messages.ftl +++ b/compiler/rustc_codegen_gcc/messages.ftl @@ -2,9 +2,6 @@ codegen_gcc_unknown_ctarget_feature_prefix = unknown feature specified for `-Ctarget-feature`: `{$feature}` .note = features must begin with a `+` to enable or `-` to disable it -codegen_gcc_forbidden_ctarget_feature = - target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason} - codegen_gcc_unwinding_inline_asm = GCC backend does not support unwinding from inline asm @@ -26,10 +23,6 @@ codegen_gcc_unknown_ctarget_feature = .possible_feature = you might have meant: `{$rust_feature}` .consider_filing_feature_request = consider filing a feature request -codegen_gcc_unstable_ctarget_feature = - unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = this feature is not stably supported; its behavior can change in the future - codegen_gcc_missing_features = add the missing features in a `target_feature` attribute diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index ccd9abe380491..7786be9ae5de9 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -17,21 +17,6 @@ pub(crate) struct UnknownCTargetFeature<'a> { pub rust_feature: PossibleFeature<'a>, } -#[derive(Diagnostic)] -#[diag(codegen_gcc_unstable_ctarget_feature)] -#[note] -pub(crate) struct UnstableCTargetFeature<'a> { - pub feature: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_gcc_forbidden_ctarget_feature)] -pub(crate) struct ForbiddenCTargetFeature<'a> { - pub feature: &'a str, - pub enabled: &'a str, - pub reason: &'a str, -} - #[derive(Subdiagnostic)] pub(crate) enum PossibleFeature<'a> { #[help(codegen_gcc_possible_feature)] diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 2b053abdd190a..d90e66aea31ee 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -5,13 +5,17 @@ use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; use rustc_session::Session; +use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use smallvec::{SmallVec, smallvec}; -use crate::errors::{ - ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix, - UnstableCTargetFeature, -}; +use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix}; + +fn gcc_features_by_flags(sess: &Session) -> Vec<&str> { + let mut features: Vec<&str> = Vec::new(); + retpoline_features_by_flags(sess, &mut features); + features +} /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). @@ -45,7 +49,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec Vec { - if let Err(reason) = stability.toggle_allowed() { - sess.dcx().emit_warn(ForbiddenCTargetFeature { - feature, - enabled: if enable { "enabled" } else { "disabled" }, - reason, - }); - } else if stability.requires_nightly().is_some() { - // An unstable feature. Warn about using it. (It makes little sense - // to hard-error here since we just warn about fully unknown - // features above). - sess.dcx().emit_warn(UnstableCTargetFeature { feature }); - } + stability.verify_feature_enabled_by_flag(sess, enable, feature); } } diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index bda121c67fb62..3faeb9b3b221b 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -10,11 +10,6 @@ codegen_llvm_dynamic_linking_with_lto = codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture -codegen_llvm_forbidden_ctarget_feature = - target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason} - .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 - codegen_llvm_from_llvm_diag = {$message} codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message} @@ -76,10 +71,6 @@ codegen_llvm_unknown_ctarget_feature_prefix = codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo -codegen_llvm_unstable_ctarget_feature = - unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = this feature is not stably supported; its behavior can change in the future - codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err} codegen_llvm_write_ir = failed to write LLVM IR to {$path} diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index eaafc68071291..8bc74fbec7ece 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -24,23 +24,6 @@ pub(crate) struct UnknownCTargetFeature<'a> { pub rust_feature: PossibleFeature<'a>, } -#[derive(Diagnostic)] -#[diag(codegen_llvm_unstable_ctarget_feature)] -#[note] -pub(crate) struct UnstableCTargetFeature<'a> { - pub feature: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_llvm_forbidden_ctarget_feature)] -#[note] -#[note(codegen_llvm_forbidden_ctarget_feature_issue)] -pub(crate) struct ForbiddenCTargetFeature<'a> { - pub feature: &'a str, - pub enabled: &'a str, - pub reason: &'a str, -} - #[derive(Subdiagnostic)] pub(crate) enum PossibleFeature<'a> { #[help(codegen_llvm_possible_feature)] diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 9718c95f38a88..0e77bc43df805 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -16,6 +16,7 @@ use rustc_fs_util::path_to_c_string; use rustc_middle::bug; use rustc_session::Session; use rustc_session::config::{PrintKind, PrintRequest}; +use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; use rustc_span::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport}; use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES}; @@ -23,8 +24,7 @@ use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; use crate::errors::{ - FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, - UnknownCTargetFeaturePrefix, UnstableCTargetFeature, + FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix, }; use crate::llvm; @@ -707,6 +707,12 @@ pub(crate) fn target_cpu(sess: &Session) -> &str { handle_native(cpu_name) } +fn llvm_features_by_flags(sess: &Session) -> Vec<&str> { + let mut features: Vec<&str> = Vec::new(); + retpoline_features_by_flags(sess, &mut features); + features +} + /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). pub(crate) fn global_llvm_features( @@ -787,7 +793,7 @@ pub(crate) fn global_llvm_features( // Compute implied features let mut all_rust_features = vec![]; - for feature in sess.opts.cg.target_feature.split(',') { + for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) { if let Some(feature) = feature.strip_prefix('+') { all_rust_features.extend( UnordSet::from(sess.target.implied_target_features(feature)) @@ -840,18 +846,7 @@ pub(crate) fn global_llvm_features( sess.dcx().emit_warn(unknown_feature); } Some((_, stability, _)) => { - if let Err(reason) = stability.toggle_allowed() { - sess.dcx().emit_warn(ForbiddenCTargetFeature { - feature, - enabled: if enable { "enabled" } else { "disabled" }, - reason, - }); - } else if stability.requires_nightly().is_some() { - // An unstable feature. Warn about using it. It makes little sense - // to hard-error here since we just warn about fully unknown - // features above. - sess.dcx().emit_warn(UnstableCTargetFeature { feature }); - } + stability.verify_feature_enabled_by_flag(sess, enable, feature); } } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 6bb3150c1c57d..640d197c219a8 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -8,6 +8,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; +use rustc_session::features::StabilityExt; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; @@ -66,7 +67,7 @@ pub(crate) fn from_target_feature_attr( // Only allow target features whose feature gates have been enabled // and which are permitted to be toggled. - if let Err(reason) = stability.toggle_allowed() { + if let Err(reason) = stability.is_toggle_permitted(tcx.sess) { tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { span: item.span(), feature, diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 528c52eace7cb..61953614c77e1 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -40,6 +40,11 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it session_file_write_fail = failed to write `{$path}` due to error `{$err}` +session_forbidden_ctarget_feature = + target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason} + .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +session_forbidden_ctarget_feature_issue = for more information, see issue #116344 + session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models @@ -132,6 +137,9 @@ session_target_stack_protector_not_supported = `-Z stack-protector={$stack_prote session_unleashed_feature_help_named = skipping check for `{$gate}` feature session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate +session_unstable_ctarget_feature = + unstable feature specified for `-Ctarget-feature`: `{$feature}` + .note = this feature is not stably supported; its behavior can change in the future session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` session_unsupported_crate_type_for_target = diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 60e1b465ba96d..8984634e5ec62 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2649,6 +2649,15 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let prints = collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches); + // -Zretpoline-external-thunk also requires -Zretpoline + if unstable_opts.retpoline_external_thunk { + unstable_opts.retpoline = true; + target_modifiers.insert( + OptionsTargetModifiers::UnstableOptions(UnstableOptionsTargetModifiers::retpoline), + "true".to_string(), + ); + } + let cg = cg; let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m)); diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index bf95014843d23..9c591dcf619a5 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -501,3 +501,20 @@ pub(crate) struct SoftFloatIgnored; #[note] #[note(session_soft_float_deprecated_issue)] pub(crate) struct SoftFloatDeprecated; + +#[derive(Diagnostic)] +#[diag(session_forbidden_ctarget_feature)] +#[note] +#[note(session_forbidden_ctarget_feature_issue)] +pub(crate) struct ForbiddenCTargetFeature<'a> { + pub feature: &'a str, + pub enabled: &'a str, + pub reason: &'a str, +} + +#[derive(Diagnostic)] +#[diag(session_unstable_ctarget_feature)] +#[note] +pub(crate) struct UnstableCTargetFeature<'a> { + pub feature: &'a str, +} diff --git a/compiler/rustc_session/src/features.rs b/compiler/rustc_session/src/features.rs new file mode 100644 index 0000000000000..70a088a236f7e --- /dev/null +++ b/compiler/rustc_session/src/features.rs @@ -0,0 +1,59 @@ +use rustc_target::target_features::Stability; + +use crate::Session; +use crate::errors::{ForbiddenCTargetFeature, UnstableCTargetFeature}; + +pub trait StabilityExt { + /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`. + /// Otherwise, some features also may only be enabled by flag (target modifier). + /// (It might still be nightly-only even if this returns `true`, so make sure to also check + /// `requires_nightly`.) + fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str>; + + /// Check that feature is correctly enabled/disabled by command line flag (emits warnings) + fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str); +} + +impl StabilityExt for Stability { + fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str> { + match self { + Stability::Forbidden { reason } => Err(reason), + Stability::TargetModifierOnly { reason, flag } => { + if !sess.opts.target_feature_flag_enabled(*flag) { Err(reason) } else { Ok(()) } + } + _ => Ok(()), + } + } + fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str) { + if let Err(reason) = self.is_toggle_permitted(sess) { + sess.dcx().emit_warn(ForbiddenCTargetFeature { + feature, + enabled: if enable { "enabled" } else { "disabled" }, + reason, + }); + } else if self.requires_nightly().is_some() { + // An unstable feature. Warn about using it. It makes little sense + // to hard-error here since we just warn about fully unknown + // features above. + sess.dcx().emit_warn(UnstableCTargetFeature { feature }); + } + } +} + +pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<&str>) { + // -Zretpoline without -Zretpoline-external-thunk enables + // retpoline-indirect-branches and retpoline-indirect-calls target features + let unstable_opts = &sess.opts.unstable_opts; + if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk { + features.push("+retpoline-indirect-branches"); + features.push("+retpoline-indirect-calls"); + } + // -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables + // retpoline-external-thunk, retpoline-indirect-branches and + // retpoline-indirect-calls target features + if unstable_opts.retpoline_external_thunk { + features.push("+retpoline-external-thunk"); + features.push("+retpoline-indirect-branches"); + features.push("+retpoline-indirect-calls"); + } +} diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 5e5872ee06815..4added19e56e7 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -29,6 +29,7 @@ pub use session::*; pub mod output; pub use getopts; +pub mod features; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 12fa05118caf5..7da48830b6af3 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -290,6 +290,14 @@ macro_rules! top_level_options { mods.sort_by(|a, b| a.opt.cmp(&b.opt)); mods } + + pub fn target_feature_flag_enabled(&self, flag: &str) -> bool { + match flag { + "retpoline" => self.unstable_opts.retpoline, + "retpoline-external-thunk" => self.unstable_opts.retpoline_external_thunk, + _ => false, + } + } } ); } @@ -2446,6 +2454,11 @@ options! { remark_dir: Option = (None, parse_opt_pathbuf, [UNTRACKED], "directory into which to write optimization remarks (if not specified, they will be \ written to standard error output)"), + retpoline: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "enables retpoline-indirect-branches and retpoline-indirect-calls target features (default: no)"), + retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \ + target features (default: no)"), sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], "use a sanitizer"), sanitizer_cfi_canonical_jump_tables: Option = (Some(true), parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index c1f128fdc87a4..06a6f6a4383c8 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -34,6 +34,9 @@ pub enum Stability { /// particular for features are actually ABI configuration flags (not all targets are as nice as /// RISC-V and have an explicit way to set the ABI separate from target features). Forbidden { reason: &'static str }, + /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be set + /// by target modifier flag. Target modifier flags are tracked to be consistent in linked modules. + TargetModifierOnly { reason: &'static str, flag: &'static str }, } use Stability::*; @@ -49,6 +52,7 @@ impl HashStable for Stability { Stability::Forbidden { reason } => { reason.hash_stable(hcx, hasher); } + Stability::TargetModifierOnly { .. } => {} } } } @@ -74,16 +78,7 @@ impl Stability { Stability::Unstable(nightly_feature) => Some(nightly_feature), Stability::Stable { .. } => None, Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"), - } - } - - /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`. - /// (It might still be nightly-only even if this returns `true`, so make sure to also check - /// `requires_nightly`.) - pub fn toggle_allowed(&self) -> Result<(), &'static str> { - match self { - Stability::Forbidden { reason } => Err(reason), - _ => Ok(()), + Stability::TargetModifierOnly { .. } => None, } } } @@ -453,6 +448,30 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("prfchw", Unstable(sym::prfchw_target_feature), &[]), ("rdrand", Stable, &[]), ("rdseed", Stable, &[]), + ( + "retpoline-external-thunk", + Stability::TargetModifierOnly { + reason: "use `retpoline-external-thunk` target modifier flag instead", + flag: "retpoline-external-thunk", + }, + &[], + ), + ( + "retpoline-indirect-branches", + Stability::TargetModifierOnly { + reason: "use `retpoline` target modifier flag instead", + flag: "retpoline", + }, + &[], + ), + ( + "retpoline-indirect-calls", + Stability::TargetModifierOnly { + reason: "use `retpoline` target modifier flag instead", + flag: "retpoline", + }, + &[], + ), ("rtm", Unstable(sym::rtm_target_feature), &[]), ("sha", Stable, &["sse2"]), ("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]), diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 131a12ce228f7..0ceeea2b9b1b4 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -18,6 +18,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_session::features::StabilityExt; use rustc_span::def_id::LOCAL_CRATE; use rustdoc_json_types as types; // It's important to use the FxHashMap from rustdoc_json_types here, instead of @@ -148,7 +149,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { .copied() .filter(|(_, stability, _)| { // Describe only target features which the user can toggle - stability.toggle_allowed().is_ok() + stability.is_toggle_permitted(sess).is_ok() }) .map(|(name, stability, implied_features)| { types::TargetFeature { @@ -164,7 +165,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { // Imply only target features which the user can toggle feature_stability .get(name) - .map(|stability| stability.toggle_allowed().is_ok()) + .map(|stability| stability.is_toggle_permitted(sess).is_ok()) .unwrap_or(false) }) .map(String::from) diff --git a/tests/codegen/retpoline.rs b/tests/codegen/retpoline.rs new file mode 100644 index 0000000000000..30fdd9c2db2c0 --- /dev/null +++ b/tests/codegen/retpoline.rs @@ -0,0 +1,29 @@ +// ignore-tidy-linelength +// Test that the +// `retpoline-external-thunk`, `retpoline-indirect-branches`, `retpoline-indirect-calls` +// target features are (not) emitted when the `retpoline/retpoline-external-thunk` flag is (not) set. + +//@ revisions: disabled enabled_retpoline enabled_retpoline_external_thunk +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ [enabled_retpoline] compile-flags: -Zretpoline +//@ [enabled_retpoline_external_thunk] compile-flags: -Zretpoline-external-thunk + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk{{.*}} } + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches{{.*}} } + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-calls{{.*}} } + + // enabled_retpoline: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } + // enabled_retpoline_external_thunk: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk,+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } +} diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index ec81ba2e3d89f..f29a41d6a8e28 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -212,6 +212,9 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `relax` `relaxed-simd` `reserve-x18` +`retpoline-external-thunk` +`retpoline-indirect-branches` +`retpoline-indirect-calls` `rtm` `sb` `scq` diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr new file mode 100644 index 0000000000000..e2b6078b7a8c9 --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr @@ -0,0 +1,7 @@ +warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `x86-retpoline` target modifier flag instead + | + = note: 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 #116344 + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr new file mode 100644 index 0000000000000..2a0f5f01aef6f --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr @@ -0,0 +1,7 @@ +warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead + | + = note: 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 #116344 + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr new file mode 100644 index 0000000000000..f7b6cb1644778 --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr @@ -0,0 +1,7 @@ +warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead + | + = note: 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 #116344 + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr new file mode 100644 index 0000000000000..4f2cd1d1a522f --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr @@ -0,0 +1,7 @@ +warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead + | + = note: 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 #116344 + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.rs b/tests/ui/target-feature/retpoline-target-feature-flag.rs new file mode 100644 index 0000000000000..3e614a4236c03 --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.rs @@ -0,0 +1,23 @@ +//@ revisions: by_flag by_feature1 by_feature2 by_feature3 +//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib +//@ needs-llvm-components: x86 +//@ [by_flag]compile-flags: -Zretpoline + +//@ [by_feature1]compile-flags: -Ctarget-feature=+retpoline-external-thunk +//@ [by_feature2]compile-flags: -Ctarget-feature=+retpoline-indirect-branches +//@ [by_feature3]compile-flags: -Ctarget-feature=+retpoline-indirect-calls +//@ [by_flag]build-pass +// For now this is just a warning. +//@ [by_feature1]build-pass +//@ [by_feature2]build-pass +//@ [by_feature3]build-pass +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead +//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead +//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead From ff8b11e02a660b2d1eccc96c3a6cc1acbc61cc70 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 9 Jun 2025 13:40:20 -0700 Subject: [PATCH 02/14] assert in release in ast_lowering::item --- compiler/rustc_ast_lowering/src/item.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index d1a2ddbdb3477..e2d291a536da8 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -63,7 +63,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { for (def_id, info) in lctx.children { let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); - debug_assert!( + assert!( matches!(owner, hir::MaybeOwner::Phantom), "duplicate copy of {def_id:?} in lctx.children" ); @@ -78,7 +78,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { match node { AstOwner::NonOwner => {} AstOwner::Crate(c) => { - debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); + assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); // FIXME(jdonszelman): is dummy span ever a problem here? @@ -1160,7 +1160,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::BodyId { let body = hir::Body { params, value: self.arena.alloc(value) }; let id = body.id(); - debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner); + assert_eq!(id.hir_id.owner, self.current_hir_id_owner); self.bodies.push((id.hir_id.local_id, self.arena.alloc(body))); id } @@ -1673,8 +1673,8 @@ impl<'hir> LoweringContext<'_, 'hir> { itctx: ImplTraitContext, f: impl FnOnce(&mut Self) -> T, ) -> (&'hir hir::Generics<'hir>, T) { - debug_assert!(self.impl_trait_defs.is_empty()); - debug_assert!(self.impl_trait_bounds.is_empty()); + assert!(self.impl_trait_defs.is_empty()); + assert!(self.impl_trait_bounds.is_empty()); // Error if `?Trait` bounds in where clauses don't refer directly to type parameters. // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering From dd78c95c54a0850571ec6ed82da2f8bb888de545 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 9 Jun 2025 13:40:40 -0700 Subject: [PATCH 03/14] assert more often in release in ast_lowering --- compiler/rustc_ast_lowering/src/lib.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b99df8bd7e552..d02accc521d1e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -503,7 +503,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, ) -> LocalDefId { let parent = self.current_hir_id_owner.def_id; - debug_assert_ne!(node_id, ast::DUMMY_NODE_ID); + assert_ne!(node_id, ast::DUMMY_NODE_ID); assert!( self.opt_local_def_id(node_id).is_none(), "adding a def'n for node-id {:?} and def kind {:?} but a previous def'n exists: {:?}", @@ -586,10 +586,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let item = f(self); - debug_assert_eq!(owner_id, item.def_id()); + assert_eq!(owner_id, item.def_id()); // `f` should have consumed all the elements in these vectors when constructing `item`. - debug_assert!(self.impl_trait_defs.is_empty()); - debug_assert!(self.impl_trait_bounds.is_empty()); + assert!(self.impl_trait_defs.is_empty()); + assert!(self.impl_trait_bounds.is_empty()); let info = self.make_owner_info(item); self.attrs = current_attrs; @@ -891,7 +891,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span)); - debug_assert_eq!(id.owner, self.current_hir_id_owner); + assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(lowered_attrs); // this is possible if an item contained syntactical attribute, @@ -915,10 +915,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn alias_attrs(&mut self, id: HirId, target_id: HirId) { - debug_assert_eq!(id.owner, self.current_hir_id_owner); - debug_assert_eq!(target_id.owner, self.current_hir_id_owner); + assert_eq!(id.owner, self.current_hir_id_owner); + assert_eq!(target_id.owner, self.current_hir_id_owner); if let Some(&a) = self.attrs.get(&target_id.local_id) { - debug_assert!(!a.is_empty()); + assert!(!a.is_empty()); self.attrs.insert(id.local_id, a); } } @@ -1397,7 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = self.resolver.get_lifetime_res(t.id) { - debug_assert_eq!(start.plus(1), end); + assert_eq!(start.plus(1), end); start } else { self.next_node_id() @@ -1805,16 +1805,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let res = match res { LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param), LifetimeRes::Fresh { param, .. } => { - debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + assert_eq!(ident.name, kw::UnderscoreLifetime); let param = self.local_def_id(param); hir::LifetimeKind::Param(param) } LifetimeRes::Infer => { - debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + assert_eq!(ident.name, kw::UnderscoreLifetime); hir::LifetimeKind::Infer } LifetimeRes::Static { .. } => { - debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime)); + assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime)); hir::LifetimeKind::Static } LifetimeRes::Error => hir::LifetimeKind::Error, @@ -2244,7 +2244,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::Stmt<'hir> { let hir_id = self.next_id(); if let Some(a) = attrs { - debug_assert!(!a.is_empty()); + assert!(!a.is_empty()); self.attrs.insert(hir_id.local_id, a); } let local = hir::LetStmt { From 59069986e7446123556630a32adce7f101eeaf8d Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 7 Jun 2025 11:04:40 -0700 Subject: [PATCH 04/14] tests: Copy dont-shuffle-bswaps per tested opt level --- .../autovec/dont-shuffle-bswaps-opt2.rs | 29 +++++++++++++++++++ .../dont-shuffle-bswaps-opt3.rs} | 3 +- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs rename tests/codegen/{dont-shuffle-bswaps.rs => autovec/dont-shuffle-bswaps-opt3.rs} (94%) diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs new file mode 100644 index 0000000000000..391cf1c639ca3 --- /dev/null +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs @@ -0,0 +1,29 @@ +//@ compile-flags: -Copt-level=2 + +#![crate_type = "lib"] +#![no_std] + +// The code is from https://github.com/rust-lang/rust/issues/122805. +// Ensure we do not generate the shufflevector instruction +// to avoid complicating the code. + +// CHECK-LABEL: define{{.*}}void @convert( +// CHECK-NOT: shufflevector +#[no_mangle] +pub fn convert(value: [u16; 8]) -> [u8; 16] { + #[cfg(target_endian = "little")] + let bswap = u16::to_be; + #[cfg(target_endian = "big")] + let bswap = u16::to_le; + let addr16 = [ + bswap(value[0]), + bswap(value[1]), + bswap(value[2]), + bswap(value[3]), + bswap(value[4]), + bswap(value[5]), + bswap(value[6]), + bswap(value[7]), + ]; + unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } +} diff --git a/tests/codegen/dont-shuffle-bswaps.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs similarity index 94% rename from tests/codegen/dont-shuffle-bswaps.rs rename to tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs index c1dab2bc29536..e105487cccab2 100644 --- a/tests/codegen/dont-shuffle-bswaps.rs +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs @@ -1,5 +1,4 @@ -//@ revisions: OPT2 OPT3 OPT3_S390X -//@[OPT2] compile-flags: -Copt-level=2 +//@ revisions: OPT3 OPT3_S390X //@[OPT3] compile-flags: -C opt-level=3 // some targets don't do the opt we are looking for //@[OPT3] only-64bit From 6b0deb2161b730be16c1ec13c1ab47455c054f37 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 7 Jun 2025 11:12:38 -0700 Subject: [PATCH 05/14] tests: Revise dont-shuffle-bswaps-opt3 per tested arch Some architectures gain target-cpu minimums in doing so. --- .../autovec/dont-shuffle-bswaps-opt2.rs | 2 ++ .../autovec/dont-shuffle-bswaps-opt3.rs | 29 +++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs index 391cf1c639ca3..c354228acc50a 100644 --- a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs @@ -3,6 +3,8 @@ #![crate_type = "lib"] #![no_std] +// This test is paired with the arch-specific -opt3.rs test. + // The code is from https://github.com/rust-lang/rust/issues/122805. // Ensure we do not generate the shufflevector instruction // to avoid complicating the code. diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs index e105487cccab2..203d12005de2a 100644 --- a/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs @@ -1,28 +1,27 @@ -//@ revisions: OPT3 OPT3_S390X -//@[OPT3] compile-flags: -C opt-level=3 -// some targets don't do the opt we are looking for -//@[OPT3] only-64bit -//@[OPT3] ignore-s390x -//@[OPT3_S390X] compile-flags: -C opt-level=3 -C target-cpu=z13 -//@[OPT3_S390X] only-s390x +//@ revisions: AARCH64 X86_64 Z13 +//@ compile-flags: -Copt-level=3 +//@[AARCH64] only-aarch64 +//@[X86_64] only-x86_64 +//@[Z13] only-s390x +//@[Z13] compile-flags: -Ctarget-cpu=z13 #![crate_type = "lib"] #![no_std] +// This test is paired with the arch-neutral -opt2.rs test + // The code is from https://github.com/rust-lang/rust/issues/122805. // Ensure we do not generate the shufflevector instruction // to avoid complicating the code. + // CHECK-LABEL: define{{.*}}void @convert( // CHECK-NOT: shufflevector + // On higher opt levels, this should just be a bswap: -// OPT3: load <8 x i16> -// OPT3-NEXT: call <8 x i16> @llvm.bswap -// OPT3-NEXT: store <8 x i16> -// OPT3-NEXT: ret void -// OPT3_S390X: load <8 x i16> -// OPT3_S390X-NEXT: call <8 x i16> @llvm.bswap -// OPT3_S390X-NEXT: store <8 x i16> -// OPT3_S390X-NEXT: ret void +// CHECK: load <8 x i16> +// CHECK-NEXT: call <8 x i16> @llvm.bswap +// CHECK-NEXT: store <8 x i16> +// CHECK-NEXT: ret void #[no_mangle] pub fn convert(value: [u16; 8]) -> [u8; 16] { #[cfg(target_endian = "little")] From de8a91b51c3fbc60e80a75e2859e371e7de7e1ec Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Mon, 9 Jun 2025 22:29:59 +0800 Subject: [PATCH 06/14] Add supported asm types for LoongArch32 --- compiler/rustc_target/src/asm/loongarch.rs | 10 ++++++---- .../src/language-features/asm-experimental-arch.md | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs index b4ea6fc592a8c..8783d3953b161 100644 --- a/compiler/rustc_target/src/asm/loongarch.rs +++ b/compiler/rustc_target/src/asm/loongarch.rs @@ -34,11 +34,13 @@ impl LoongArchInlineAsmRegClass { pub fn supported_types( self, - _arch: InlineAsmArch, + arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option)] { - match self { - Self::reg => types! { _: I8, I16, I32, I64, F32, F64; }, - Self::freg => types! { f: F32; d: F64; }, + match (self, arch) { + (Self::reg, InlineAsmArch::LoongArch64) => types! { _: I8, I16, I32, I64, F32, F64; }, + (Self::reg, InlineAsmArch::LoongArch32) => types! { _: I8, I16, I32, F32; }, + (Self::freg, _) => types! { f: F32; d: F64; }, + _ => unreachable!("unsupported register class"), } } } diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index d9566c9f55c5c..121f949343594 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -19,6 +19,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - M68k - CSKY - SPARC +- LoongArch32 ## Register classes @@ -53,6 +54,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | `f[0-31]` | `f` | | SPARC | `reg` | `r[2-29]` | `r` | | SPARC | `yreg` | `y` | Only clobbers | +| LoongArch32 | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` | +| LoongArch32 | `freg` | `$f[0-31]` | `f` | > **Notes**: > - NVPTX doesn't have a fixed register set, so named registers are not supported. @@ -91,6 +94,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | None | `f32`, | | SPARC | `reg` | None | `i8`, `i16`, `i32`, `i64` (SPARC64 only) | | SPARC | `yreg` | N/A | Only clobbers | +| LoongArch32 | `reg` | None | `i8`, `i16`, `i32`, `f32` | +| LoongArch32 | `freg` | None | `f32`, `f64` | ## Register aliases From 457a4c4aff4231357f9a8ad4e56cc645823dbcd8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 10 Jun 2025 01:37:47 +0000 Subject: [PATCH 07/14] Update dependencies in `library/Cargo.lock` This removes the `compiler_builtins` dependency from a handful of library dependencies, which is progress toward [1]. [1]: https://github.com/rust-lang/rust/issues/142265 --- library/Cargo.lock | 54 +++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 966ae72dc2ad1..abdc0592d43f2 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -16,11 +16,10 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -51,11 +50,10 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -81,12 +79,11 @@ dependencies = [ [[package]] name = "dlmalloc" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7" +checksum = "d01597dde41c0b9da50d5f8c219023d63d8f27f39a27095070fd191fddc83891" dependencies = [ "cfg-if", - "compiler_builtins", "libc", "rustc-std-workspace-core", "windows-sys", @@ -104,9 +101,9 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.21" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" dependencies = [ "rustc-std-workspace-core", "rustc-std-workspace-std", @@ -126,22 +123,20 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] [[package]] name = "hermit-abi" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -157,22 +152,20 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -274,11 +267,10 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -381,11 +373,10 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", "rustc-std-workspace-std", ] @@ -414,11 +405,10 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] From 1ec80452b6508f915be1c5ae2667f830882029e9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 10 Jun 2025 18:25:21 +0000 Subject: [PATCH 08/14] Upgrade the standard library `object` version 0.37.0 is a semver-breaking release but the only breakage is in `elf::R_RISCV_GNU_*` and `pe::IMAGE_WEAK_EXTERN_*` constants, as well as Mach-O dyld. This API is not used by `std`, so we should be fine to upgrade. This new version also includes functionality for parsing Wasm object files that we may eventually like to make use of. Also includes the minor bump from 0.37.0 to 0.37.1 to help [1]. Changelog: https://github.com/gimli-rs/object/blob/master/CHANGELOG.md#0370 [1]: https://github.com/rust-lang/rust/issues/142265 --- library/Cargo.lock | 10 ++++------ library/std/Cargo.toml | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 966ae72dc2ad1..f0a7f6874ba28 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -157,11 +157,10 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -179,11 +178,10 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" dependencies = [ - "compiler_builtins", "memchr", "rustc-std-workspace-alloc", "rustc-std-workspace-core", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 53d78dcc48847..3e2f34cfb3726 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -40,7 +40,7 @@ libc = { version = "0.2.172", default-features = false, features = [ ], public = true } [target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies] -object = { version = "0.36.0", default-features = false, optional = true, features = [ +object = { version = "0.37.1", default-features = false, optional = true, features = [ 'read_core', 'elf', 'macho', @@ -50,7 +50,7 @@ object = { version = "0.36.0", default-features = false, optional = true, featur ] } [target.'cfg(target_os = "aix")'.dependencies] -object = { version = "0.36.0", default-features = false, optional = true, features = [ +object = { version = "0.37.1", default-features = false, optional = true, features = [ 'read_core', 'xcoff', 'unaligned', From 1f6abbb99ffbf052e56c815ba8eac2c9b9a7a75d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 10 Jun 2025 18:25:21 +0000 Subject: [PATCH 09/14] Upgrade the standard library `addr2line` version 0.25.0 is a breaking change only because it upgrades the `gimli` version. It also includes a change to the `compiler-builtins` dependency that helps with [1]. Changelog: https://github.com/gimli-rs/addr2line/blob/master/CHANGELOG.md#0250-20250611 [1]: https://github.com/rust-lang/rust/issues/142265 --- library/Cargo.lock | 19 ++++++++++++++----- library/std/Cargo.toml | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index f0a7f6874ba28..85c0e781d1fce 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -4,12 +4,11 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43" dependencies = [ - "compiler_builtins", - "gimli", + "gimli 0.32.0", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -124,6 +123,16 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "gimli" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe" +dependencies = [ + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + [[package]] name = "hashbrown" version = "0.15.3" @@ -406,7 +415,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.31.1", "rustc-std-workspace-core", ] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 3e2f34cfb3726..ae7107938f363 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -32,7 +32,7 @@ rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] miniz_oxide = { version = "0.8.0", optional = true, default-features = false } -addr2line = { version = "0.24.0", optional = true, default-features = false } +addr2line = { version = "0.25.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2.172", default-features = false, features = [ From 68609e4214ebee4e7ccd5f729102a010f9d3ccb1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 11 Jun 2025 20:05:06 +0000 Subject: [PATCH 10/14] Upgrade the standard library `unwinding` version This comes with a `gimli` upgrade, so we no longer have two different versions. --- library/Cargo.lock | 19 ++++--------------- library/unwind/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 85c0e781d1fce..b6ef2126b44e3 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -8,7 +8,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43" dependencies = [ - "gimli 0.32.0", + "gimli", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -112,17 +112,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - [[package]] name = "gimli" version = "0.32.0" @@ -410,12 +399,12 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345" +checksum = "7d80f6c2bfede213d9a90b4a14f3eb99b84e33c52df6c1a15de0a100f5a88751" dependencies = [ "compiler_builtins", - "gimli 0.31.1", + "gimli", "rustc-std-workspace-core", ] diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index ad373420a96f8..f8da09f71931a 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -22,7 +22,7 @@ cfg-if = "1.0" libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false } [target.'cfg(target_os = "xous")'.dependencies] -unwinding = { version = "0.2.6", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } +unwinding = { version = "0.2.7", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } [features] From 208cb5da15d5a8378efff6d44a5ffa53fd51bbbc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 31 Jul 2024 01:59:22 -0400 Subject: [PATCH 11/14] Fix a missing fragment specifier in rustdoc tests --- .../macro/macro-generated-macro.macro_morestuff_pre.html | 4 ++-- tests/rustdoc/macro/macro-generated-macro.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html b/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html index 28f15522a82f7..4dcc8111c6ff3 100644 --- a/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html +++ b/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html @@ -1,7 +1,7 @@ macro_rules! morestuff { ( - <= "space between most kinds of tokens" : 1 $x + @ :: >>= 'static - "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)* + <= "space between most kinds of tokens" : 1 $x:ident + @ :: >>= + 'static "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)* "space inside curly brace" : { 2 a } "no space inside empty delimiters" : () [] {} "no space before comma or semicolon" : a, (a), { a }, a; [T; 0]; diff --git a/tests/rustdoc/macro/macro-generated-macro.rs b/tests/rustdoc/macro/macro-generated-macro.rs index e77d0cf89e748..dfb152bafb62e 100644 --- a/tests/rustdoc/macro/macro-generated-macro.rs +++ b/tests/rustdoc/macro/macro-generated-macro.rs @@ -25,7 +25,7 @@ make_macro!(linebreak 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 //@ snapshot macro_morestuff_pre macro_generated_macro/macro.morestuff.html //pre/text() make_macro!(morestuff - "space between most kinds of tokens": 1 $x + @ :: >>= 'static + "space between most kinds of tokens": 1 $x:ident + @ :: >>= 'static "no space inside paren or bracket": (2 a) [2 a] $(2 $a:tt)* "space inside curly brace": { 2 a } "no space inside empty delimiters": () [] {} From 841f7ce69ac503fb9566deeefbbd273c1587f4e6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 30 Jul 2024 23:04:23 -0400 Subject: [PATCH 12/14] Make `missing_fragment_specifier` an unconditional error This was attempted in [1] then reverted in [2] because of fallout. Recently, this was made an edition-dependent error in [3]. Make missing fragment specifiers an unconditional error again. [1]: https://github.com/rust-lang/rust/pull/75516 [2]: https://github.com/rust-lang/rust/pull/80210 [3]: https://github.com/rust-lang/rust/pull/128006 --- compiler/rustc_expand/messages.ftl | 2 +- compiler/rustc_expand/src/mbe/macro_check.rs | 25 ++---- compiler/rustc_lint/messages.ftl | 2 - compiler/rustc_lint/src/early/diagnostics.rs | 3 - compiler/rustc_lint/src/lib.rs | 5 ++ compiler/rustc_lint/src/lints.rs | 4 - compiler/rustc_lint_defs/src/builtin.rs | 46 ---------- compiler/rustc_lint_defs/src/lib.rs | 1 - tests/ui/lint/expansion-time.rs | 4 - tests/ui/lint/expansion-time.stderr | 33 +------ .../ui/lint/future-incompatible-lint-group.rs | 19 +++-- .../future-incompatible-lint-group.stderr | 44 +++++----- tests/ui/macros/issue-39404.rs | 6 +- tests/ui/macros/issue-39404.stderr | 26 ++---- tests/ui/macros/macro-match-nonterminal.rs | 2 - .../ui/macros/macro-match-nonterminal.stderr | 39 +++------ .../macro-missing-fragment-deduplication.rs | 6 +- ...acro-missing-fragment-deduplication.stderr | 26 ++---- .../macro-missing-fragment.e2015.stderr | 85 ------------------- tests/ui/macros/macro-missing-fragment.rs | 24 ++---- ...4.stderr => macro-missing-fragment.stderr} | 14 +-- tests/ui/parser/macro/issue-33569.rs | 1 - tests/ui/parser/macro/issue-33569.stderr | 24 ++---- 23 files changed, 102 insertions(+), 339 deletions(-) delete mode 100644 tests/ui/macros/macro-missing-fragment.e2015.stderr rename tests/ui/macros/{macro-missing-fragment.e2024.stderr => macro-missing-fragment.stderr} (79%) diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 08b7a36208302..8b7c47dad991f 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -113,7 +113,7 @@ expand_meta_var_expr_unrecognized_var = variable `{$key}` is not recognized in meta-variable expression expand_missing_fragment_specifier = missing fragment specifier - .note = fragment specifiers must be specified in the 2024 edition + .note = fragment specifiers must be provided .suggestion_add_fragspec = try adding a specifier here .valid = {$valid} diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 1a2db233b7a64..3cd803c3e8482 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -112,9 +112,8 @@ use rustc_ast::{DUMMY_NODE_ID, NodeId}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::MultiSpan; use rustc_lint_defs::BuiltinLintDiag; -use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; +use rustc_session::lint::builtin::META_VARIABLE_MISUSE; use rustc_session::parse::ParseSess; -use rustc_span::edition::Edition; use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw}; use smallvec::SmallVec; @@ -266,23 +265,11 @@ fn check_binders( // Similarly, this can only happen when checking a toplevel macro. TokenTree::MetaVarDecl(span, name, kind) => { if kind.is_none() && node_id != DUMMY_NODE_ID { - // FIXME: Report this as a hard error eventually and remove equivalent errors from - // `parse_tt_inner` and `nameize`. Until then the error may be reported twice, once - // as a hard error and then once as a buffered lint. - if span.edition() >= Edition::Edition2024 { - psess.dcx().emit_err(errors::MissingFragmentSpecifier { - span, - add_span: span.shrink_to_hi(), - valid: VALID_FRAGMENT_NAMES_MSG, - }); - } else { - psess.buffer_lint( - MISSING_FRAGMENT_SPECIFIER, - span, - node_id, - BuiltinLintDiag::MissingFragmentSpecifier, - ); - } + psess.dcx().emit_err(errors::MissingFragmentSpecifier { + span, + add_span: span.shrink_to_hi(), + valid: VALID_FRAGMENT_NAMES_MSG, + }); } if !macros.is_empty() { psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs"); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index fd2e2ba39acec..9a1db52fbd1ee 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -533,8 +533,6 @@ lint_mismatched_lifetime_syntaxes_suggestion_implicit = lint_mismatched_lifetime_syntaxes_suggestion_mixed = one option is to remove the lifetime for references and use the anonymous lifetime for paths -lint_missing_fragment_specifier = missing fragment specifier - lint_missing_unsafe_on_extern = extern blocks should be unsafe .suggestion = needs `unsafe` before the extern keyword diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 60c477dd6c749..3b0a36186b671 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -432,9 +432,6 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::CfgAttrNoAttributes => { lints::CfgAttrNoAttributes.decorate_lint(diag); } - BuiltinLintDiag::MissingFragmentSpecifier => { - lints::MissingFragmentSpecifier.decorate_lint(diag); - } BuiltinLintDiag::MetaVariableStillRepeating(name) => { lints::MetaVariableStillRepeating { name }.decorate_lint(diag); } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 72bfeaddbf1a7..547539d7273c3 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -619,6 +619,11 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, \ see for more information", ); + store.register_removed( + "missing_fragment_specifier", + "converted into hard error, \ + see for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 9d3c74a9a2b80..25acde53367b8 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2616,10 +2616,6 @@ pub(crate) struct DuplicateMacroAttribute; #[diag(lint_cfg_attr_no_attributes)] pub(crate) struct CfgAttrNoAttributes; -#[derive(LintDiagnostic)] -#[diag(lint_missing_fragment_specifier)] -pub(crate) struct MissingFragmentSpecifier; - #[derive(LintDiagnostic)] #[diag(lint_metavariable_still_repeating)] pub(crate) struct MetaVariableStillRepeating { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 777118e69fb15..174619e5ad9f6 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -65,7 +65,6 @@ declare_lint_pass! { MACRO_USE_EXTERN_CRATE, META_VARIABLE_MISUSE, MISSING_ABI, - MISSING_FRAGMENT_SPECIFIER, MISSING_UNSAFE_ON_EXTERN, MUST_NOT_SUSPEND, NAMED_ARGUMENTS_USED_POSITIONALLY, @@ -1417,51 +1416,6 @@ declare_lint! { }; } -declare_lint! { - /// The `missing_fragment_specifier` lint is issued when an unused pattern in a - /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not - /// followed by a fragment specifier (e.g. `:expr`). - /// - /// This warning can always be fixed by removing the unused pattern in the - /// `macro_rules!` macro definition. - /// - /// ### Example - /// - /// ```rust,compile_fail,edition2021 - /// macro_rules! foo { - /// () => {}; - /// ($name) => { }; - /// } - /// - /// fn main() { - /// foo!(); - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// To fix this, remove the unused pattern from the `macro_rules!` macro definition: - /// - /// ```rust - /// macro_rules! foo { - /// () => {}; - /// } - /// fn main() { - /// foo!(); - /// } - /// ``` - pub MISSING_FRAGMENT_SPECIFIER, - Deny, - "detects missing fragment specifiers in unused `macro_rules!` patterns", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #40107 ", - report_in_deps: true, - }; -} - declare_lint! { /// The `late_bound_lifetime_arguments` lint detects generic lifetime /// arguments in path segments with late bound lifetime parameters. diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1d9b7a7fcb948..cd402c9234fd8 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -778,7 +778,6 @@ pub enum BuiltinLintDiag { UnnameableTestItems, DuplicateMacroAttribute, CfgAttrNoAttributes, - MissingFragmentSpecifier, MetaVariableStillRepeating(MacroRulesNormalizedIdent), MetaVariableWrongOperator, DuplicateMatcherBinding, diff --git a/tests/ui/lint/expansion-time.rs b/tests/ui/lint/expansion-time.rs index 5ffb0c7881e33..2c59bf0006514 100644 --- a/tests/ui/lint/expansion-time.rs +++ b/tests/ui/lint/expansion-time.rs @@ -5,10 +5,6 @@ macro_rules! foo { ( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator } -#[warn(missing_fragment_specifier)] -macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier - //~| WARN this was previously accepted - #[deprecated = "reason"] macro_rules! deprecated { () => {} diff --git a/tests/ui/lint/expansion-time.stderr b/tests/ui/lint/expansion-time.stderr index f24d1b68a8dae..b1154d1a54c0b 100644 --- a/tests/ui/lint/expansion-time.stderr +++ b/tests/ui/lint/expansion-time.stderr @@ -12,20 +12,6 @@ note: the lint level is defined here LL | #[warn(meta_variable_misuse)] | ^^^^^^^^^^^^^^^^^^^^ -warning: missing fragment specifier - --> $DIR/expansion-time.rs:9:19 - | -LL | macro_rules! m { ($i) => {} } - | ^^ - | - = 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 #40107 -note: the lint level is defined here - --> $DIR/expansion-time.rs:8:8 - | -LL | #[warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - warning: include macro expected single expression in source --> $DIR/expansion-time-include.rs:4:1 | @@ -33,25 +19,10 @@ LL | 2 | ^ | note: the lint level is defined here - --> $DIR/expansion-time.rs:22:8 + --> $DIR/expansion-time.rs:18:8 | LL | #[warn(incomplete_include)] | ^^^^^^^^^^^^^^^^^^ -warning: 3 warnings emitted - -Future incompatibility report: Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/expansion-time.rs:9:19 - | -LL | macro_rules! m { ($i) => {} } - | ^^ - | - = 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 #40107 -note: the lint level is defined here - --> $DIR/expansion-time.rs:8:8 - | -LL | #[warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: 2 warnings emitted diff --git a/tests/ui/lint/future-incompatible-lint-group.rs b/tests/ui/lint/future-incompatible-lint-group.rs index d1adcf21cdceb..22a7ccb463b6c 100644 --- a/tests/ui/lint/future-incompatible-lint-group.rs +++ b/tests/ui/lint/future-incompatible-lint-group.rs @@ -4,14 +4,23 @@ // lints for changes that are not tied to an edition #![deny(future_incompatible)] -// Error since this is a `future_incompatible` lint -macro_rules! m { - ($i) => {}; - //~^ ERROR missing fragment specifier +enum E { V } + +trait Tr1 { + type V; + fn foo() -> Self::V; +} + +impl Tr1 for E { + type V = u8; + + // Error since this is a `future_incompatible` lint + fn foo() -> Self::V { 0 } + //~^ ERROR ambiguous associated item //~| WARN this was previously accepted } -trait Tr { +trait Tr2 { // Warn only since this is not a `future_incompatible` lint fn f(u8) {} //~^ WARN anonymous parameters are deprecated diff --git a/tests/ui/lint/future-incompatible-lint-group.stderr b/tests/ui/lint/future-incompatible-lint-group.stderr index 264911b46d4d9..87b9ebec08b37 100644 --- a/tests/ui/lint/future-incompatible-lint-group.stderr +++ b/tests/ui/lint/future-incompatible-lint-group.stderr @@ -1,20 +1,5 @@ -error: missing fragment specifier - --> $DIR/future-incompatible-lint-group.rs:9:6 - | -LL | ($i) => {}; - | ^^ - | - = 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 #40107 -note: the lint level is defined here - --> $DIR/future-incompatible-lint-group.rs:5:9 - | -LL | #![deny(future_incompatible)] - | ^^^^^^^^^^^^^^^^^^^ - = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` - warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/future-incompatible-lint-group.rs:16:10 + --> $DIR/future-incompatible-lint-group.rs:25:10 | LL | fn f(u8) {} | ^^ help: try naming the parameter or explicitly ignoring it: `_: u8` @@ -23,21 +8,30 @@ LL | fn f(u8) {} = note: for more information, see issue #41686 = note: `#[warn(anonymous_parameters)]` on by default -error: aborting due to 1 previous error; 1 warning emitted - -Future incompatibility report: Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/future-incompatible-lint-group.rs:9:6 +error: ambiguous associated item + --> $DIR/future-incompatible-lint-group.rs:18:17 | -LL | ($i) => {}; - | ^^ +LL | fn foo() -> Self::V { 0 } + | ^^^^^^^ help: use fully-qualified syntax: `::V` | = 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 #40107 + = note: for more information, see issue #57644 +note: `V` could refer to the variant defined here + --> $DIR/future-incompatible-lint-group.rs:7:10 + | +LL | enum E { V } + | ^ +note: `V` could also refer to the associated type defined here + --> $DIR/future-incompatible-lint-group.rs:10:5 + | +LL | type V; + | ^^^^^^ note: the lint level is defined here --> $DIR/future-incompatible-lint-group.rs:5:9 | LL | #![deny(future_incompatible)] | ^^^^^^^^^^^^^^^^^^^ - = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` + = note: `#[deny(ambiguous_associated_items)]` implied by `#[deny(future_incompatible)]` + +error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/macros/issue-39404.rs b/tests/ui/macros/issue-39404.rs index 2229f2c3900c3..ceeb6231bc8cd 100644 --- a/tests/ui/macros/issue-39404.rs +++ b/tests/ui/macros/issue-39404.rs @@ -1,7 +1,7 @@ #![allow(unused)] -macro_rules! m { ($i) => {} } -//~^ ERROR missing fragment specifier -//~| WARN previously accepted +macro_rules! m { + ($i) => {}; //~ ERROR missing fragment specifier +} fn main() {} diff --git a/tests/ui/macros/issue-39404.stderr b/tests/ui/macros/issue-39404.stderr index 176c8e9f073c8..62d0bc1018c59 100644 --- a/tests/ui/macros/issue-39404.stderr +++ b/tests/ui/macros/issue-39404.stderr @@ -1,23 +1,15 @@ error: missing fragment specifier - --> $DIR/issue-39404.rs:3:19 + --> $DIR/issue-39404.rs:4:6 | -LL | macro_rules! m { ($i) => {} } - | ^^ +LL | ($i) => {}; + | ^^ | - = 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 #40107 - = note: `#[deny(missing_fragment_specifier)]` on by default + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here + | +LL | ($i:spec) => {}; + | +++++ error: aborting due to 1 previous error -Future incompatibility report: Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/issue-39404.rs:3:19 - | -LL | macro_rules! m { ($i) => {} } - | ^^ - | - = 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 #40107 - = note: `#[deny(missing_fragment_specifier)]` on by default - diff --git a/tests/ui/macros/macro-match-nonterminal.rs b/tests/ui/macros/macro-match-nonterminal.rs index 5d9eb55fee036..fa2af945a1f1b 100644 --- a/tests/ui/macros/macro-match-nonterminal.rs +++ b/tests/ui/macros/macro-match-nonterminal.rs @@ -3,8 +3,6 @@ macro_rules! test { //~^ ERROR missing fragment //~| ERROR missing fragment //~| ERROR missing fragment - //~| WARN this was previously accepted - //~| WARN this was previously accepted () }; } diff --git a/tests/ui/macros/macro-match-nonterminal.stderr b/tests/ui/macros/macro-match-nonterminal.stderr index f221f92c3cda6..8196d795c4c8f 100644 --- a/tests/ui/macros/macro-match-nonterminal.stderr +++ b/tests/ui/macros/macro-match-nonterminal.stderr @@ -3,16 +3,13 @@ error: missing fragment specifier | LL | ($a, $b) => { | ^^ - -error: missing fragment specifier - --> $DIR/macro-match-nonterminal.rs:2:6 | -LL | ($a, $b) => { - | ^^ + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here | - = 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 #40107 - = note: `#[deny(missing_fragment_specifier)]` on by default +LL | ($a:spec, $b) => { + | +++++ error: missing fragment specifier --> $DIR/macro-match-nonterminal.rs:2:10 @@ -20,30 +17,18 @@ error: missing fragment specifier LL | ($a, $b) => { | ^^ | - = 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 #40107 - -error: aborting due to 3 previous errors + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here + | +LL | ($a, $b:spec) => { + | +++++ -Future incompatibility report: Future breakage diagnostic: error: missing fragment specifier --> $DIR/macro-match-nonterminal.rs:2:6 | LL | ($a, $b) => { | ^^ - | - = 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 #40107 - = note: `#[deny(missing_fragment_specifier)]` on by default -Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/macro-match-nonterminal.rs:2:10 - | -LL | ($a, $b) => { - | ^^ - | - = 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 #40107 - = note: `#[deny(missing_fragment_specifier)]` on by default +error: aborting due to 3 previous errors diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.rs b/tests/ui/macros/macro-missing-fragment-deduplication.rs index b77c51e055bff..481f08fa11199 100644 --- a/tests/ui/macros/macro-missing-fragment-deduplication.rs +++ b/tests/ui/macros/macro-missing-fragment-deduplication.rs @@ -1,10 +1,8 @@ //@ compile-flags: -Zdeduplicate-diagnostics=yes macro_rules! m { - ($name) => {} - //~^ ERROR missing fragment - //~| ERROR missing fragment - //~| WARN this was previously accepted + ($name) => {}; //~ ERROR missing fragment + //~| ERROR missing fragment } fn main() { diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.stderr b/tests/ui/macros/macro-missing-fragment-deduplication.stderr index c46712f70fd53..820f7eb3cf7fd 100644 --- a/tests/ui/macros/macro-missing-fragment-deduplication.stderr +++ b/tests/ui/macros/macro-missing-fragment-deduplication.stderr @@ -1,29 +1,21 @@ error: missing fragment specifier --> $DIR/macro-missing-fragment-deduplication.rs:4:6 | -LL | ($name) => {} +LL | ($name) => {}; | ^^^^^ - -error: missing fragment specifier - --> $DIR/macro-missing-fragment-deduplication.rs:4:6 | -LL | ($name) => {} - | ^^^^^ + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here | - = 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 #40107 - = note: `#[deny(missing_fragment_specifier)]` on by default +LL | ($name:spec) => {}; + | +++++ -error: aborting due to 2 previous errors - -Future incompatibility report: Future breakage diagnostic: error: missing fragment specifier --> $DIR/macro-missing-fragment-deduplication.rs:4:6 | -LL | ($name) => {} +LL | ($name) => {}; | ^^^^^ - | - = 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 #40107 - = note: `#[deny(missing_fragment_specifier)]` on by default + +error: aborting due to 2 previous errors diff --git a/tests/ui/macros/macro-missing-fragment.e2015.stderr b/tests/ui/macros/macro-missing-fragment.e2015.stderr deleted file mode 100644 index 3d32f203d4a2e..0000000000000 --- a/tests/ui/macros/macro-missing-fragment.e2015.stderr +++ /dev/null @@ -1,85 +0,0 @@ -error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 - | -LL | ( $( any_token $field_rust_type )* ) => {}; - | ^^^^^^^^^^^^^^^^ - -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 - | -LL | ( $( any_token $field_rust_type )* ) => {}; - | ^^^^^^^^^^^^^^^^ - | - = 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 #40107 -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:18:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = 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 #40107 - -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:25:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = 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 #40107 - -error: aborting due to 1 previous error; 3 warnings emitted - -Future incompatibility report: Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 - | -LL | ( $( any_token $field_rust_type )* ) => {}; - | ^^^^^^^^^^^^^^^^ - | - = 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 #40107 -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:18:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = 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 #40107 -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:25:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = 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 #40107 -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - diff --git a/tests/ui/macros/macro-missing-fragment.rs b/tests/ui/macros/macro-missing-fragment.rs index 42387e8dbbf4f..533aa147bcbf5 100644 --- a/tests/ui/macros/macro-missing-fragment.rs +++ b/tests/ui/macros/macro-missing-fragment.rs @@ -1,31 +1,17 @@ -//@ revisions: e2015 e2024 -//@[e2015] edition:2015 -//@[e2024] edition:2024 - -#![warn(missing_fragment_specifier)] +//! Ensure that macros produce an error if fragment specifiers are missing. macro_rules! used_arm { - ( $( any_token $field_rust_type )* ) => {}; - //[e2015]~^ ERROR missing fragment - //[e2015]~| WARN missing fragment - //[e2015]~| WARN this was previously accepted - //[e2024]~^^^^ ERROR missing fragment - //[e2024]~| ERROR missing fragment + ( $( any_token $field_rust_type )* ) => {}; //~ ERROR missing fragment + //~| ERROR missing fragment } macro_rules! used_macro_unused_arm { () => {}; - ( $name ) => {}; - //[e2015]~^ WARN missing fragment - //[e2015]~| WARN this was previously accepted - //[e2024]~^^^ ERROR missing fragment + ( $name ) => {}; //~ ERROR missing fragment } macro_rules! unused_macro { - ( $name ) => {}; - //[e2015]~^ WARN missing fragment - //[e2015]~| WARN this was previously accepted - //[e2024]~^^^ ERROR missing fragment + ( $name ) => {}; //~ ERROR missing fragment } fn main() { diff --git a/tests/ui/macros/macro-missing-fragment.e2024.stderr b/tests/ui/macros/macro-missing-fragment.stderr similarity index 79% rename from tests/ui/macros/macro-missing-fragment.e2024.stderr rename to tests/ui/macros/macro-missing-fragment.stderr index a9195063a5b92..4a99d7d949cfe 100644 --- a/tests/ui/macros/macro-missing-fragment.e2024.stderr +++ b/tests/ui/macros/macro-missing-fragment.stderr @@ -1,10 +1,10 @@ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 + --> $DIR/macro-missing-fragment.rs:4:20 | LL | ( $( any_token $field_rust_type )* ) => {}; | ^^^^^^^^^^^^^^^^ | - = note: fragment specifiers must be specified in the 2024 edition + = note: fragment specifiers must be provided = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | @@ -12,12 +12,12 @@ LL | ( $( any_token $field_rust_type:spec )* ) => {}; | +++++ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:18:7 + --> $DIR/macro-missing-fragment.rs:10:7 | LL | ( $name ) => {}; | ^^^^^ | - = note: fragment specifiers must be specified in the 2024 edition + = note: fragment specifiers must be provided = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | @@ -25,12 +25,12 @@ LL | ( $name:spec ) => {}; | +++++ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:25:7 + --> $DIR/macro-missing-fragment.rs:14:7 | LL | ( $name ) => {}; | ^^^^^ | - = note: fragment specifiers must be specified in the 2024 edition + = note: fragment specifiers must be provided = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | @@ -38,7 +38,7 @@ LL | ( $name:spec ) => {}; | +++++ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 + --> $DIR/macro-missing-fragment.rs:4:20 | LL | ( $( any_token $field_rust_type )* ) => {}; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/parser/macro/issue-33569.rs b/tests/ui/parser/macro/issue-33569.rs index 069d181e96267..e0a5352ab06db 100644 --- a/tests/ui/parser/macro/issue-33569.rs +++ b/tests/ui/parser/macro/issue-33569.rs @@ -2,7 +2,6 @@ macro_rules! foo { { $+ } => { //~ ERROR expected identifier, found `+` //~^ ERROR missing fragment specifier //~| ERROR missing fragment specifier - //~| WARN this was previously accepted $(x)(y) //~ ERROR expected one of: `*`, `+`, or `?` } } diff --git a/tests/ui/parser/macro/issue-33569.stderr b/tests/ui/parser/macro/issue-33569.stderr index d1b6abfeeebfd..0d53c04c1c9f0 100644 --- a/tests/ui/parser/macro/issue-33569.stderr +++ b/tests/ui/parser/macro/issue-33569.stderr @@ -5,7 +5,7 @@ LL | { $+ } => { | ^ error: expected one of: `*`, `+`, or `?` - --> $DIR/issue-33569.rs:6:13 + --> $DIR/issue-33569.rs:5:13 | LL | $(x)(y) | ^^^ @@ -15,27 +15,19 @@ error: missing fragment specifier | LL | { $+ } => { | ^ - -error: missing fragment specifier - --> $DIR/issue-33569.rs:2:8 | -LL | { $+ } => { - | ^ + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here | - = 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 #40107 - = note: `#[deny(missing_fragment_specifier)]` on by default +LL | { $+:spec } => { + | +++++ -error: aborting due to 4 previous errors - -Future incompatibility report: Future breakage diagnostic: error: missing fragment specifier --> $DIR/issue-33569.rs:2:8 | LL | { $+ } => { | ^ - | - = 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 #40107 - = note: `#[deny(missing_fragment_specifier)]` on by default + +error: aborting due to 4 previous errors From 61881e3c708628367565c6958d1a4e1794519797 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 10 Jun 2025 00:25:51 +0000 Subject: [PATCH 13/14] Update the stdarch submodule Includes the following changes: * Add s390x z17 target features [1] * Remove `compiler-builtins` from `rustc-dep-of-std` dependencies [2] * Darwin AArch64 detection update [3] * Fixes for the latest nightly [4] * Add a lockfile [5] [1]: https://github.com/rust-lang/stdarch/pull/1826 [2]: https://github.com/rust-lang/stdarch/pull/1825 [3]: https://github.com/rust-lang/stdarch/pull/1827 [4]: https://github.com/rust-lang/stdarch/pull/1830 [5]: https://github.com/rust-lang/stdarch/pull/1829 --- library/Cargo.lock | 1 - library/stdarch | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 966ae72dc2ad1..8e39e7a09f42b 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -353,7 +353,6 @@ name = "std_detect" version = "0.1.5" dependencies = [ "cfg-if", - "compiler_builtins", "libc", "rustc-std-workspace-alloc", "rustc-std-workspace-core", diff --git a/library/stdarch b/library/stdarch index 5c1c436524c0b..1b4d15df12079 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 5c1c436524c0bbc8db83577f42f8bea9006a7b75 +Subproject commit 1b4d15df12079504942d0a3f1030b2039b8a776c From 5f73ce2b7ebfc0234a4bc736217110a2af1e2380 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 7 May 2025 20:02:29 +0200 Subject: [PATCH 14/14] add `extern "custom"` functions --- compiler/rustc_abi/src/canon_abi.rs | 4 + compiler/rustc_abi/src/extern_abi.rs | 6 + compiler/rustc_ast/src/ast.rs | 32 ++ compiler/rustc_ast_lowering/src/stability.rs | 3 + compiler/rustc_ast_passes/messages.ftl | 17 + .../rustc_ast_passes/src/ast_validation.rs | 89 +++++- compiler/rustc_ast_passes/src/errors.rs | 64 ++++ .../rustc_codegen_cranelift/src/abi/mod.rs | 5 + compiler/rustc_codegen_gcc/src/abi.rs | 6 +- compiler/rustc_codegen_llvm/src/abi.rs | 4 + compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_hir_analysis/messages.ftl | 4 + .../rustc_hir_analysis/src/check/check.rs | 14 +- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- compiler/rustc_hir_analysis/src/errors.rs | 14 + compiler/rustc_hir_typeck/messages.ftl | 4 + compiler/rustc_hir_typeck/src/callee.rs | 18 ++ compiler/rustc_hir_typeck/src/errors.rs | 7 + compiler/rustc_hir_typeck/src/expr.rs | 10 +- compiler/rustc_hir_typeck/src/lib.rs | 6 +- compiler/rustc_middle/src/ty/layout.rs | 1 + .../rustc_smir/src/rustc_internal/internal.rs | 1 + .../rustc_smir/src/rustc_smir/convert/abi.rs | 1 + .../rustc_smir/src/rustc_smir/convert/ty.rs | 1 + compiler/rustc_smir/src/stable_mir/abi.rs | 2 + compiler/rustc_smir/src/stable_mir/ty.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/spec/abi_map.rs | 2 + tests/ui/abi/bad-custom.rs | 121 +++++++ tests/ui/abi/bad-custom.stderr | 299 ++++++++++++++++++ tests/ui/abi/custom.rs | 88 ++++++ .../feature-gates/feature-gate-abi-custom.rs | 51 +++ .../feature-gate-abi-custom.stderr | 117 +++++++ tests/ui/print-calling-conventions.stdout | 1 + 34 files changed, 988 insertions(+), 10 deletions(-) create mode 100644 tests/ui/abi/bad-custom.rs create mode 100644 tests/ui/abi/bad-custom.stderr create mode 100644 tests/ui/abi/custom.rs create mode 100644 tests/ui/feature-gates/feature-gate-abi-custom.rs create mode 100644 tests/ui/feature-gates/feature-gate-abi-custom.stderr diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 03eeb645489c3..7c020be676172 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -28,6 +28,9 @@ pub enum CanonAbi { Rust, RustCold, + /// An ABI that rustc does not know how to call or define. + Custom, + /// ABIs relevant to 32-bit Arm targets Arm(ArmCall), /// ABI relevant to GPUs: the entry point for a GPU kernel @@ -57,6 +60,7 @@ impl fmt::Display for CanonAbi { CanonAbi::C => ExternAbi::C { unwind: false }, CanonAbi::Rust => ExternAbi::Rust, CanonAbi::RustCold => ExternAbi::RustCold, + CanonAbi::Custom => ExternAbi::Custom, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false }, ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 0bc1c8a093088..7457ae1f03344 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -40,6 +40,11 @@ pub enum ExternAbi { /// Even normally-compatible Rust types can become ABI-incompatible with this ABI! Unadjusted, + /// An ABI that rustc does not know how to call or define. Functions with this ABI can + /// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only + /// be called from inline assembly. + Custom, + /// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias /// and only valid on platforms that have a UEFI standard EfiApi, @@ -141,6 +146,7 @@ abi_impls! { AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt", Cdecl { unwind: false } =><= "cdecl", Cdecl { unwind: true } =><= "cdecl-unwind", + Custom =><= "custom", EfiApi =><= "efiapi", Fastcall { unwind: false } =><= "fastcall", Fastcall { unwind: true } =><= "fastcall-unwind", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index cf40c3f7f6f8e..e50d30e25f013 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3520,6 +3520,38 @@ impl FnHeader { || matches!(constness, Const::Yes(_)) || !matches!(ext, Extern::None) } + + /// Return a span encompassing the header, or none if all options are default. + pub fn span(&self) -> Option { + fn append(a: &mut Option, b: Span) { + *a = match a { + None => Some(b), + Some(x) => Some(x.to(b)), + } + } + + let mut full_span = None; + + match self.safety { + Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span), + Safety::Default => {} + }; + + if let Some(coroutine_kind) = self.coroutine_kind { + append(&mut full_span, coroutine_kind.span()); + } + + if let Const::Yes(span) = self.constness { + append(&mut full_span, span); + } + + match self.ext { + Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span), + Extern::None => {} + } + + full_span + } } impl Default for FnHeader { diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index eb052ba1c6d78..b8fa2dd3dd626 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -134,5 +134,8 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { feature: sym::cmse_nonsecure_entry, explain: GateReason::Experimental, }), + ExternAbi::Custom => { + Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental }) + } } } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 80754a8f65a69..9a267501230fe 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -1,3 +1,20 @@ +ast_passes_abi_custom_coroutine = + functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}` + .suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton + +ast_passes_abi_custom_invalid_signature = + invalid signature for `extern "custom"` function + .note = functions with the `"custom"` ABI cannot have any parameters or return type + .suggestion = remove the parameters and return type + +ast_passes_abi_custom_safe_foreign_function = + foreign functions with the `"custom"` ABI cannot be safe + .suggestion = remove the `safe` keyword from this definition + +ast_passes_abi_custom_safe_function = + functions with the `"custom"` ABI must be unsafe + .suggestion = add the `unsafe` keyword to this definition + ast_passes_assoc_const_without_body = associated constant in `impl` without body .suggestion = provide a definition for the constant diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index d6fe04d2994b5..018887d0e8eaa 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -18,6 +18,7 @@ use std::mem; use std::ops::{Deref, DerefMut}; +use std::str::FromStr; use itertools::{Either, Itertools}; use rustc_abi::ExternAbi; @@ -81,6 +82,7 @@ struct AstValidator<'a> { /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. extern_mod_safety: Option, + extern_mod_abi: Option, lint_node_id: NodeId, @@ -121,10 +123,17 @@ impl<'a> AstValidator<'a> { self.outer_trait_or_trait_impl = old; } - fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety)); + fn with_in_extern_mod( + &mut self, + extern_mod_safety: Safety, + abi: Option, + f: impl FnOnce(&mut Self), + ) { + let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety)); + let old_abi = mem::replace(&mut self.extern_mod_abi, abi); f(self); - self.extern_mod_safety = old; + self.extern_mod_safety = old_safety; + self.extern_mod_abi = old_abi; } fn with_tilde_const( @@ -370,6 +379,65 @@ impl<'a> AstValidator<'a> { } } + /// An `extern "custom"` function must be unsafe, and must not have any parameters or return + /// type. + fn check_custom_abi(&self, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) { + let dcx = self.dcx(); + + // An `extern "custom"` function must be unsafe. + match sig.header.safety { + Safety::Unsafe(_) => { /* all good */ } + Safety::Safe(safe_span) => { + let safe_span = + self.sess.psess.source_map().span_until_non_whitespace(safe_span.to(sig.span)); + dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span }); + } + Safety::Default => match ctxt { + FnCtxt::Foreign => { /* all good */ } + FnCtxt::Free | FnCtxt::Assoc(_) => { + self.dcx().emit_err(errors::AbiCustomSafeFunction { + span: sig.span, + unsafe_span: sig.span.shrink_to_lo(), + }); + } + }, + } + + // An `extern "custom"` function cannot be `async` and/or `gen`. + if let Some(coroutine_kind) = sig.header.coroutine_kind { + let coroutine_kind_span = self + .sess + .psess + .source_map() + .span_until_non_whitespace(coroutine_kind.span().to(sig.span)); + + self.dcx().emit_err(errors::AbiCustomCoroutine { + span: sig.span, + coroutine_kind_span, + coroutine_kind_str: coroutine_kind.as_str(), + }); + } + + // An `extern "custom"` function must not have any parameters or return type. + let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect(); + if let FnRetTy::Ty(ref ret_ty) = sig.decl.output { + spans.push(ret_ty.span); + } + + if !spans.is_empty() { + let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo()); + let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span()); + let padding = if header_span.is_empty() { "" } else { " " }; + + self.dcx().emit_err(errors::AbiCustomInvalidSignature { + spans, + symbol: ident.name, + suggestion_span, + padding, + }); + } + } + /// This ensures that items can only be `unsafe` (or unmarked) outside of extern /// blocks. /// @@ -1005,7 +1073,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if abi.is_none() { self.handle_missing_abi(*extern_span, item.id); } - self.with_in_extern_mod(*safety, |this| { + + let extern_abi = abi.and_then(|abi| ExternAbi::from_str(abi.symbol.as_str()).ok()); + self.with_in_extern_mod(*safety, extern_abi, |this| { visit::walk_item(this, item); }); self.extern_mod_span = old_item; @@ -1145,6 +1215,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_fn_bodyless(*ident, body.as_deref()); self.check_foreign_fn_headerless(sig.header); self.check_foreign_item_ascii_only(*ident); + if self.extern_mod_abi == Some(ExternAbi::Custom) { + self.check_custom_abi(FnCtxt::Foreign, ident, sig); + } } ForeignItemKind::TyAlias(box TyAlias { defaultness, @@ -1352,6 +1425,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_item_safety(span, safety); } + if let FnKind::Fn(ctxt, _, fun) = fk + && let Extern::Explicit(str_lit, _) = fun.sig.header.ext + && let Ok(ExternAbi::Custom) = ExternAbi::from_str(str_lit.symbol.as_str()) + { + self.check_custom_abi(ctxt, &fun.ident, &fun.sig); + } + self.check_c_variadic_type(fk); // Functions cannot both be `const async` or `const gen` @@ -1703,6 +1783,7 @@ pub fn check_crate( outer_impl_trait_span: None, disallow_tilde_const: Some(TildeConstReason::Item), extern_mod_safety: None, + extern_mod_abi: None, lint_node_id: CRATE_NODE_ID, is_sdylib_interface, lint_buffer: lints, diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 6f9737e08314e..c437e62f4d373 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -824,3 +824,67 @@ pub(crate) struct MissingAbi { #[suggestion(code = "extern \"\"", applicability = "has-placeholders")] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_safe_foreign_function)] +pub(crate) struct AbiCustomSafeForeignFunction { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "", + style = "verbose" + )] + pub safe_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_safe_function)] +pub(crate) struct AbiCustomSafeFunction { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "unsafe ", + style = "verbose" + )] + pub unsafe_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_coroutine)] +pub(crate) struct AbiCustomCoroutine { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "", + style = "verbose" + )] + pub coroutine_kind_span: Span, + pub coroutine_kind_str: &'static str, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_invalid_signature)] +#[note] +pub(crate) struct AbiCustomInvalidSignature { + #[primary_span] + pub spans: Vec, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "{padding}fn {symbol}()", + style = "verbose" + )] + pub suggestion_span: Span, + pub symbol: Symbol, + pub padding: &'static str, +} diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index fe5b220117f3c..4c6fd90781543 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -51,6 +51,11 @@ pub(crate) fn conv_to_call_conv( CanonAbi::Rust | CanonAbi::C => default_call_conv, CanonAbi::RustCold => CallConv::Cold, + // Functions with this calling convention can only be called from assembly, but it is + // possible to declare an `extern "custom"` block, so the backend still needs a calling + // convention for declaring foreign functions. + CanonAbi::Custom => default_call_conv, + CanonAbi::X86(x86_call) => match x86_call { X86Call::SysV64 => CallConv::SystemV, X86Call::Win64 => CallConv::WindowsFastcall, diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 3d0c258f576d0..08f3d2819040f 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -239,12 +239,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option> { let attribute = match conv { CanonAbi::C | CanonAbi::Rust => return None, + CanonAbi::RustCold => FnAttribute::Cold, + // Functions with this calling convention can only be called from assembly, but it is + // possible to declare an `extern "custom"` block, so the backend still needs a calling + // convention for declaring foreign functions. + CanonAbi::Custom => return None, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall, ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry, ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"), }, - CanonAbi::RustCold => FnAttribute::Cold, CanonAbi::GpuKernel => { if arch == "amdgpu" { FnAttribute::GcnAmdGpuHsaKernel diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 119cd634f9827..aba63d75f1dfa 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -649,6 +649,10 @@ impl llvm::CallConv { match conv { CanonAbi::C | CanonAbi::Rust => llvm::CCallConv, CanonAbi::RustCold => llvm::PreserveMost, + // Functions with this calling convention can only be called from assembly, but it is + // possible to declare an `extern "custom"` block, so the backend still needs a calling + // convention for declaring foreign functions. + CanonAbi::Custom => llvm::CCallConv, CanonAbi::GpuKernel => { if arch == "amdgpu" { llvm::AmdgpuKernel diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 594021d78d2e4..cfdca8c48b0d1 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -353,6 +353,8 @@ declare_features! ( (unstable, abi_avr_interrupt, "1.45.0", Some(69664)), /// Allows `extern "C-cmse-nonsecure-call" fn()`. (unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391)), + /// Allows `extern "custom" fn()`. + (unstable, abi_custom, "CURRENT_RUSTC_VERSION", Some(140829)), /// Allows `extern "gpu-kernel" fn()`. (unstable, abi_gpu_kernel, "1.86.0", Some(135467)), /// Allows `extern "msp430-interrupt" fn()`. diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 4fcd9f8a646e3..3e98bd213d3bf 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -1,3 +1,7 @@ +hir_analysis_abi_custom_clothed_function = + items with the `"custom"` ABI can only be declared externally or defined via naked functions + .suggestion = convert this to an `#[unsafe(naked)]` function + hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}` .label = ambiguous associated {$assoc_kind} `{$assoc_ident}` diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 60ca0155bdd56..32fec0604c0f1 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::Discr; use rustc_middle::ty::{ - AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable, + AdtDef, BottomUpFolder, FnSig, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, fold_regions, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; @@ -100,6 +100,18 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex } } +pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) { + if fn_sig.abi == ExternAbi::Custom { + // Function definitions that use `extern "custom"` must be naked functions. + if !tcx.has_attr(def_id, sym::naked) { + tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction { + span: fn_sig_span, + naked_span: tcx.def_span(def_id).shrink_to_lo(), + }); + } + } +} + fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index fad8abf5fae85..c5c7e6b2aa722 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -72,7 +72,7 @@ pub mod wfcheck; use std::num::NonZero; -pub use check::{check_abi, check_abi_fn_ptr}; +pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi}; use rustc_abi::{ExternAbi, VariantIdx}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index a27d1ed6c532b..809cb311c1f5b 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1698,3 +1698,17 @@ pub(crate) struct SelfInTypeAlias { #[label] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_abi_custom_clothed_function)] +pub(crate) struct AbiCustomClothedFunction { + #[primary_span] + pub span: Span, + #[suggestion( + hir_analysis_suggestion, + applicability = "maybe-incorrect", + code = "#[unsafe(naked)]\n", + style = "short" + )] + pub naked_span: Span, +} diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 3bdd1b48666e0..ac7ff65528d94 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -1,3 +1,7 @@ +hir_typeck_abi_custom_call = + functions with the `"custom"` ABI cannot be called + .note = an `extern "custom"` function can only be called from within inline assembly + hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function hir_typeck_add_return_type_add = try adding a return type diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index d173fe7c2c26a..e915b4fc626f3 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -1,5 +1,6 @@ use std::iter; +use rustc_abi::ExternAbi; use rustc_ast::util::parser::ExprPrecedence; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; use rustc_hir::def::{self, CtorKind, Namespace, Res}; @@ -83,6 +84,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { while result.is_none() && autoderef.next().is_some() { result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef); } + self.check_call_custom_abi(autoderef.final_ty(false), call_expr.span); self.register_predicates(autoderef.into_obligations()); let output = match result { @@ -135,6 +137,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { output } + /// Functions of type `extern "custom" fn(/* ... */)` cannot be called using `ExprKind::Call`. + /// + /// These functions have a calling convention that is unknown to rust, hence it cannot generate + /// code for the call. The only way to execute such a function is via inline assembly. + fn check_call_custom_abi(&self, callee_ty: Ty<'tcx>, span: Span) { + let abi = match callee_ty.kind() { + ty::FnDef(def_id, _) => self.tcx.fn_sig(def_id).skip_binder().skip_binder().abi, + ty::FnPtr(_, header) => header.abi, + _ => return, + }; + + if let ExternAbi::Custom = abi { + self.tcx.dcx().emit_err(errors::AbiCustomCall { span }); + } + } + #[instrument(level = "debug", skip(self, call_expr, callee_expr, arg_exprs, autoderef), ret)] fn try_overloaded_call_step( &self, diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 774815015d542..abb8cdc1cdf3c 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -1163,3 +1163,10 @@ pub(crate) struct NakedFunctionsMustNakedAsm { #[label] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_abi_custom_call)] +pub(crate) struct AbiCustomCall { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index dfc7935d02bd0..87682d52dbfd3 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -5,7 +5,7 @@ //! //! See [`rustc_hir_analysis::check`] for more context on type checking in general. -use rustc_abi::{FIRST_VARIANT, FieldIdx}; +use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; @@ -1627,6 +1627,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(method.def_id), ); + // Functions of type `extern "custom" fn(/* ... */)` cannot be called using + // `ExprKind::MethodCall`. These functions have a calling convention that is + // unknown to rust, hence it cannot generate code for the call. The only way + // to execute such a function is via inline assembly. + if let ExternAbi::Custom = method.sig.abi { + self.tcx.dcx().emit_err(crate::errors::AbiCustomCall { span: expr.span }); + } + method.sig.output() } Err(error) => { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index a45a771534029..043a687914b70 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -48,7 +48,7 @@ use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_e use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, HirIdMap, Node}; -use rustc_hir_analysis::check::check_abi; +use rustc_hir_analysis::check::{check_abi, check_custom_abi}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc}; use rustc_middle::query::Providers; @@ -138,7 +138,7 @@ fn typeck_with_inspect<'tcx>( // for visit the asm expr of the body. let ty = fcx.check_expr(body.value); fcx.write_ty(id, ty); - } else if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() { + } else if let Some(hir::FnSig { header, decl, span: fn_sig_span }) = node.fn_sig() { let fn_sig = if decl.output.is_suggestable_infer_ty().is_some() { // In the case that we're recovering `fn() -> W<_>` or some other return // type that has an infer in it, lower the type directly so that it'll @@ -150,6 +150,8 @@ fn typeck_with_inspect<'tcx>( }; check_abi(tcx, id, span, fn_sig.abi()); + check_custom_abi(tcx, def_id, fn_sig.skip_binder(), *fn_sig_span); + loops::check(tcx, def_id, body); // Compute the function signature from point of view of inside the fn. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c2ae6b06192a9..9bce284568050 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1266,6 +1266,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: ExternAbi) | RiscvInterruptS | CCmseNonSecureCall | CCmseNonSecureEntry + | Custom | Unadjusted => false, Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, } diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 6e13b87c41d73..a4c6f18622218 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -496,6 +496,7 @@ impl RustcInternal for Abi { Abi::RustCold => rustc_abi::ExternAbi::RustCold, Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM, Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS, + Abi::Custom => rustc_abi::ExternAbi::Custom, } } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 46f1ca61cec6d..35d5b7fb89afd 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -101,6 +101,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi { CanonAbi::C => CallConvention::C, CanonAbi::Rust => CallConvention::Rust, CanonAbi::RustCold => CallConvention::Cold, + CanonAbi::Custom => CallConvention::Custom, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => CallConvention::ArmAapcs, ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index b0c9dba78a659..6a26f5f79974d 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -879,6 +879,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi { ExternAbi::RustCold => Abi::RustCold, ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM, ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS, + ExternAbi::Custom => Abi::Custom, } } } diff --git a/compiler/rustc_smir/src/stable_mir/abi.rs b/compiler/rustc_smir/src/stable_mir/abi.rs index 347c6ed16a245..d8a2b97662c45 100644 --- a/compiler/rustc_smir/src/stable_mir/abi.rs +++ b/compiler/rustc_smir/src/stable_mir/abi.rs @@ -430,6 +430,8 @@ pub enum CallConvention { PreserveMost, PreserveAll, + Custom, + // Target-specific calling conventions. ArmAapcs, CCmseNonSecureCall, diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 4461b4ae1250c..0b79cec0d45a8 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1103,6 +1103,7 @@ pub enum Abi { RustCold, RiscvInterruptM, RiscvInterruptS, + Custom, } /// A binder represents a possibly generic type and its bound vars. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d66f98871b97d..7f3fe1876a83f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -407,6 +407,7 @@ symbols! { abi_amdgpu_kernel, abi_avr_interrupt, abi_c_cmse_nonsecure_call, + abi_custom, abi_efiapi, abi_gpu_kernel, abi_msp430_interrupt, diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index c4978a8e52a95..4659bbdb89090 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -71,6 +71,8 @@ impl AbiMap { (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust, (ExternAbi::RustCold, _) => CanonAbi::RustCold, + (ExternAbi::Custom, _) => CanonAbi::Custom, + (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => { CanonAbi::X86(X86Call::Stdcall) } diff --git a/tests/ui/abi/bad-custom.rs b/tests/ui/abi/bad-custom.rs new file mode 100644 index 0000000000000..e792f0955b916 --- /dev/null +++ b/tests/ui/abi/bad-custom.rs @@ -0,0 +1,121 @@ +//@ edition: 2021 +//@ check-fail +//@ needs-asm-support +#![feature(abi_custom)] + +#[unsafe(naked)] +extern "custom" fn must_be_unsafe(a: i64) -> i64 { + //~^ ERROR functions with the `"custom"` ABI must be unsafe + //~| ERROR invalid signature for `extern "custom"` function + std::arch::naked_asm!("") +} + +#[unsafe(naked)] +unsafe extern "custom" fn no_parameters(a: i64) { + //~^ ERROR invalid signature for `extern "custom"` function + std::arch::naked_asm!("") +} + +#[unsafe(naked)] +unsafe extern "custom" fn no_return_type() -> i64 { + //~^ ERROR invalid signature for `extern "custom"` function + std::arch::naked_asm!("") +} + +unsafe extern "custom" fn double(a: i64) -> i64 { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR invalid signature for `extern "custom"` function + unimplemented!() +} + +struct Thing(i64); + +impl Thing { + unsafe extern "custom" fn is_even(self) -> bool { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR invalid signature for `extern "custom"` function + unimplemented!() + } +} + +trait BitwiseNot { + unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR invalid signature for `extern "custom"` function + unimplemented!() + } +} + +impl BitwiseNot for Thing {} + +trait Negate { + extern "custom" fn negate(a: i64) -> i64; + //~^ ERROR functions with the `"custom"` ABI must be unsafe + //~| ERROR invalid signature for `extern "custom"` function +} + +impl Negate for Thing { + extern "custom" fn negate(a: i64) -> i64 { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR functions with the `"custom"` ABI must be unsafe + //~| ERROR invalid signature for `extern "custom"` function + -a + } +} + +unsafe extern "custom" { + fn increment(a: i64) -> i64; + //~^ ERROR invalid signature for `extern "custom"` function + + safe fn extern_cannot_be_safe(); + //~^ ERROR foreign functions with the `"custom"` ABI cannot be safe +} + +fn caller(f: unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 { + unsafe { f(x) } + //~^ ERROR functions with the `"custom"` ABI cannot be called +} + +fn caller_by_ref(f: &unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 { + unsafe { f(x) } + //~^ ERROR functions with the `"custom"` ABI cannot be called +} + +type Custom = unsafe extern "custom" fn(i64) -> i64; + +fn caller_alias(f: Custom, mut x: i64) -> i64 { + unsafe { f(x) } + //~^ ERROR functions with the `"custom"` ABI cannot be called +} + +#[unsafe(naked)] +const unsafe extern "custom" fn no_const_fn() { + std::arch::naked_asm!("") + //~^ ERROR inline assembly is not allowed in constant functions +} + +async unsafe extern "custom" fn no_async_fn() { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR functions with the `"custom"` ABI cannot be `async` +} + +fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() { + //~^ ERROR expected a `Fn()` closure, found `unsafe extern "custom" fn()` + f +} + +pub fn main() { + unsafe { + assert_eq!(double(21), 42); + //~^ ERROR functions with the `"custom"` ABI cannot be called + + assert_eq!(unsafe { increment(41) }, 42); + //~^ ERROR functions with the `"custom"` ABI cannot be called + + assert!(Thing(41).is_even()); + //~^ ERROR functions with the `"custom"` ABI cannot be called + + assert_eq!(Thing::bitwise_not(42), !42); + //~^ ERROR functions with the `"custom"` ABI cannot be called + } +} diff --git a/tests/ui/abi/bad-custom.stderr b/tests/ui/abi/bad-custom.stderr new file mode 100644 index 0000000000000..ec0f11af89804 --- /dev/null +++ b/tests/ui/abi/bad-custom.stderr @@ -0,0 +1,299 @@ +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/bad-custom.rs:7:1 + | +LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn must_be_unsafe(a: i64) -> i64 { + | ++++++ + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:7:35 + | +LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "custom" fn must_be_unsafe(a: i64) -> i64 { +LL + extern "custom" fn must_be_unsafe() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:14:41 + | +LL | unsafe extern "custom" fn no_parameters(a: i64) { + | ^^^^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn no_parameters(a: i64) { +LL + unsafe extern "custom" fn no_parameters() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:20:47 + | +LL | unsafe extern "custom" fn no_return_type() -> i64 { + | ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn no_return_type() -> i64 { +LL + unsafe extern "custom" fn no_return_type() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:25:34 + | +LL | unsafe extern "custom" fn double(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn double(a: i64) -> i64 { +LL + unsafe extern "custom" fn double() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:34:39 + | +LL | unsafe extern "custom" fn is_even(self) -> bool { + | ^^^^ ^^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn is_even(self) -> bool { +LL + unsafe extern "custom" fn is_even() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:42:43 + | +LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { +LL + unsafe extern "custom" fn bitwise_not() { + | + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/bad-custom.rs:52:5 + | +LL | extern "custom" fn negate(a: i64) -> i64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn negate(a: i64) -> i64; + | ++++++ + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:52:31 + | +LL | extern "custom" fn negate(a: i64) -> i64; + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "custom" fn negate(a: i64) -> i64; +LL + extern "custom" fn negate(); + | + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/bad-custom.rs:58:5 + | +LL | extern "custom" fn negate(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn negate(a: i64) -> i64 { + | ++++++ + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:58:31 + | +LL | extern "custom" fn negate(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "custom" fn negate(a: i64) -> i64 { +LL + extern "custom" fn negate() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:67:18 + | +LL | fn increment(a: i64) -> i64; + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - fn increment(a: i64) -> i64; +LL + fn increment(); + | + +error: foreign functions with the `"custom"` ABI cannot be safe + --> $DIR/bad-custom.rs:70:5 + | +LL | safe fn extern_cannot_be_safe(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `safe` keyword from this definition + | +LL - safe fn extern_cannot_be_safe(); +LL + fn extern_cannot_be_safe(); + | + +error: functions with the `"custom"` ABI cannot be `async` + --> $DIR/bad-custom.rs:97:1 + | +LL | async unsafe extern "custom" fn no_async_fn() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `async` keyword from this definiton + | +LL - async unsafe extern "custom" fn no_async_fn() { +LL + unsafe extern "custom" fn no_async_fn() { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:97:1 + | +LL | async unsafe extern "custom" fn no_async_fn() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | async unsafe extern "custom" fn no_async_fn() { + | + +error[E0277]: expected a `Fn()` closure, found `unsafe extern "custom" fn()` + --> $DIR/bad-custom.rs:102:64 + | +LL | fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() { + | ^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` +LL | +LL | f + | - return type was inferred to be `unsafe extern "custom" fn()` here + | + = help: the trait `Fn()` is not implemented for `unsafe extern "custom" fn()` + = note: unsafe function cannot be called generically without an unsafe block + = note: wrap the `unsafe extern "custom" fn()` in a closure with no arguments: `|| { /* code */ }` + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:25:1 + | +LL | unsafe extern "custom" fn double(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | unsafe extern "custom" fn double(a: i64) -> i64 { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:34:5 + | +LL | unsafe extern "custom" fn is_even(self) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | unsafe extern "custom" fn is_even(self) -> bool { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:42:5 + | +LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:58:5 + | +LL | extern "custom" fn negate(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | extern "custom" fn negate(a: i64) -> i64 { + | + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:75:14 + | +LL | unsafe { f(x) } + | ^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:80:14 + | +LL | unsafe { f(x) } + | ^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:87:14 + | +LL | unsafe { f(x) } + | ^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:109:20 + | +LL | assert_eq!(double(21), 42); + | ^^^^^^^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:112:29 + | +LL | assert_eq!(unsafe { increment(41) }, 42); + | ^^^^^^^^^^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:115:17 + | +LL | assert!(Thing(41).is_even()); + | ^^^^^^^^^^^^^^^^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:118:20 + | +LL | assert_eq!(Thing::bitwise_not(42), !42); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0015]: inline assembly is not allowed in constant functions + --> $DIR/bad-custom.rs:93:5 + | +LL | std::arch::naked_asm!("") + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 28 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/abi/custom.rs b/tests/ui/abi/custom.rs new file mode 100644 index 0000000000000..0f6ff77f58084 --- /dev/null +++ b/tests/ui/abi/custom.rs @@ -0,0 +1,88 @@ +// Test that `extern "custom"` functions can be called from assembly, and defined using a naked +// function, and `global_asm!` with an `extern "custom"` block. +// +//@ run-pass +//@ only-x86_64 +#![feature(abi_custom)] + +use std::arch::{asm, global_asm, naked_asm}; + +#[unsafe(naked)] +unsafe extern "custom" fn double() { + naked_asm!("add rax, rax", "ret"); +} + +global_asm!( + // work around macOS prefixing symbols with _ + " .globl {0}", + "{0}:", + " add rax, 1", + " ret", + sym increment, +); + +unsafe extern "custom" { + fn increment(); +} + +#[repr(transparent)] +struct Thing(u64); + +impl Thing { + #[unsafe(naked)] + unsafe extern "custom" fn is_even() { + naked_asm!("test al, 1", "sete al", "ret"); + } +} + +trait BitwiseNot { + #[unsafe(naked)] + unsafe extern "custom" fn bitwise_not() { + naked_asm!("not rax", "ret"); + } +} + +impl BitwiseNot for Thing {} + +#[unsafe(naked)] +unsafe extern "C" fn const_generic() { + naked_asm!( + "mov rax, {}", + "ret", + const N, + ); +} + +pub fn main() { + let mut x: u64 = 21; + unsafe { asm!("call {}", sym double, inout("rax") x) }; + assert_eq!(x, 42); + + let mut x: u64 = 41; + unsafe { asm!("call {}", sym increment, inout("rax") x) }; + assert_eq!(x, 42); + + let mut x: u8; + unsafe { asm!("call {}", sym Thing::is_even, inout("al") 42u8 => x) }; + assert!(x != 0); + + let mut x: u64 = 42; + unsafe { asm!("call {}", sym Thing::bitwise_not, inout("rax") x) }; + assert_eq!(x, !42); + + // Create and call in `asm!` an `extern "custom"` function pointer. + fn caller(f: unsafe extern "custom" fn(), mut x: u64) -> u64 { + unsafe { asm!("call {}", in(reg) f, inout("rax") x) }; + x + } + + assert_eq!(caller(double, 2), 4); + + let x: u64; + unsafe { asm!("call {}", sym const_generic::<42>, out("rax") x) }; + assert_eq!(x, 42); + + let x: u64; + unsafe { asm!("call {}", sym const_generic::<84>, out("rax") x) }; + assert_eq!(x, 84); +} diff --git a/tests/ui/feature-gates/feature-gate-abi-custom.rs b/tests/ui/feature-gates/feature-gate-abi-custom.rs new file mode 100644 index 0000000000000..3ddce974dd7d4 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-abi-custom.rs @@ -0,0 +1,51 @@ +//@ add-core-stubs +//@ needs-asm-support +#![no_core] +#![feature(no_core, lang_items)] +#![crate_type = "rlib"] + +extern crate minicore; +use minicore::*; + +#[unsafe(naked)] +unsafe extern "custom" fn f7() { + //~^ ERROR "custom" ABI is experimental + naked_asm!("") +} +trait Tr { + extern "custom" fn m7(); + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + #[unsafe(naked)] + extern "custom" fn dm7() { + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + naked_asm!("") + } +} + +struct S; + +// Methods in trait impl +impl Tr for S { + #[unsafe(naked)] + extern "custom" fn m7() { + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + naked_asm!("") + } +} + +// Methods in inherent impl +impl S { + #[unsafe(naked)] + extern "custom" fn im7() { + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + naked_asm!("") + } +} + +type A7 = extern "custom" fn(); //~ ERROR "custom" ABI is experimental + +extern "custom" {} //~ ERROR "custom" ABI is experimental diff --git a/tests/ui/feature-gates/feature-gate-abi-custom.stderr b/tests/ui/feature-gates/feature-gate-abi-custom.stderr new file mode 100644 index 0000000000000..e6dce0126d643 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-abi-custom.stderr @@ -0,0 +1,117 @@ +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:16:5 + | +LL | extern "custom" fn m7(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn m7(); + | ++++++ + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:20:5 + | +LL | extern "custom" fn dm7() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn dm7() { + | ++++++ + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:32:5 + | +LL | extern "custom" fn m7() { + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn m7() { + | ++++++ + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:42:5 + | +LL | extern "custom" fn im7() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn im7() { + | ++++++ + +error[E0658]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:11:15 + | +LL | unsafe extern "custom" fn f7() { + | ^^^^^^^^ + | + = note: see issue #140829 for more information + = help: add `#![feature(abi_custom)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:16:12 + | +LL | extern "custom" fn m7(); + | ^^^^^^^^ + | + = note: see issue #140829 for more information + = help: add `#![feature(abi_custom)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:20:12 + | +LL | extern "custom" fn dm7() { + | ^^^^^^^^ + | + = note: see issue #140829 for more information + = help: add `#![feature(abi_custom)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:32:12 + | +LL | extern "custom" fn m7() { + | ^^^^^^^^ + | + = note: see issue #140829 for more information + = help: add `#![feature(abi_custom)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:42:12 + | +LL | extern "custom" fn im7() { + | ^^^^^^^^ + | + = note: see issue #140829 for more information + = help: add `#![feature(abi_custom)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:49:18 + | +LL | type A7 = extern "custom" fn(); + | ^^^^^^^^ + | + = note: see issue #140829 for more information + = help: add `#![feature(abi_custom)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:51:8 + | +LL | extern "custom" {} + | ^^^^^^^^ + | + = note: see issue #140829 for more information + = help: add `#![feature(abi_custom)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout index feee8cc3aa9c3..7b5ae49566062 100644 --- a/tests/ui/print-calling-conventions.stdout +++ b/tests/ui/print-calling-conventions.stdout @@ -9,6 +9,7 @@ avr-interrupt avr-non-blocking-interrupt cdecl cdecl-unwind +custom efiapi fastcall fastcall-unwind