Skip to content

Commit fbc7181

Browse files
committed
a new parser generating the exact same error messages
1 parent 408cfef commit fbc7181

File tree

1 file changed

+248
-39
lines changed
  • compiler/rustc_builtin_macros/src

1 file changed

+248
-39
lines changed

compiler/rustc_builtin_macros/src/asm.rs

Lines changed: 248 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@ use {rustc_ast as ast, rustc_parse_format as parse};
1818
use crate::errors;
1919
use crate::util::{ExprToSpannedString, expr_to_spanned_string};
2020

21+
pub struct RawAsmArgs(Vec<RawAsmArg>);
22+
23+
pub struct RawAsmArg {
24+
pub span: Span,
25+
pub attributes: ast::AttrVec,
26+
pub kind: RawAsmArgKind,
27+
}
28+
29+
enum RawAsmArgKind {
30+
Template(P<ast::Expr>),
31+
Operand(Option<Symbol>, ast::InlineAsmOperand),
32+
Options(Vec<(Symbol, ast::InlineAsmOptions, Span, Span)>),
33+
ClobberAbi(Vec<(Symbol, Span)>),
34+
}
35+
2136
pub struct AsmArgs {
2237
pub templates: Vec<P<ast::Expr>>,
2338
pub operands: Vec<(ast::InlineAsmOperand, Span)>,
@@ -139,31 +154,28 @@ fn parse_asm_operand<'a>(
139154
}))
140155
}
141156

142-
// Primarily public for rustfmt consumption.
143-
// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
144-
pub fn parse_asm_args<'a>(
157+
pub fn parse_raw_asm_args<'a>(
145158
p: &mut Parser<'a>,
146159
sp: Span,
147160
asm_macro: AsmMacro,
148-
) -> PResult<'a, AsmArgs> {
161+
) -> PResult<'a, Vec<RawAsmArg>> {
149162
let dcx = p.dcx();
150163

151164
if p.token == token::Eof {
152165
return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp }));
153166
}
154167

168+
let mut args = Vec::new();
169+
155170
let first_template = p.parse_expr()?;
156-
let mut args = AsmArgs {
157-
templates: vec![first_template],
158-
operands: vec![],
159-
named_args: Default::default(),
160-
reg_args: Default::default(),
161-
clobber_abis: Vec::new(),
162-
options: ast::InlineAsmOptions::empty(),
163-
options_spans: vec![],
164-
};
171+
args.push(RawAsmArg {
172+
span: first_template.span,
173+
attributes: ast::AttrVec::new(),
174+
kind: RawAsmArgKind::Template(first_template),
175+
});
165176

166177
let mut allow_templates = true;
178+
167179
while p.token != token::Eof {
168180
if !p.eat(exp!(Comma)) {
169181
if allow_templates {
@@ -178,22 +190,116 @@ pub fn parse_asm_args<'a>(
178190
break;
179191
} // accept trailing commas
180192

193+
let span_start = p.token.span;
194+
181195
// Parse clobber_abi
182196
if p.eat_keyword(exp!(ClobberAbi)) {
183-
parse_clobber_abi(p, &mut args)?;
184197
allow_templates = false;
198+
199+
p.expect(exp!(OpenParen))?;
200+
201+
// FIXME: why not allow this?
202+
if p.eat(exp!(CloseParen)) {
203+
return Err(p.dcx().create_err(errors::NonABI { span: p.token.span }));
204+
}
205+
206+
let mut new_abis = Vec::new();
207+
while !p.eat(exp!(CloseParen)) {
208+
match p.parse_str_lit() {
209+
Ok(str_lit) => {
210+
new_abis.push((str_lit.symbol_unescaped, str_lit.span));
211+
}
212+
Err(opt_lit) => {
213+
let span = opt_lit.map_or(p.token.span, |lit| lit.span);
214+
return Err(p.dcx().create_err(errors::AsmExpectedStringLiteral { span }));
215+
}
216+
};
217+
218+
// Allow trailing commas
219+
if p.eat(exp!(CloseParen)) {
220+
break;
221+
}
222+
p.expect(exp!(Comma))?;
223+
}
224+
225+
args.push(RawAsmArg {
226+
span: span_start.to(p.prev_token.span),
227+
attributes: ast::AttrVec::new(),
228+
kind: RawAsmArgKind::ClobberAbi(new_abis),
229+
});
230+
185231
continue;
186232
}
187233

188234
// Parse options
189235
if p.eat_keyword(exp!(Options)) {
190-
parse_options(p, &mut args, asm_macro)?;
191236
allow_templates = false;
237+
238+
p.expect(exp!(OpenParen))?;
239+
240+
let mut options = Vec::new();
241+
242+
while !p.eat(exp!(CloseParen)) {
243+
const OPTIONS: [(ExpKeywordPair, ast::InlineAsmOptions);
244+
ast::InlineAsmOptions::COUNT] = [
245+
(exp!(Pure), ast::InlineAsmOptions::PURE),
246+
(exp!(Nomem), ast::InlineAsmOptions::NOMEM),
247+
(exp!(Readonly), ast::InlineAsmOptions::READONLY),
248+
(exp!(PreservesFlags), ast::InlineAsmOptions::PRESERVES_FLAGS),
249+
(exp!(Noreturn), ast::InlineAsmOptions::NORETURN),
250+
(exp!(Nostack), ast::InlineAsmOptions::NOSTACK),
251+
(exp!(MayUnwind), ast::InlineAsmOptions::MAY_UNWIND),
252+
(exp!(AttSyntax), ast::InlineAsmOptions::ATT_SYNTAX),
253+
(exp!(Raw), ast::InlineAsmOptions::RAW),
254+
];
255+
256+
'blk: {
257+
for (exp, option) in OPTIONS {
258+
let kw_matched = if asm_macro.is_supported_option(option) {
259+
p.eat_keyword(exp)
260+
} else {
261+
p.eat_keyword_noexpect(exp.kw)
262+
};
263+
264+
if kw_matched {
265+
let span = p.prev_token.span;
266+
let full_span =
267+
if p.token == token::Comma { span.to(p.token.span) } else { span };
268+
269+
if !asm_macro.is_supported_option(option) {
270+
// Tool-only output
271+
p.dcx().emit_err(errors::AsmUnsupportedOption {
272+
span,
273+
symbol: exp.kw,
274+
full_span,
275+
macro_name: asm_macro.macro_name(),
276+
});
277+
}
278+
279+
options.push((exp.kw, option, span, full_span));
280+
break 'blk;
281+
}
282+
}
283+
284+
return p.unexpected_any();
285+
}
286+
287+
// Allow trailing commas
288+
if p.eat(exp!(CloseParen)) {
289+
break;
290+
}
291+
p.expect(exp!(Comma))?;
292+
}
293+
294+
args.push(RawAsmArg {
295+
span: span_start.to(p.prev_token.span),
296+
attributes: ast::AttrVec::new(),
297+
kind: RawAsmArgKind::Options(options),
298+
});
299+
192300
continue;
193301
}
194302

195-
let span_start = p.token.span;
196-
197303
// Parse operand names
198304
let name = if p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq) {
199305
let (ident, _) = p.token.ident().unwrap();
@@ -225,40 +331,143 @@ pub fn parse_asm_args<'a>(
225331
return Err(err);
226332
}
227333
}
228-
args.templates.push(template);
334+
335+
args.push(RawAsmArg {
336+
span: template.span,
337+
attributes: ast::AttrVec::new(),
338+
kind: RawAsmArgKind::Template(template),
339+
});
340+
229341
continue;
230342
} else {
231343
p.unexpected_any()?
232344
}
233345
};
234346

235-
let explicit_reg = matches!(op.reg(), Some(ast::InlineAsmRegOrRegClass::Reg(_)));
236-
237347
allow_templates = false;
238-
let span = span_start.to(p.prev_token.span);
239-
let slot = args.operands.len();
240-
args.operands.push((op, span));
241348

242-
// Validate the order of named, positional & explicit register operands and
243-
// clobber_abi/options. We do this at the end once we have the full span
244-
// of the argument available.
349+
args.push(RawAsmArg {
350+
span: span_start.to(p.prev_token.span),
351+
attributes: ast::AttrVec::new(),
352+
kind: RawAsmArgKind::Operand(name, op),
353+
});
354+
}
355+
356+
Ok(args)
357+
}
358+
359+
pub fn parse_asm_args<'a>(
360+
p: &mut Parser<'a>,
361+
sp: Span,
362+
asm_macro: AsmMacro,
363+
) -> PResult<'a, AsmArgs> {
364+
let dcx = p.dcx();
365+
366+
let mut args = AsmArgs {
367+
templates: vec![],
368+
operands: vec![],
369+
named_args: Default::default(),
370+
reg_args: Default::default(),
371+
clobber_abis: Vec::new(),
372+
options: ast::InlineAsmOptions::empty(),
373+
options_spans: vec![],
374+
};
245375

246-
if explicit_reg {
247-
if name.is_some() {
248-
dcx.emit_err(errors::AsmExplicitRegisterName { span });
376+
let mut allow_templates = true;
377+
378+
for arg in parse_raw_asm_args(p, sp, asm_macro)? {
379+
match arg.kind {
380+
RawAsmArgKind::Template(template) => {
381+
if allow_templates {
382+
args.templates.push(template);
383+
} else {
384+
match template.kind {
385+
ast::ExprKind::Lit(token_lit)
386+
if matches!(
387+
token_lit.kind,
388+
token::LitKind::Str | token::LitKind::StrRaw(_)
389+
) => {}
390+
ast::ExprKind::MacCall(..) => {}
391+
_ => {
392+
let err = dcx.create_err(errors::AsmExpectedOther {
393+
span: template.span,
394+
is_inline_asm: matches!(asm_macro, AsmMacro::Asm),
395+
});
396+
return Err(err);
397+
}
398+
}
399+
args.templates.push(template);
400+
}
249401
}
250-
args.reg_args.insert(slot);
251-
} else if let Some(name) = name {
252-
if let Some(&prev) = args.named_args.get(&name) {
253-
dcx.emit_err(errors::AsmDuplicateArg { span, name, prev: args.operands[prev].1 });
254-
continue;
402+
RawAsmArgKind::Operand(name, op) => {
403+
allow_templates = false;
404+
405+
let explicit_reg = matches!(op.reg(), Some(ast::InlineAsmRegOrRegClass::Reg(_)));
406+
407+
let span = arg.span;
408+
let slot = args.operands.len();
409+
args.operands.push((op, span));
410+
411+
// Validate the order of named, positional & explicit register operands and
412+
// clobber_abi/options. We do this at the end once we have the full span
413+
// of the argument available.
414+
415+
if explicit_reg {
416+
if name.is_some() {
417+
dcx.emit_err(errors::AsmExplicitRegisterName { span });
418+
}
419+
args.reg_args.insert(slot);
420+
} else if let Some(name) = name {
421+
if let Some(&prev) = args.named_args.get(&name) {
422+
dcx.emit_err(errors::AsmDuplicateArg {
423+
span,
424+
name,
425+
prev: args.operands[prev].1,
426+
});
427+
continue;
428+
}
429+
args.named_args.insert(name, slot);
430+
} else if !args.named_args.is_empty() || !args.reg_args.is_empty() {
431+
let named = args.named_args.values().map(|p| args.operands[*p].1).collect();
432+
let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect();
433+
434+
dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit });
435+
}
255436
}
256-
args.named_args.insert(name, slot);
257-
} else if !args.named_args.is_empty() || !args.reg_args.is_empty() {
258-
let named = args.named_args.values().map(|p| args.operands[*p].1).collect();
259-
let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect();
437+
RawAsmArgKind::Options(new_options) => {
438+
allow_templates = false;
439+
440+
for (symbol, option, span, full_span) in new_options {
441+
if !asm_macro.is_supported_option(option) {
442+
/*
443+
// Tool-only output
444+
p.dcx().emit_err(errors::AsmUnsupportedOption {
445+
span,
446+
symbol,
447+
full_span,
448+
macro_name: asm_macro.macro_name(),
449+
});
450+
*/
451+
} else if args.options.contains(option) {
452+
// Tool-only output
453+
p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
454+
} else {
455+
args.options |= option;
456+
}
457+
}
260458

261-
dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit });
459+
args.options_spans.push(arg.span);
460+
}
461+
RawAsmArgKind::ClobberAbi(new_abis) => {
462+
allow_templates = false;
463+
464+
match &new_abis[..] {
465+
// should have errored above during parsing
466+
[] => unreachable!(),
467+
[(abi, _span)] => args.clobber_abis.push((*abi, arg.span)),
468+
_ => args.clobber_abis.extend(new_abis),
469+
}
470+
}
262471
}
263472
}
264473

0 commit comments

Comments
 (0)