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