Skip to content

Commit b25e706

Browse files
authored
Rollup merge of rust-lang#66271 - petrochenkov:abism, r=Centril
syntax: Keep string literals in ABIs and `asm!` more precisely As a result we don't lose spans when `extern` functions or blocks are passed to proc macros, and also escape all string literals consistently. Continuation of rust-lang#60679, which did a similar thing with all literals besides those in ABIs and `asm!`. TODO: Add tests. Fixes rust-lang#60493 Fixes rust-lang#64561 r? @Centril
2 parents f188904 + 28aec1b commit b25e706

File tree

18 files changed

+271
-177
lines changed

18 files changed

+271
-177
lines changed

src/librustc/hir/lowering.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,7 @@ impl<'a> LoweringContext<'a> {
12191219
ImplTraitContext::disallowed(),
12201220
),
12211221
unsafety: f.unsafety,
1222-
abi: this.lower_abi(f.abi),
1222+
abi: this.lower_extern(f.ext),
12231223
decl: this.lower_fn_decl(&f.decl, None, false, None),
12241224
param_names: this.lower_fn_params_to_names(&f.decl),
12251225
}))

src/librustc/hir/lowering/item.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ impl LoweringContext<'_> {
735735

736736
fn lower_foreign_mod(&mut self, fm: &ForeignMod) -> hir::ForeignMod {
737737
hir::ForeignMod {
738-
abi: self.lower_abi(fm.abi),
738+
abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)),
739739
items: fm.items
740740
.iter()
741741
.map(|x| self.lower_foreign_item(x))
@@ -1283,18 +1283,26 @@ impl LoweringContext<'_> {
12831283
unsafety: h.unsafety,
12841284
asyncness: self.lower_asyncness(h.asyncness.node),
12851285
constness: h.constness.node,
1286-
abi: self.lower_abi(h.abi),
1286+
abi: self.lower_extern(h.ext),
12871287
}
12881288
}
12891289

1290-
pub(super) fn lower_abi(&mut self, abi: Abi) -> abi::Abi {
1291-
abi::lookup(&abi.symbol.as_str()).unwrap_or_else(|| {
1290+
pub(super) fn lower_abi(&mut self, abi: StrLit) -> abi::Abi {
1291+
abi::lookup(&abi.symbol_unescaped.as_str()).unwrap_or_else(|| {
12921292
self.error_on_invalid_abi(abi);
12931293
abi::Abi::Rust
12941294
})
12951295
}
12961296

1297-
fn error_on_invalid_abi(&self, abi: Abi) {
1297+
pub(super) fn lower_extern(&mut self, ext: Extern) -> abi::Abi {
1298+
match ext {
1299+
Extern::None => abi::Abi::Rust,
1300+
Extern::Implicit => abi::Abi::C,
1301+
Extern::Explicit(abi) => self.lower_abi(abi),
1302+
}
1303+
}
1304+
1305+
fn error_on_invalid_abi(&self, abi: StrLit) {
12981306
struct_span_err!(
12991307
self.sess,
13001308
abi.span,

src/librustc_parse/parser/expr.rs

+38-12
Original file line numberDiff line numberDiff line change
@@ -778,13 +778,12 @@ impl<'a> Parser<'a> {
778778

779779
macro_rules! parse_lit {
780780
() => {
781-
match self.parse_lit() {
782-
Ok(literal) => {
781+
match self.parse_opt_lit() {
782+
Some(literal) => {
783783
hi = self.prev_span;
784784
ex = ExprKind::Lit(literal);
785785
}
786-
Err(mut err) => {
787-
err.cancel();
786+
None => {
788787
return Err(self.expected_expression_found());
789788
}
790789
}
@@ -1074,11 +1073,39 @@ impl<'a> Parser<'a> {
10741073
self.maybe_recover_from_bad_qpath(expr, true)
10751074
}
10761075

1077-
/// Matches `lit = true | false | token_lit`.
1076+
/// Returns a string literal if the next token is a string literal.
1077+
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
1078+
/// and returns `None` if the next token is not literal at all.
1079+
pub fn parse_str_lit(&mut self) -> Result<ast::StrLit, Option<Lit>> {
1080+
match self.parse_opt_lit() {
1081+
Some(lit) => match lit.kind {
1082+
ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit {
1083+
style,
1084+
symbol: lit.token.symbol,
1085+
suffix: lit.token.suffix,
1086+
span: lit.span,
1087+
symbol_unescaped,
1088+
}),
1089+
_ => Err(Some(lit)),
1090+
}
1091+
None => Err(None),
1092+
}
1093+
}
1094+
10781095
pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
1096+
self.parse_opt_lit().ok_or_else(|| {
1097+
let msg = format!("unexpected token: {}", self.this_token_descr());
1098+
self.span_fatal(self.token.span, &msg)
1099+
})
1100+
}
1101+
1102+
/// Matches `lit = true | false | token_lit`.
1103+
/// Returns `None` if the next token is not a literal.
1104+
pub(super) fn parse_opt_lit(&mut self) -> Option<Lit> {
10791105
let mut recovered = None;
10801106
if self.token == token::Dot {
1081-
// Attempt to recover `.4` as `0.4`.
1107+
// Attempt to recover `.4` as `0.4`. We don't currently have any syntax where
1108+
// dot would follow an optional literal, so we do this unconditionally.
10821109
recovered = self.look_ahead(1, |next_token| {
10831110
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix })
10841111
= next_token.kind {
@@ -1107,11 +1134,10 @@ impl<'a> Parser<'a> {
11071134
match Lit::from_token(token) {
11081135
Ok(lit) => {
11091136
self.bump();
1110-
Ok(lit)
1137+
Some(lit)
11111138
}
11121139
Err(LitError::NotLiteral) => {
1113-
let msg = format!("unexpected token: {}", self.this_token_descr());
1114-
Err(self.span_fatal(token.span, &msg))
1140+
None
11151141
}
11161142
Err(err) => {
11171143
let span = token.span;
@@ -1120,18 +1146,18 @@ impl<'a> Parser<'a> {
11201146
_ => unreachable!(),
11211147
};
11221148
self.bump();
1123-
self.error_literal_from_token(err, lit, span);
1149+
self.report_lit_error(err, lit, span);
11241150
// Pack possible quotes and prefixes from the original literal into
11251151
// the error literal's symbol so they can be pretty-printed faithfully.
11261152
let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None);
11271153
let symbol = Symbol::intern(&suffixless_lit.to_string());
11281154
let lit = token::Lit::new(token::Err, symbol, lit.suffix);
1129-
Lit::from_lit_token(lit, span).map_err(|_| unreachable!())
1155+
Some(Lit::from_lit_token(lit, span).unwrap_or_else(|_| unreachable!()))
11301156
}
11311157
}
11321158
}
11331159

1134-
fn error_literal_from_token(&self, err: LitError, lit: token::Lit, span: Span) {
1160+
fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) {
11351161
// Checks if `s` looks like i32 or u1234 etc.
11361162
fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
11371163
s.len() > 1

src/librustc_parse/parser/item.rs

+24-17
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use super::diagnostics::{Error, dummy_arg, ConsumeClosingDelim};
33

44
use crate::maybe_whole;
55

6-
use syntax::ast::{self, Abi, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item};
6+
use syntax::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item};
77
use syntax::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind};
8-
use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness};
8+
use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit};
99
use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
1010
use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, VariantData, StructField};
1111
use syntax::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param};
@@ -105,7 +105,7 @@ impl<'a> Parser<'a> {
105105
return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?));
106106
}
107107

108-
let abi = self.parse_opt_abi()?;
108+
let abi = self.parse_abi();
109109

110110
if self.eat_keyword(kw::Fn) {
111111
// EXTERN FUNCTION ITEM
@@ -114,7 +114,7 @@ impl<'a> Parser<'a> {
114114
unsafety: Unsafety::Normal,
115115
asyncness: respan(fn_span, IsAsync::NotAsync),
116116
constness: respan(fn_span, Constness::NotConst),
117-
abi,
117+
ext: Extern::from_abi(abi),
118118
};
119119
return self.parse_item_fn(lo, vis, attrs, header);
120120
} else if self.check(&token::OpenDelim(token::Brace)) {
@@ -143,14 +143,14 @@ impl<'a> Parser<'a> {
143143
if self.check_keyword(kw::Extern) {
144144
self.sess.gated_spans.gate(sym::const_extern_fn, lo.to(self.token.span));
145145
}
146-
let abi = self.parse_extern_abi()?;
146+
let ext = self.parse_extern()?;
147147
self.bump(); // `fn`
148148

149149
let header = FnHeader {
150150
unsafety,
151151
asyncness: respan(const_span, IsAsync::NotAsync),
152152
constness: respan(const_span, Constness::Const),
153-
abi,
153+
ext,
154154
};
155155
return self.parse_item_fn(lo, vis, attrs, header);
156156
}
@@ -193,7 +193,7 @@ impl<'a> Parser<'a> {
193193
unsafety,
194194
asyncness,
195195
constness: respan(fn_span, Constness::NotConst),
196-
abi: Abi::new(sym::Rust, fn_span),
196+
ext: Extern::None,
197197
};
198198
return self.parse_item_fn(lo, vis, attrs, header);
199199
}
@@ -230,7 +230,7 @@ impl<'a> Parser<'a> {
230230
unsafety: Unsafety::Normal,
231231
asyncness: respan(fn_span, IsAsync::NotAsync),
232232
constness: respan(fn_span, Constness::NotConst),
233-
abi: Abi::new(sym::Rust, fn_span),
233+
ext: Extern::None,
234234
};
235235
return self.parse_item_fn(lo, vis, attrs, header);
236236
}
@@ -242,14 +242,14 @@ impl<'a> Parser<'a> {
242242
self.bump(); // `unsafe`
243243
// `{` is also expected after `unsafe`; in case of error, include it in the diagnostic.
244244
self.check(&token::OpenDelim(token::Brace));
245-
let abi = self.parse_extern_abi()?;
245+
let ext = self.parse_extern()?;
246246
self.expect_keyword(kw::Fn)?;
247247
let fn_span = self.prev_span;
248248
let header = FnHeader {
249249
unsafety: Unsafety::Unsafe,
250250
asyncness: respan(fn_span, IsAsync::NotAsync),
251251
constness: respan(fn_span, Constness::NotConst),
252-
abi,
252+
ext,
253253
};
254254
return self.parse_item_fn(lo, vis, attrs, header);
255255
}
@@ -1100,7 +1100,7 @@ impl<'a> Parser<'a> {
11001100
fn parse_item_foreign_mod(
11011101
&mut self,
11021102
lo: Span,
1103-
abi: Abi,
1103+
abi: Option<StrLit>,
11041104
visibility: Visibility,
11051105
mut attrs: Vec<Attribute>,
11061106
extern_sp: Span,
@@ -1775,9 +1775,16 @@ impl<'a> Parser<'a> {
17751775
attrs: Vec<Attribute>,
17761776
header: FnHeader,
17771777
) -> PResult<'a, Option<P<Item>>> {
1778+
let is_c_abi = match header.ext {
1779+
ast::Extern::None => false,
1780+
ast::Extern::Implicit => true,
1781+
ast::Extern::Explicit(abi) => abi.symbol_unescaped == sym::C,
1782+
};
17781783
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
17791784
is_self_allowed: false,
1780-
allow_c_variadic: header.abi.symbol == sym::C && header.unsafety == Unsafety::Unsafe,
1785+
// FIXME: Parsing should not depend on ABI or unsafety and
1786+
// the variadic parameter should always be parsed.
1787+
allow_c_variadic: is_c_abi && header.unsafety == Unsafety::Unsafe,
17811788
is_name_required: |_| true,
17821789
})?;
17831790
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
@@ -1905,19 +1912,19 @@ impl<'a> Parser<'a> {
19051912
}
19061913
let asyncness = respan(self.prev_span, asyncness);
19071914
let unsafety = self.parse_unsafety();
1908-
let (constness, unsafety, abi) = if is_const_fn {
1909-
(respan(const_span, Constness::Const), unsafety, Abi::default())
1915+
let (constness, unsafety, ext) = if is_const_fn {
1916+
(respan(const_span, Constness::Const), unsafety, Extern::None)
19101917
} else {
1911-
let abi = self.parse_extern_abi()?;
1912-
(respan(self.prev_span, Constness::NotConst), unsafety, abi)
1918+
let ext = self.parse_extern()?;
1919+
(respan(self.prev_span, Constness::NotConst), unsafety, ext)
19131920
};
19141921
if !self.eat_keyword(kw::Fn) {
19151922
// It is possible for `expect_one_of` to recover given the contents of
19161923
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
19171924
// account for this.
19181925
if !self.expect_one_of(&[], &[])? { unreachable!() }
19191926
}
1920-
Ok(FnHeader { constness, unsafety, asyncness, abi })
1927+
Ok(FnHeader { constness, unsafety, asyncness, ext })
19211928
}
19221929

19231930
/// Parse the "signature", including the identifier, parameters, and generics of a function.

src/librustc_parse/parser/mod.rs

+15-49
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use crate::{Directory, DirectoryOwnership};
1515
use crate::lexer::UnmatchedBrace;
1616

1717
use syntax::ast::{
18-
self, Abi, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident,
19-
IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety,
18+
self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, StrLit,
19+
IsAsync, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety,
2020
};
2121

2222
use syntax::print::pprust;
@@ -1212,40 +1212,34 @@ impl<'a> Parser<'a> {
12121212
}
12131213

12141214
/// Parses `extern string_literal?`.
1215-
/// If `extern` is not found, the Rust ABI is used.
1216-
/// If `extern` is found and a `string_literal` does not follow, the C ABI is used.
1217-
fn parse_extern_abi(&mut self) -> PResult<'a, Abi> {
1215+
fn parse_extern(&mut self) -> PResult<'a, Extern> {
12181216
Ok(if self.eat_keyword(kw::Extern) {
1219-
self.parse_opt_abi()?
1217+
Extern::from_abi(self.parse_abi())
12201218
} else {
1221-
Abi::default()
1219+
Extern::None
12221220
})
12231221
}
12241222

12251223
/// Parses a string literal as an ABI spec.
1226-
/// If one is not found, the "C" ABI is used.
1227-
fn parse_opt_abi(&mut self) -> PResult<'a, Abi> {
1228-
let span = if self.token.can_begin_literal_or_bool() {
1229-
let ast::Lit { span, kind, .. } = self.parse_lit()?;
1230-
match kind {
1231-
ast::LitKind::Str(symbol, _) => return Ok(Abi::new(symbol, span)),
1232-
ast::LitKind::Err(_) => {}
1224+
fn parse_abi(&mut self) -> Option<StrLit> {
1225+
match self.parse_str_lit() {
1226+
Ok(str_lit) => Some(str_lit),
1227+
Err(Some(lit)) => match lit.kind {
1228+
ast::LitKind::Err(_) => None,
12331229
_ => {
1234-
self.struct_span_err(span, "non-string ABI literal")
1230+
self.struct_span_err(lit.span, "non-string ABI literal")
12351231
.span_suggestion(
1236-
span,
1232+
lit.span,
12371233
"specify the ABI with a string literal",
12381234
"\"C\"".to_string(),
12391235
Applicability::MaybeIncorrect,
12401236
)
12411237
.emit();
1238+
None
12421239
}
12431240
}
1244-
span
1245-
} else {
1246-
self.prev_span
1247-
};
1248-
Ok(Abi::new(sym::C, span))
1241+
Err(None) => None,
1242+
}
12491243
}
12501244

12511245
/// We are parsing `async fn`. If we are on Rust 2015, emit an error.
@@ -1337,34 +1331,6 @@ impl<'a> Parser<'a> {
13371331
self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace) ||
13381332
*t == token::BinOp(token::Star))
13391333
}
1340-
1341-
fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option<ast::Name>)> {
1342-
let ret = match self.token.kind {
1343-
token::Literal(token::Lit { kind: token::Str, symbol, suffix }) =>
1344-
(symbol, ast::StrStyle::Cooked, suffix),
1345-
token::Literal(token::Lit { kind: token::StrRaw(n), symbol, suffix }) =>
1346-
(symbol, ast::StrStyle::Raw(n), suffix),
1347-
_ => return None
1348-
};
1349-
self.bump();
1350-
Some(ret)
1351-
}
1352-
1353-
pub fn parse_str(&mut self) -> PResult<'a, (Symbol, StrStyle)> {
1354-
match self.parse_optional_str() {
1355-
Some((s, style, suf)) => {
1356-
let sp = self.prev_span;
1357-
self.expect_no_suffix(sp, "a string literal", suf);
1358-
Ok((s, style))
1359-
}
1360-
_ => {
1361-
let msg = "expected string literal";
1362-
let mut err = self.fatal(msg);
1363-
err.span_label(self.token.span, msg);
1364-
Err(err)
1365-
}
1366-
}
1367-
}
13681334
}
13691335

13701336
crate fn make_unclosed_delims_error(

src/librustc_parse/parser/ty.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ impl<'a> Parser<'a> {
287287
*/
288288

289289
let unsafety = self.parse_unsafety();
290-
let abi = self.parse_extern_abi()?;
290+
let ext = self.parse_extern()?;
291291
self.expect_keyword(kw::Fn)?;
292292
let cfg = ParamCfg {
293293
is_self_allowed: false,
@@ -296,7 +296,7 @@ impl<'a> Parser<'a> {
296296
};
297297
let decl = self.parse_fn_decl(cfg, false)?;
298298
Ok(TyKind::BareFn(P(BareFnTy {
299-
abi,
299+
ext,
300300
unsafety,
301301
generic_params,
302302
decl,

0 commit comments

Comments
 (0)