@@ -10,18 +10,20 @@ use rustc_index::bit_set::GrowableBitSet;
1010use rustc_parse:: exp;
1111use rustc_parse:: parser:: { ExpKeywordPair , Parser } ;
1212use rustc_session:: lint;
13- use rustc_span:: { ErrorGuaranteed , InnerSpan , Span , Symbol , kw} ;
13+ use rustc_session:: parse:: feature_err;
14+ use rustc_span:: { ErrorGuaranteed , InnerSpan , Span , Symbol , kw, sym} ;
1415use rustc_target:: asm:: InlineAsmArch ;
1516use smallvec:: smallvec;
1617use { rustc_ast as ast, rustc_parse_format as parse} ;
1718
18- use crate :: errors;
1919use crate :: util:: { ExprToSpannedString , expr_to_spanned_string} ;
20+ use crate :: { errors, fluent_generated as fluent} ;
2021
2122/// An argument to one of the `asm!` macros. The argument is syntactically valid, but is otherwise
2223/// not validated at all.
2324pub struct RawAsmArg {
2425 pub kind : RawAsmArgKind ,
26+ pub attributes : AsmAttrVec ,
2527 pub span : Span ,
2628}
2729
@@ -43,6 +45,48 @@ struct AsmArgs {
4345 pub options_spans : Vec < Span > ,
4446}
4547
48+ /// A parsed list of attributes that is not attached to any item.
49+ /// Used to check whether `asm!` arguments are configured out.
50+ pub struct AsmAttrVec ( pub ast:: AttrVec ) ;
51+
52+ impl AsmAttrVec {
53+ fn parse < ' a > ( p : & mut Parser < ' a > ) -> PResult < ' a , Self > {
54+ let mut attributes = ast:: AttrVec :: new ( ) ;
55+ loop {
56+ if p. token != token:: Pound {
57+ break ;
58+ }
59+
60+ let attr = p. parse_attribute ( rustc_parse:: parser:: attr:: InnerAttrPolicy :: Permitted ) ?;
61+ attributes. push ( attr) ;
62+ }
63+
64+ Ok ( Self ( attributes) )
65+ }
66+ }
67+ impl ast:: HasAttrs for AsmAttrVec {
68+ // Follows `ast::Expr`.
69+ const SUPPORTS_CUSTOM_INNER_ATTRS : bool = false ;
70+
71+ fn attrs ( & self ) -> & [ rustc_ast:: Attribute ] {
72+ & self . 0
73+ }
74+
75+ fn visit_attrs ( & mut self , f : impl FnOnce ( & mut rustc_ast:: AttrVec ) ) {
76+ f ( & mut self . 0 )
77+ }
78+ }
79+
80+ impl ast:: HasTokens for AsmAttrVec {
81+ fn tokens ( & self ) -> Option < & rustc_ast:: tokenstream:: LazyAttrTokenStream > {
82+ None
83+ }
84+
85+ fn tokens_mut ( & mut self ) -> Option < & mut Option < rustc_ast:: tokenstream:: LazyAttrTokenStream > > {
86+ None
87+ }
88+ }
89+
4690/// Used for better error messages when operand types are used that are not
4791/// supported by the current macro (e.g. `in` or `out` for `global_asm!`)
4892///
@@ -158,10 +202,12 @@ pub fn parse_raw_asm_args<'a>(
158202
159203 let mut args = Vec :: new ( ) ;
160204
205+ let attributes = AsmAttrVec :: parse ( p) ?;
161206 let first_template = p. parse_expr ( ) ?;
162207 args. push ( RawAsmArg {
163208 span : first_template. span ,
164209 kind : RawAsmArgKind :: Template ( first_template) ,
210+ attributes,
165211 } ) ;
166212
167213 let mut allow_templates = true ;
@@ -180,6 +226,7 @@ pub fn parse_raw_asm_args<'a>(
180226 break ;
181227 } // accept trailing commas
182228
229+ let attributes = AsmAttrVec :: parse ( p) ?;
183230 let span_start = p. token . span ;
184231
185232 // Parse clobber_abi
@@ -189,6 +236,7 @@ pub fn parse_raw_asm_args<'a>(
189236 args. push ( RawAsmArg {
190237 kind : RawAsmArgKind :: ClobberAbi ( parse_clobber_abi ( p) ?) ,
191238 span : span_start. to ( p. prev_token . span ) ,
239+ attributes,
192240 } ) ;
193241
194242 continue ;
@@ -201,6 +249,7 @@ pub fn parse_raw_asm_args<'a>(
201249 args. push ( RawAsmArg {
202250 kind : RawAsmArgKind :: Options ( parse_options ( p, asm_macro) ?) ,
203251 span : span_start. to ( p. prev_token . span ) ,
252+ attributes,
204253 } ) ;
205254
206255 continue ;
@@ -223,6 +272,7 @@ pub fn parse_raw_asm_args<'a>(
223272 args. push ( RawAsmArg {
224273 span : span_start. to ( p. prev_token . span ) ,
225274 kind : RawAsmArgKind :: Operand ( name, op) ,
275+ attributes,
226276 } ) ;
227277 } else if allow_templates {
228278 let template = p. parse_expr ( ) ?;
@@ -244,7 +294,11 @@ pub fn parse_raw_asm_args<'a>(
244294 }
245295 }
246296
247- args. push ( RawAsmArg { span : template. span , kind : RawAsmArgKind :: Template ( template) } ) ;
297+ args. push ( RawAsmArg {
298+ span : template. span ,
299+ kind : RawAsmArgKind :: Template ( template) ,
300+ attributes,
301+ } ) ;
248302 } else {
249303 p. unexpected_any ( ) ?
250304 }
@@ -270,6 +324,13 @@ fn validate_raw_asm_args<'a>(
270324) -> PResult < ' a , AsmArgs > {
271325 let dcx = ecx. dcx ( ) ;
272326
327+ let strip_unconfigured = rustc_expand:: config:: StripUnconfigured {
328+ sess : ecx. sess ,
329+ features : Some ( ecx. ecfg . features ) ,
330+ config_tokens : false ,
331+ lint_node_id : ecx. current_expansion . lint_node_id ,
332+ } ;
333+
273334 let mut args = AsmArgs {
274335 templates : vec ! [ ] ,
275336 operands : vec ! [ ] ,
@@ -283,6 +344,26 @@ fn validate_raw_asm_args<'a>(
283344 let mut allow_templates = true ;
284345
285346 for arg in raw_args {
347+ for attr in arg. attributes . 0 . iter ( ) {
348+ match attr. name ( ) {
349+ Some ( sym:: cfg | sym:: cfg_attr) => {
350+ if !ecx. ecfg . features . asm_cfg ( ) {
351+ let span = attr. span ( ) ;
352+ feature_err ( ecx. sess , sym:: asm_cfg, span, fluent:: builtin_macros_asm_cfg)
353+ . emit ( ) ;
354+ }
355+ }
356+ _ => {
357+ ecx. dcx ( ) . emit_err ( errors:: AsmAttributeNotSupported { span : attr. span ( ) } ) ;
358+ }
359+ }
360+ }
361+
362+ // Skip arguments that are configured out.
363+ if ecx. ecfg . features . asm_cfg ( ) && strip_unconfigured. configure ( arg. attributes ) . is_none ( ) {
364+ continue ;
365+ }
366+
286367 match arg. kind {
287368 RawAsmArgKind :: Template ( template) => {
288369 // The error for the first template is delayed.
0 commit comments