Skip to content

Commit 1db4d60

Browse files
committed
parser: allow ABIs from literal macro fragments
1 parent 49def07 commit 1db4d60

File tree

7 files changed

+63
-26
lines changed

7 files changed

+63
-26
lines changed

src/libsyntax/parse/parser.rs

+27-13
Original file line numberDiff line numberDiff line change
@@ -1205,27 +1205,41 @@ impl<'a> Parser<'a> {
12051205
Ok(())
12061206
}
12071207

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

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

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

src/libsyntax/parse/parser/expr.rs

+5-1
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

+1-1
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

-7
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

+2-2
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

+2-2
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
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)