about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl5
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs88
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs7
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
5 files changed, 99 insertions, 4 deletions
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 73be954cefd..9e0fe255e99 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -1,6 +1,11 @@
 builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function
 builtin_macros_alloc_must_statics = allocators must be statics
 
+builtin_macros_asm_attribute_not_supported =
+    this attribute is not supported on assembly
+builtin_macros_asm_cfg =
+    the `#[cfg(/* ... */)]` and `#[cfg_attr(/* ... */)]` attributes on assembly are unstable
+
 builtin_macros_asm_clobber_abi = clobber_abi
 builtin_macros_asm_clobber_no_reg = asm with `clobber_abi` must specify explicit registers for outputs
 builtin_macros_asm_clobber_outputs = generic outputs
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 62ee71fecc2..593d9ddfdf8 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -10,18 +10,20 @@ use rustc_index::bit_set::GrowableBitSet;
 use rustc_parse::exp;
 use rustc_parse::parser::{ExpKeywordPair, Parser};
 use rustc_session::lint;
-use rustc_span::{ErrorGuaranteed, InnerSpan, Span, Symbol, kw};
+use rustc_session::parse::feature_err;
+use rustc_span::{ErrorGuaranteed, InnerSpan, Span, Symbol, kw, sym};
 use rustc_target::asm::InlineAsmArch;
 use smallvec::smallvec;
 use {rustc_ast as ast, rustc_parse_format as parse};
 
-use crate::errors;
 use crate::util::{ExprToSpannedString, expr_to_spanned_string};
+use crate::{errors, fluent_generated as fluent};
 
 /// An argument to one of the `asm!` macros. The argument is syntactically valid, but is otherwise
 /// not validated at all.
 pub struct AsmArg {
     pub kind: AsmArgKind,
+    pub attributes: AsmAttrVec,
     pub span: Span,
 }
 
@@ -52,6 +54,44 @@ struct ValidatedAsmArgs {
     pub options_spans: Vec<Span>,
 }
 
+/// A parsed list of attributes that is not attached to any item.
+/// Used to check whether `asm!` arguments are configured out.
+pub struct AsmAttrVec(pub ast::AttrVec);
+
+impl AsmAttrVec {
+    fn parse<'a>(p: &mut Parser<'a>) -> PResult<'a, Self> {
+        let mut attributes = ast::AttrVec::new();
+        while p.token == token::Pound {
+            let attr = p.parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted)?;
+            attributes.push(attr);
+        }
+
+        Ok(Self(attributes))
+    }
+}
+impl ast::HasAttrs for AsmAttrVec {
+    // Follows `ast::Expr`.
+    const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
+
+    fn attrs(&self) -> &[rustc_ast::Attribute] {
+        &self.0
+    }
+
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut rustc_ast::AttrVec)) {
+        f(&mut self.0)
+    }
+}
+
+impl ast::HasTokens for AsmAttrVec {
+    fn tokens(&self) -> Option<&rustc_ast::tokenstream::LazyAttrTokenStream> {
+        None
+    }
+
+    fn tokens_mut(&mut self) -> Option<&mut Option<rustc_ast::tokenstream::LazyAttrTokenStream>> {
+        None
+    }
+}
+
 /// Used for better error messages when operand types are used that are not
 /// supported by the current macro (e.g. `in` or `out` for `global_asm!`)
 ///
@@ -167,8 +207,13 @@ pub fn parse_asm_args<'a>(
 
     let mut args = Vec::new();
 
+    let attributes = AsmAttrVec::parse(p)?;
     let first_template = p.parse_expr()?;
-    args.push(AsmArg { span: first_template.span, kind: AsmArgKind::Template(first_template) });
+    args.push(AsmArg {
+        span: first_template.span,
+        kind: AsmArgKind::Template(first_template),
+        attributes,
+    });
 
     let mut allow_templates = true;
 
@@ -188,6 +233,7 @@ pub fn parse_asm_args<'a>(
             break;
         }
 
+        let attributes = AsmAttrVec::parse(p)?;
         let span_start = p.token.span;
 
         // Parse `clobber_abi`.
@@ -197,6 +243,7 @@ pub fn parse_asm_args<'a>(
             args.push(AsmArg {
                 kind: AsmArgKind::ClobberAbi(parse_clobber_abi(p)?),
                 span: span_start.to(p.prev_token.span),
+                attributes,
             });
 
             continue;
@@ -209,6 +256,7 @@ pub fn parse_asm_args<'a>(
             args.push(AsmArg {
                 kind: AsmArgKind::Options(parse_options(p, asm_macro)?),
                 span: span_start.to(p.prev_token.span),
+                attributes,
             });
 
             continue;
@@ -231,6 +279,7 @@ pub fn parse_asm_args<'a>(
             args.push(AsmArg {
                 span: span_start.to(p.prev_token.span),
                 kind: AsmArgKind::Operand(name, op),
+                attributes,
             });
         } else if allow_templates {
             let template = p.parse_expr()?;
@@ -252,7 +301,11 @@ pub fn parse_asm_args<'a>(
                 }
             }
 
-            args.push(AsmArg { span: template.span, kind: AsmArgKind::Template(template) });
+            args.push(AsmArg {
+                span: template.span,
+                kind: AsmArgKind::Template(template),
+                attributes,
+            });
         } else {
             p.unexpected_any()?
         }
@@ -278,6 +331,13 @@ fn validate_asm_args<'a>(
 ) -> PResult<'a, ValidatedAsmArgs> {
     let dcx = ecx.dcx();
 
+    let strip_unconfigured = rustc_expand::config::StripUnconfigured {
+        sess: ecx.sess,
+        features: Some(ecx.ecfg.features),
+        config_tokens: false,
+        lint_node_id: ecx.current_expansion.lint_node_id,
+    };
+
     let mut validated = ValidatedAsmArgs {
         templates: vec![],
         operands: vec![],
@@ -291,6 +351,26 @@ fn validate_asm_args<'a>(
     let mut allow_templates = true;
 
     for arg in args {
+        for attr in arg.attributes.0.iter() {
+            match attr.name() {
+                Some(sym::cfg | sym::cfg_attr) => {
+                    if !ecx.ecfg.features.asm_cfg() {
+                        let span = attr.span();
+                        feature_err(ecx.sess, sym::asm_cfg, span, fluent::builtin_macros_asm_cfg)
+                            .emit();
+                    }
+                }
+                _ => {
+                    ecx.dcx().emit_err(errors::AsmAttributeNotSupported { span: attr.span() });
+                }
+            }
+        }
+
+        // Skip arguments that are configured out.
+        if ecx.ecfg.features.asm_cfg() && strip_unconfigured.configure(arg.attributes).is_none() {
+            continue;
+        }
+
         match arg.kind {
             AsmArgKind::Template(template) => {
                 // The error for the first template is delayed.
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index b28f7d312d9..73e8fed321c 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -796,6 +796,13 @@ pub(crate) struct AsmRequiresTemplate {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_asm_attribute_not_supported)]
+pub(crate) struct AsmAttributeNotSupported {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_asm_expected_comma)]
 pub(crate) struct AsmExpectedComma {
     #[primary_span]
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 6cdcf451f37..3e408a03111 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -371,6 +371,8 @@ declare_features! (
     (unstable, arbitrary_self_types, "1.23.0", Some(44874)),
     /// Allows inherent and trait methods with arbitrary self types that are raw pointers.
     (unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)),
+    /// Allows #[cfg(...)] on inline assembly templates and operands.
+    (unstable, asm_cfg, "CURRENT_RUSTC_VERSION", Some(140364)),
     /// Enables experimental inline assembly support for additional architectures.
     (unstable, asm_experimental_arch, "1.58.0", Some(93335)),
     /// Enables experimental register support in inline assembly.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index fbe3b4ca6f5..391d820faad 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -475,6 +475,7 @@ symbols! {
         as_ref,
         as_str,
         asm,
+        asm_cfg,
         asm_const,
         asm_experimental_arch,
         asm_experimental_reg,