parser: allow ABIs from literal macro fragments

This commit is contained in:
Mazdak Farrokhzad 2019-10-28 00:29:23 +01:00
parent 49def0769c
commit 1db4d607e7
7 changed files with 63 additions and 26 deletions

View File

@ -1205,27 +1205,41 @@ impl<'a> Parser<'a> {
Ok(())
}
/// Parses `extern` followed by an optional ABI string, or nothing.
/// Parses `extern string_literal?`.
/// If `extern` is not found, the Rust ABI is used.
/// If `extern` is found and a `string_literal` does not follow, the C ABI is used.
fn parse_extern_abi(&mut self) -> PResult<'a, Abi> {
Ok(if self.eat_keyword(kw::Extern) {
let ext_sp = self.prev_span;
self.parse_opt_abi()?.unwrap_or_else(|| Abi::new(sym::C, ext_sp))
self.parse_opt_abi()?
} else {
Abi::default()
})
}
/// Parses a string as an ABI spec on an extern type or module.
fn parse_opt_abi(&mut self) -> PResult<'a, Option<Abi>> {
match self.token.kind {
token::Literal(token::Lit { kind: token::Str, symbol, suffix }) |
token::Literal(token::Lit { kind: token::StrRaw(..), symbol, suffix }) => {
self.expect_no_suffix(self.token.span, "an ABI spec", suffix);
self.bump();
Ok(Some(Abi::new(symbol, self.prev_span)))
/// Parses a string literal as an ABI spec.
/// If one is not found, the "C" ABI is used.
fn parse_opt_abi(&mut self) -> PResult<'a, Abi> {
let span = if self.token.can_begin_literal_or_bool() {
let ast::Lit { span, kind, .. } = self.parse_lit()?;
match kind {
ast::LitKind::Str(symbol, _) => return Ok(Abi::new(symbol, span)),
ast::LitKind::Err(_) => {}
_ => {
self.struct_span_err(span, "non-string ABI literal")
.span_suggestion(
span,
"specify the ABI with a string literal",
"\"C\"".to_string(),
Applicability::MaybeIncorrect,
)
.emit();
}
}
_ => Ok(None),
}
span
} else {
self.prev_span
};
Ok(Abi::new(sym::C, span))
}
/// We are parsing `async fn`. If we are on Rust 2015, emit an error.

View File

@ -1116,7 +1116,11 @@ impl<'a> Parser<'a> {
Err(self.span_fatal(token.span, &msg))
}
Err(err) => {
let (lit, span) = (token.expect_lit(), token.span);
let span = token.span;
let lit = match token.kind {
token::Literal(lit) => lit,
_ => unreachable!(),
};
self.bump();
self.error_literal_from_token(err, lit, span);
// Pack possible quotes and prefixes from the original literal into

View File

@ -110,7 +110,7 @@ impl<'a> Parser<'a> {
return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?));
}
let abi = self.parse_opt_abi()?.unwrap_or_else(|| Abi::new(sym::C, extern_sp));
let abi = self.parse_opt_abi()?;
if self.eat_keyword(kw::Fn) {
// EXTERN FUNCTION ITEM

View File

@ -402,13 +402,6 @@ impl Token {
}
}
crate fn expect_lit(&self) -> Lit {
match self.kind {
Literal(lit) => lit,
_ => panic!("`expect_lit` called on non-literal"),
}
}
/// Returns `true` if the token is any literal, a minus (which can prefix a literal,
/// for example a '-42', or one of the boolean idents).
pub fn can_begin_literal_or_bool(&self) -> bool {

View File

@ -1,9 +1,9 @@
extern
"C"suffix //~ ERROR suffixes on an ABI spec are invalid
"C"suffix //~ ERROR suffixes on a string literal are invalid
fn foo() {}
extern
"C"suffix //~ ERROR suffixes on an ABI spec are invalid
"C"suffix //~ ERROR suffixes on a string literal are invalid
{}
fn main() {

View File

@ -1,10 +1,10 @@
error: suffixes on an ABI spec are invalid
error: suffixes on a string literal are invalid
--> $DIR/bad-lit-suffixes.rs:2:5
|
LL | "C"suffix
| ^^^^^^^^^ invalid suffix `suffix`
error: suffixes on an ABI spec are invalid
error: suffixes on a string literal are invalid
--> $DIR/bad-lit-suffixes.rs:6:5
|
LL | "C"suffix

View File

@ -0,0 +1,26 @@
// check-pass
// In this test we check that the parser accepts an ABI string when it
// comes from a macro `literal` fragment as opposed to a hardcoded string.
fn main() {}
macro_rules! abi_from_lit_frag {
($abi:literal) => {
extern $abi {
fn _import();
}
extern $abi fn _export() {}
type _PTR = extern $abi fn();
}
}
mod rust {
abi_from_lit_frag!("Rust");
}
mod c {
abi_from_lit_frag!("C");
}