1use rustc_ast as ast;
2use rustc_ast::tokenstream::TokenStream;
3use rustc_ast::{AsmMacro, token};
4use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
5use rustc_errors::PResult;
6use rustc_expand::base::*;
7use rustc_index::bit_set::GrowableBitSet;
8use rustc_parse::parser::asm::*;
9use rustc_parse_format as parse;
10use rustc_session::lint;
11use rustc_span::{ErrorGuaranteed, InnerSpan, Span, Symbol, sym};
12use rustc_target::asm::InlineAsmArch;
13use smallvec::smallvec;
14
15use crate::errors;
16use crate::util::{ExprToSpannedString, expr_to_spanned_string};
17
18struct ValidatedAsmArgs {
20 pub templates: Vec<Box<ast::Expr>>,
21 pub operands: Vec<(ast::InlineAsmOperand, Span)>,
22 named_args: FxIndexMap<Symbol, usize>,
23 reg_args: GrowableBitSet<usize>,
24 pub clobber_abis: Vec<(Symbol, Span)>,
25 options: ast::InlineAsmOptions,
26 pub options_spans: Vec<Span>,
27}
28
29fn parse_args<'a>(
30 ecx: &ExtCtxt<'a>,
31 sp: Span,
32 tts: TokenStream,
33 asm_macro: AsmMacro,
34) -> PResult<'a, ValidatedAsmArgs> {
35 let args = parse_asm_args(&mut ecx.new_parser_from_tts(tts), sp, asm_macro)?;
36 validate_asm_args(ecx, asm_macro, args)
37}
38
39fn validate_asm_args<'a>(
40 ecx: &ExtCtxt<'a>,
41 asm_macro: AsmMacro,
42 args: Vec<AsmArg>,
43) -> PResult<'a, ValidatedAsmArgs> {
44 let dcx = ecx.dcx();
45
46 let strip_unconfigured = rustc_expand::config::StripUnconfigured {
47 sess: ecx.sess,
48 features: Some(ecx.ecfg.features),
49 config_tokens: false,
50 lint_node_id: ecx.current_expansion.lint_node_id,
51 };
52
53 let mut validated = ValidatedAsmArgs {
54 templates: ::alloc::vec::Vec::new()vec![],
55 operands: ::alloc::vec::Vec::new()vec![],
56 named_args: Default::default(),
57 reg_args: Default::default(),
58 clobber_abis: Vec::new(),
59 options: ast::InlineAsmOptions::empty(),
60 options_spans: ::alloc::vec::Vec::new()vec![],
61 };
62
63 let mut allow_templates = true;
64
65 for arg in args {
66 for attr in arg.attributes.0.iter() {
67 if !#[allow(non_exhaustive_omitted_patterns)] match attr.name() {
Some(sym::cfg | sym::cfg_attr) => true,
_ => false,
}matches!(attr.name(), Some(sym::cfg | sym::cfg_attr)) {
68 ecx.dcx().emit_err(errors::AsmAttributeNotSupported { span: attr.span() });
69 }
70 }
71
72 if strip_unconfigured.configure(arg.attributes).is_none() {
74 continue;
75 }
76
77 match arg.kind {
78 AsmArgKind::Template(template) => {
79 if !allow_templates {
81 match template.kind {
82 ast::ExprKind::Lit(token_lit)
83 if #[allow(non_exhaustive_omitted_patterns)] match token_lit.kind {
token::LitKind::Str | token::LitKind::StrRaw(_) => true,
_ => false,
}matches!(
84 token_lit.kind,
85 token::LitKind::Str | token::LitKind::StrRaw(_)
86 ) => {}
87 ast::ExprKind::MacCall(..) => {}
88 _ => {
89 let err = dcx.create_err(errors::AsmExpectedOther {
90 span: template.span,
91 is_inline_asm: #[allow(non_exhaustive_omitted_patterns)] match asm_macro {
AsmMacro::Asm => true,
_ => false,
}matches!(asm_macro, AsmMacro::Asm),
92 });
93 return Err(err);
94 }
95 }
96 }
97
98 validated.templates.push(template);
99 }
100 AsmArgKind::Operand(name, op) => {
101 allow_templates = false;
102
103 let explicit_reg = #[allow(non_exhaustive_omitted_patterns)] match op.reg() {
Some(ast::InlineAsmRegOrRegClass::Reg(_)) => true,
_ => false,
}matches!(op.reg(), Some(ast::InlineAsmRegOrRegClass::Reg(_)));
104 let span = arg.span;
105 let slot = validated.operands.len();
106 validated.operands.push((op, span));
107
108 if explicit_reg {
113 if name.is_some() {
114 dcx.emit_err(errors::AsmExplicitRegisterName { span });
115 }
116 validated.reg_args.insert(slot);
117 } else if let Some(name) = name {
118 if let Some(&prev) = validated.named_args.get(&name) {
119 dcx.emit_err(errors::AsmDuplicateArg {
120 span,
121 name,
122 prev: validated.operands[prev].1,
123 });
124 continue;
125 }
126 validated.named_args.insert(name, slot);
127 } else if !validated.named_args.is_empty() || !validated.reg_args.is_empty() {
128 let named =
129 validated.named_args.values().map(|p| validated.operands[*p].1).collect();
130 let explicit =
131 validated.reg_args.iter().map(|p| validated.operands[p].1).collect();
132
133 dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit });
134 }
135 }
136 AsmArgKind::Options(new_options) => {
137 allow_templates = false;
138
139 for asm_option in new_options {
140 let AsmOption { span, symbol, span_with_comma, options } = asm_option;
141
142 if !asm_macro.is_supported_option(options) {
143 dcx.emit_err(errors::AsmUnsupportedOption {
145 span,
146 symbol,
147 span_with_comma,
148 macro_name: asm_macro.macro_name(),
149 });
150 } else if validated.options.contains(options) {
151 dcx.emit_err(errors::AsmOptAlreadyprovided {
153 span,
154 symbol,
155 span_with_comma,
156 });
157 } else {
158 validated.options |= asm_option.options;
159 }
160 }
161
162 validated.options_spans.push(arg.span);
163 }
164 AsmArgKind::ClobberAbi(new_abis) => {
165 allow_templates = false;
166
167 match &new_abis[..] {
168 [] => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
170 [(abi, _span)] => validated.clobber_abis.push((*abi, arg.span)),
171 _ => validated.clobber_abis.extend(new_abis),
172 }
173 }
174 }
175 }
176
177 if validated.options.contains(ast::InlineAsmOptions::NOMEM)
178 && validated.options.contains(ast::InlineAsmOptions::READONLY)
179 {
180 let spans = validated.options_spans.clone();
181 dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" });
182 }
183 if validated.options.contains(ast::InlineAsmOptions::PURE)
184 && validated.options.contains(ast::InlineAsmOptions::NORETURN)
185 {
186 let spans = validated.options_spans.clone();
187 dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" });
188 }
189 if validated.options.contains(ast::InlineAsmOptions::PURE)
190 && !validated
191 .options
192 .intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
193 {
194 let spans = validated.options_spans.clone();
195 dcx.emit_err(errors::AsmPureCombine { spans });
196 }
197
198 let mut have_real_output = false;
199 let mut outputs_sp = ::alloc::vec::Vec::new()vec![];
200 let mut regclass_outputs = ::alloc::vec::Vec::new()vec![];
201 let mut labels_sp = ::alloc::vec::Vec::new()vec![];
202 for (op, op_sp) in &validated.operands {
203 match op {
204 ast::InlineAsmOperand::Out { reg, expr, .. }
205 | ast::InlineAsmOperand::SplitInOut { reg, out_expr: expr, .. } => {
206 outputs_sp.push(*op_sp);
207 have_real_output |= expr.is_some();
208 if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg {
209 regclass_outputs.push(*op_sp);
210 }
211 }
212 ast::InlineAsmOperand::InOut { reg, .. } => {
213 outputs_sp.push(*op_sp);
214 have_real_output = true;
215 if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg {
216 regclass_outputs.push(*op_sp);
217 }
218 }
219 ast::InlineAsmOperand::Label { .. } => {
220 labels_sp.push(*op_sp);
221 }
222 _ => {}
223 }
224 }
225 if validated.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
226 dcx.emit_err(errors::AsmPureNoOutput { spans: validated.options_spans.clone() });
227 }
228 if validated.options.contains(ast::InlineAsmOptions::NORETURN)
229 && !outputs_sp.is_empty()
230 && labels_sp.is_empty()
231 {
232 let err = dcx.create_err(errors::AsmNoReturn { outputs_sp });
233 return Err(err);
235 }
236 if validated.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() {
237 dcx.emit_err(errors::AsmMayUnwind { labels_sp });
238 }
239
240 if !validated.clobber_abis.is_empty() {
241 match asm_macro {
242 AsmMacro::GlobalAsm | AsmMacro::NakedAsm => {
243 let err = dcx.create_err(errors::AsmUnsupportedClobberAbi {
244 spans: validated.clobber_abis.iter().map(|(_, span)| *span).collect(),
245 macro_name: asm_macro.macro_name(),
246 });
247
248 return Err(err);
250 }
251 AsmMacro::Asm => {
252 if !regclass_outputs.is_empty() {
253 dcx.emit_err(errors::AsmClobberNoReg {
254 spans: regclass_outputs,
255 clobbers: validated.clobber_abis.iter().map(|(_, span)| *span).collect(),
256 });
257 }
258 }
259 }
260 }
261
262 Ok(validated)
263}
264
265fn expand_preparsed_asm(
266 ecx: &mut ExtCtxt<'_>,
267 asm_macro: AsmMacro,
268 args: ValidatedAsmArgs,
269) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
270 let mut template = ::alloc::vec::Vec::new()vec![];
271 let mut used = ::alloc::vec::from_elem(false, args.operands.len())vec![false; args.operands.len()];
274 for pos in args.reg_args.iter() {
275 used[pos] = true;
276 }
277 let named_pos: FxHashMap<usize, Symbol> =
278 args.named_args.iter().map(|(&sym, &idx)| (idx, sym)).collect();
279 let mut line_spans = Vec::with_capacity(args.templates.len());
280 let mut curarg = 0;
281
282 let mut template_strs = Vec::with_capacity(args.templates.len());
283
284 for (i, template_expr) in args.templates.into_iter().enumerate() {
285 if i != 0 {
286 template.push(ast::InlineAsmTemplatePiece::String("\n".into()));
287 }
288
289 let msg = "asm template must be a string literal";
290 let template_sp = template_expr.span;
291 let template_is_mac_call = #[allow(non_exhaustive_omitted_patterns)] match template_expr.kind {
ast::ExprKind::MacCall(_) => true,
_ => false,
}matches!(template_expr.kind, ast::ExprKind::MacCall(_));
292
293 let span_in_template = |range: std::ops::Range<usize>| -> Span {
295 if template_is_mac_call {
296 template_sp
299 } else {
300 template_sp.from_inner(InnerSpan::new(range.start, range.end))
301 }
302 };
303
304 let ExprToSpannedString {
305 symbol: template_str,
306 style: template_style,
307 span: template_span,
308 ..
309 } = {
310 let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else {
311 return ExpandResult::Retry(());
312 };
313 match mac {
314 Ok(template_part) => template_part,
315 Err(err) => {
316 return ExpandResult::Ready(Err(match err {
317 Ok((err, _)) => err.emit(),
318 Err(guar) => guar,
319 }));
320 }
321 }
322 };
323
324 let str_style = match template_style {
325 ast::StrStyle::Cooked => None,
326 ast::StrStyle::Raw(raw) => Some(raw as usize),
327 };
328
329 let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok();
330 template_strs.push((
331 template_str,
332 template_snippet.as_deref().map(Symbol::intern),
333 template_sp,
334 ));
335 let template_str = template_str.as_str();
336
337 if let Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) = ecx.sess.asm_arch {
338 let find_span = |needle: &str| -> Span {
339 if let Some(snippet) = &template_snippet {
340 if let Some(pos) = snippet.find(needle) {
341 let end = pos
342 + snippet[pos..]
343 .find(|c| #[allow(non_exhaustive_omitted_patterns)] match c {
'\n' | ';' | '\\' | '"' => true,
_ => false,
}matches!(c, '\n' | ';' | '\\' | '"'))
344 .unwrap_or(snippet[pos..].len() - 1);
345 let inner = InnerSpan::new(pos, end);
346 return template_sp.from_inner(inner);
347 }
348 }
349 template_sp
350 };
351
352 if template_str.contains(".intel_syntax") {
353 ecx.psess().buffer_lint(
354 lint::builtin::BAD_ASM_STYLE,
355 find_span(".intel_syntax"),
356 ecx.current_expansion.lint_node_id,
357 errors::AvoidIntelSyntax,
358 );
359 }
360 if template_str.contains(".att_syntax") {
361 ecx.psess().buffer_lint(
362 lint::builtin::BAD_ASM_STYLE,
363 find_span(".att_syntax"),
364 ecx.current_expansion.lint_node_id,
365 errors::AvoidAttSyntax,
366 );
367 }
368 }
369
370 if args.options.contains(ast::InlineAsmOptions::RAW) {
372 template.push(ast::InlineAsmTemplatePiece::String(template_str.to_string().into()));
373 let template_num_lines = 1 + template_str.matches('\n').count();
374 line_spans.extend(std::iter::repeat_n(template_sp, template_num_lines));
375 continue;
376 }
377
378 let mut parser = parse::Parser::new(
379 template_str,
380 str_style,
381 template_snippet,
382 false,
383 parse::ParseMode::InlineAsm,
384 );
385 parser.curarg = curarg;
386
387 let mut unverified_pieces = Vec::new();
388 while let Some(piece) = parser.next() {
389 if !parser.errors.is_empty() {
390 break;
391 } else {
392 unverified_pieces.push(piece);
393 }
394 }
395
396 if !parser.errors.is_empty() {
397 let err = parser.errors.remove(0);
398
399 let err_sp = span_in_template(err.span);
400
401 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("invalid asm template string: {0}",
err.description))
})format!("invalid asm template string: {}", err.description);
402 let mut e = ecx.dcx().struct_span_err(err_sp, msg);
403 e.span_label(err_sp, err.label + " in asm template string");
404 if let Some(note) = err.note {
405 e.note(note);
406 }
407 if let Some((label, span)) = err.secondary_label {
408 e.span_label(span_in_template(span), label);
409 }
410 let guar = e.emit();
411 return ExpandResult::Ready(Err(guar));
412 }
413
414 curarg = parser.curarg;
415
416 let mut arg_spans = parser
417 .arg_places
418 .iter()
419 .map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end)));
420 for piece in unverified_pieces {
421 match piece {
422 parse::Piece::Lit(s) => {
423 template.push(ast::InlineAsmTemplatePiece::String(s.to_string().into()))
424 }
425 parse::Piece::NextArgument(arg) => {
426 let span = arg_spans.next().unwrap_or(template_sp);
427
428 let operand_idx = match arg.position {
429 parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
430 if idx >= args.operands.len()
431 || named_pos.contains_key(&idx)
432 || args.reg_args.contains(idx)
433 {
434 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("invalid reference to argument at index {0}",
idx))
})format!("invalid reference to argument at index {idx}");
435 let mut err = ecx.dcx().struct_span_err(span, msg);
436 err.span_label(span, "from here");
437
438 let positional_args = args.operands.len()
439 - args.named_args.len()
440 - args.reg_args.len();
441 let positional = if positional_args != args.operands.len() {
442 "positional "
443 } else {
444 ""
445 };
446 let msg = match positional_args {
447 0 => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("no {0}arguments were given",
positional))
})format!("no {positional}arguments were given"),
448 1 => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("there is 1 {0}argument",
positional))
})format!("there is 1 {positional}argument"),
449 x => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("there are {0} {1}arguments", x,
positional))
})format!("there are {x} {positional}arguments"),
450 };
451 err.note(msg);
452
453 if named_pos.contains_key(&idx) {
454 err.span_label(args.operands[idx].1, "named argument");
455 err.span_note(
456 args.operands[idx].1,
457 "named arguments cannot be referenced by position",
458 );
459 } else if args.reg_args.contains(idx) {
460 err.span_label(
461 args.operands[idx].1,
462 "explicit register argument",
463 );
464 err.span_note(
465 args.operands[idx].1,
466 "explicit register arguments cannot be used in the asm template",
467 );
468 err.span_help(
469 args.operands[idx].1,
470 "use the register name directly in the assembly code",
471 );
472 }
473 err.emit();
474 None
475 } else {
476 Some(idx)
477 }
478 }
479 parse::ArgumentNamed(name) => {
480 match args.named_args.get(&Symbol::intern(name)) {
481 Some(&idx) => Some(idx),
482 None => {
483 let span = arg.position_span;
484 ecx.dcx()
485 .create_err(errors::AsmNoMatchedArgumentName {
486 name: name.to_owned(),
487 span: span_in_template(span),
488 })
489 .emit();
490 None
491 }
492 }
493 }
494 };
495
496 let mut chars = arg.format.ty.chars();
497 let mut modifier = chars.next();
498 if chars.next().is_some() {
499 let span = arg.format.ty_span.map(span_in_template).unwrap_or(template_sp);
500 ecx.dcx().emit_err(errors::AsmModifierInvalid { span });
501 modifier = None;
502 }
503
504 if let Some(operand_idx) = operand_idx {
505 used[operand_idx] = true;
506 template.push(ast::InlineAsmTemplatePiece::Placeholder {
507 operand_idx,
508 modifier,
509 span,
510 });
511 }
512 }
513 }
514 }
515
516 if parser.line_spans.is_empty() {
517 let template_num_lines = 1 + template_str.matches('\n').count();
518 line_spans.extend(std::iter::repeat_n(template_sp, template_num_lines));
519 } else {
520 line_spans.extend(
521 parser
522 .line_spans
523 .iter()
524 .map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end))),
525 );
526 };
527 }
528
529 let mut unused_operands = ::alloc::vec::Vec::new()vec![];
530 let mut help_str = String::new();
531 for (idx, used) in used.into_iter().enumerate() {
532 if !used {
533 let msg = if let Some(sym) = named_pos.get(&idx) {
534 help_str.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {{{0}}}", sym))
})format!(" {{{}}}", sym));
535 "named argument never used"
536 } else {
537 help_str.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {{{0}}}", idx))
})format!(" {{{}}}", idx));
538 "argument never used"
539 };
540 unused_operands.push((args.operands[idx].1, msg));
541 }
542 }
543 match unused_operands[..] {
544 [] => {}
545 [(sp, msg)] => {
546 ecx.dcx()
547 .struct_span_err(sp, msg)
548 .with_span_label(sp, msg)
549 .with_help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("if this argument is intentionally unused, consider using it in an asm comment: `\"/*{0} */\"`",
help_str))
})format!(
550 "if this argument is intentionally unused, \
551 consider using it in an asm comment: `\"/*{help_str} */\"`"
552 ))
553 .emit();
554 }
555 _ => {
556 let mut err = ecx.dcx().struct_span_err(
557 unused_operands.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
558 "multiple unused asm arguments",
559 );
560 for (sp, msg) in unused_operands {
561 err.span_label(sp, msg);
562 }
563 err.help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("if these arguments are intentionally unused, consider using them in an asm comment: `\"/*{0} */\"`",
help_str))
})format!(
564 "if these arguments are intentionally unused, \
565 consider using them in an asm comment: `\"/*{help_str} */\"`"
566 ));
567 err.emit();
568 }
569 }
570
571 ExpandResult::Ready(Ok(ast::InlineAsm {
572 asm_macro,
573 template,
574 template_strs: template_strs.into_boxed_slice(),
575 operands: args.operands,
576 clobber_abis: args.clobber_abis,
577 options: args.options,
578 line_spans,
579 }))
580}
581
582pub(super) fn expand_asm<'cx>(
583 ecx: &'cx mut ExtCtxt<'_>,
584 sp: Span,
585 tts: TokenStream,
586) -> MacroExpanderResult<'cx> {
587 ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::Asm) {
588 Ok(args) => {
589 let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else {
590 return ExpandResult::Retry(());
591 };
592 let expr = match mac {
593 Ok(inline_asm) => Box::new(ast::Expr {
594 id: ast::DUMMY_NODE_ID,
595 kind: ast::ExprKind::InlineAsm(Box::new(inline_asm)),
596 span: sp,
597 attrs: ast::AttrVec::new(),
598 tokens: None,
599 }),
600 Err(guar) => DummyResult::raw_expr(sp, Some(guar)),
601 };
602 MacEager::expr(expr)
603 }
604 Err(err) => {
605 let guar = err.emit();
606 DummyResult::any(sp, guar)
607 }
608 })
609}
610
611pub(super) fn expand_naked_asm<'cx>(
612 ecx: &'cx mut ExtCtxt<'_>,
613 sp: Span,
614 tts: TokenStream,
615) -> MacroExpanderResult<'cx> {
616 ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::NakedAsm) {
617 Ok(args) => {
618 let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args)
619 else {
620 return ExpandResult::Retry(());
621 };
622 let expr = match mac {
623 Ok(inline_asm) => Box::new(ast::Expr {
624 id: ast::DUMMY_NODE_ID,
625 kind: ast::ExprKind::InlineAsm(Box::new(inline_asm)),
626 span: sp,
627 attrs: ast::AttrVec::new(),
628 tokens: None,
629 }),
630 Err(guar) => DummyResult::raw_expr(sp, Some(guar)),
631 };
632 MacEager::expr(expr)
633 }
634 Err(err) => {
635 let guar = err.emit();
636 DummyResult::any(sp, guar)
637 }
638 })
639}
640
641pub(super) fn expand_global_asm<'cx>(
642 ecx: &'cx mut ExtCtxt<'_>,
643 sp: Span,
644 tts: TokenStream,
645) -> MacroExpanderResult<'cx> {
646 ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::GlobalAsm) {
647 Ok(args) => {
648 let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args)
649 else {
650 return ExpandResult::Retry(());
651 };
652 match mac {
653 Ok(inline_asm) => MacEager::items({
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(Box::new(ast::Item {
attrs: ast::AttrVec::new(),
id: ast::DUMMY_NODE_ID,
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
vis: ast::Visibility {
span: sp.shrink_to_lo(),
kind: ast::VisibilityKind::Inherited,
tokens: None,
},
span: sp,
tokens: None,
}));
vec
} else {
::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Box::new(ast::Item {
attrs: ast::AttrVec::new(),
id: ast::DUMMY_NODE_ID,
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
vis: ast::Visibility {
span: sp.shrink_to_lo(),
kind: ast::VisibilityKind::Inherited,
tokens: None,
},
span: sp,
tokens: None,
})])))
}
}smallvec![Box::new(ast::Item {
654 attrs: ast::AttrVec::new(),
655 id: ast::DUMMY_NODE_ID,
656 kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
657 vis: ast::Visibility {
658 span: sp.shrink_to_lo(),
659 kind: ast::VisibilityKind::Inherited,
660 tokens: None,
661 },
662 span: sp,
663 tokens: None,
664 })]),
665 Err(guar) => DummyResult::any(sp, guar),
666 }
667 }
668 Err(err) => {
669 let guar = err.emit();
670 DummyResult::any(sp, guar)
671 }
672 })
673}