Skip to content

Commit cf75e6e

Browse files
committed
parser: allow ABIs from literal macro fragments
1 parent 9ffdc3b commit cf75e6e

File tree

7 files changed

+63
-26
lines changed

7 files changed

+63
-26
lines changed

src/libsyntax/parse/parser.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,27 +1206,41 @@ impl<'a> Parser<'a> {
12061206
Ok(())
12071207
}
12081208

1209-
/// Parses `extern` followed by an optional ABI string, or nothing.
1209+
/// Parses `extern string_literal?`.
1210+
/// If `extern` is not found, the Rust ABI is used.
1211+
/// If `extern` is found and a `string_literal` does not follow, the C ABI is used.
12101212
fn parse_extern_abi(&mut self) -> PResult<'a, Abi> {
12111213
Ok(if self.eat_keyword(kw::Extern) {
1212-
let ext_sp = self.prev_span;
1213-
self.parse_opt_abi()?.unwrap_or_else(|| Abi::new(sym::C, ext_sp))
1214+
self.parse_opt_abi()?
12141215
} else {
12151216
Abi::default()
12161217
})
12171218
}
12181219

1219-
/// Parses a string as an ABI spec on an extern type or module.
1220-
fn parse_opt_abi(&mut self) -> PResult<'a, Option<Abi>> {
1221-
match self.token.kind {
1222-
token::Literal(token::Lit { kind: token::Str, symbol, suffix }) |
1223-
token::Literal(token::Lit { kind: token::StrRaw(..), symbol, suffix }) => {
1224-
self.expect_no_suffix(self.token.span, "an ABI spec", suffix);
1225-
self.bump();
1226-
Ok(Some(Abi::new(symbol, self.prev_span)))
1220+
/// Parses a string literal as an ABI spec.
1221+
/// If one is not found, the "C" ABI is used.
1222+
fn parse_opt_abi(&mut self) -> PResult<'a, Abi> {
1223+
let span = if self.token.can_begin_literal_or_bool() {
1224+
let ast::Lit { span, kind, .. } = self.parse_lit()?;
1225+
match kind {
1226+
ast::LitKind::Str(symbol, _) => return Ok(Abi::new(symbol, span)),
1227+
ast::LitKind::Err(_) => {}
1228+
_ => {
1229+
self.struct_span_err(span, "non-string ABI literal")
1230+
.span_suggestion(
1231+
span,
1232+
"specify the ABI with a string literal",
1233+
"\"C\"".to_string(),
1234+
Applicability::MaybeIncorrect,
1235+
)
1236+
.emit();
1237+
}
12271238
}
1228-
_ => Ok(None),
1229-
}
1239+
span
1240+
} else {
1241+
self.prev_span
1242+
};
1243+
Ok(Abi::new(sym::C, span))
12301244
}
12311245

12321246
/// We are parsing `async fn`. If we are on Rust 2015, emit an error.

src/libsyntax/parse/parser/expr.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,11 @@ impl<'a> Parser<'a> {
11161116
Err(self.span_fatal(token.span, &msg))
11171117
}
11181118
Err(err) => {
1119-
let (lit, span) = (token.expect_lit(), token.span);
1119+
let span = token.span;
1120+
let lit = match token.kind {
1121+
token::Literal(lit) => lit,
1122+
_ => unreachable!(),
1123+
};
11201124
self.bump();
11211125
self.error_literal_from_token(err, lit, span);
11221126
// Pack possible quotes and prefixes from the original literal into

src/libsyntax/parse/parser/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ impl<'a> Parser<'a> {
110110
return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?));
111111
}
112112

113-
let abi = self.parse_opt_abi()?.unwrap_or_else(|| Abi::new(sym::C, extern_sp));
113+
let abi = self.parse_opt_abi()?;
114114

115115
if self.eat_keyword(kw::Fn) {
116116
// EXTERN FUNCTION ITEM

src/libsyntax/parse/token.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -402,13 +402,6 @@ impl Token {
402402
}
403403
}
404404

405-
crate fn expect_lit(&self) -> Lit {
406-
match self.kind {
407-
Literal(lit) => lit,
408-
_ => panic!("`expect_lit` called on non-literal"),
409-
}
410-
}
411-
412405
/// Returns `true` if the token is any literal, a minus (which can prefix a literal,
413406
/// for example a '-42', or one of the boolean idents).
414407
pub fn can_begin_literal_or_bool(&self) -> bool {

src/test/ui/parser/bad-lit-suffixes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
extern
2-
"C"suffix //~ ERROR suffixes on an ABI spec are invalid
2+
"C"suffix //~ ERROR suffixes on a string literal are invalid
33
fn foo() {}
44

55
extern
6-
"C"suffix //~ ERROR suffixes on an ABI spec are invalid
6+
"C"suffix //~ ERROR suffixes on a string literal are invalid
77
{}
88

99
fn main() {

src/test/ui/parser/bad-lit-suffixes.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: suffixes on an ABI spec are invalid
1+
error: suffixes on a string literal are invalid
22
--> $DIR/bad-lit-suffixes.rs:2:5
33
|
44
LL | "C"suffix
55
| ^^^^^^^^^ invalid suffix `suffix`
66

7-
error: suffixes on an ABI spec are invalid
7+
error: suffixes on a string literal are invalid
88
--> $DIR/bad-lit-suffixes.rs:6:5
99
|
1010
LL | "C"suffix
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// check-pass
2+
3+
// In this test we check that the parser accepts an ABI string when it
4+
// comes from a macro `literal` fragment as opposed to a hardcoded string.
5+
6+
fn main() {}
7+
8+
macro_rules! abi_from_lit_frag {
9+
($abi:literal) => {
10+
extern $abi {
11+
fn _import();
12+
}
13+
14+
extern $abi fn _export() {}
15+
16+
type _PTR = extern $abi fn();
17+
}
18+
}
19+
20+
mod rust {
21+
abi_from_lit_frag!("Rust");
22+
}
23+
24+
mod c {
25+
abi_from_lit_frag!("C");
26+
}

0 commit comments

Comments
 (0)