Skip to content

Commit 59ecbd2

Browse files
committed
Add parsing for builtin # in expression and item context
1 parent 4b94c23 commit 59ecbd2

File tree

8 files changed

+96
-1
lines changed

8 files changed

+96
-1
lines changed

compiler/rustc_parse/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,10 @@ parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are inva
257257
.tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access
258258
.tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information
259259
260+
parse_expected_builtin_ident = expected identifier after `builtin #`
261+
262+
parse_unknown_builtin_construct = unknown `builtin #` construct `{$name}`
263+
260264
parse_non_string_abi_literal = non-string ABI literal
261265
.suggestion = specify the ABI with a string literal
262266

compiler/rustc_parse/src/errors.rs

+15
Original file line numberDiff line numberDiff line change
@@ -2644,3 +2644,18 @@ pub(crate) struct MalformedCfgAttr {
26442644
pub span: Span,
26452645
pub sugg: &'static str,
26462646
}
2647+
2648+
#[derive(Diagnostic)]
2649+
#[diag(parse_unknown_builtin_construct)]
2650+
pub(crate) struct UnknownBuiltinConstruct {
2651+
#[primary_span]
2652+
pub span: Span,
2653+
pub name: Symbol,
2654+
}
2655+
2656+
#[derive(Diagnostic)]
2657+
#[diag(parse_expected_builtin_ident)]
2658+
pub(crate) struct ExpectedBuiltinIdent {
2659+
#[primary_span]
2660+
pub span: Span,
2661+
}

compiler/rustc_parse/src/parser/expr.rs

+42
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,8 @@ impl<'a> Parser<'a> {
13001300
})
13011301
} else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
13021302
self.parse_expr_array_or_repeat(Delimiter::Bracket)
1303+
} else if self.is_builtin() {
1304+
self.parse_expr_builtin()
13031305
} else if self.check_path() {
13041306
self.parse_expr_path_start()
13051307
} else if self.check_keyword(kw::Move)
@@ -1755,6 +1757,42 @@ impl<'a> Parser<'a> {
17551757
self.maybe_recover_from_bad_qpath(expr)
17561758
}
17571759

1760+
/// Parse `builtin # ident(args,*)`.
1761+
fn parse_expr_builtin(&mut self) -> PResult<'a, P<Expr>> {
1762+
self.parse_builtin(|_this, _lo, _ident| {
1763+
Ok(None)
1764+
})
1765+
}
1766+
1767+
pub(crate) fn parse_builtin<T>(
1768+
&mut self,
1769+
parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
1770+
) -> PResult<'a, T> {
1771+
let lo = self.token.span;
1772+
1773+
self.bump(); // `builtin`
1774+
self.bump(); // `#`
1775+
1776+
let Some((ident, false)) = self.token.ident() else {
1777+
let err = errors::ExpectedBuiltinIdent { span: self.token.span }
1778+
.into_diagnostic(&self.sess.span_diagnostic);
1779+
return Err(err);
1780+
};
1781+
self.bump();
1782+
1783+
self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?;
1784+
let ret = if let Some(res) = parse(self, lo, ident)? {
1785+
Ok(res)
1786+
} else {
1787+
let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name }
1788+
.into_diagnostic(&self.sess.span_diagnostic);
1789+
return Err(err);
1790+
};
1791+
self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?;
1792+
1793+
ret
1794+
}
1795+
17581796
/// Returns a string literal if the next token is a string literal.
17591797
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
17601798
/// and returns `None` if the next token is not literal at all.
@@ -2824,6 +2862,10 @@ impl<'a> Parser<'a> {
28242862
})
28252863
}
28262864

2865+
pub(crate) fn is_builtin(&self) -> bool {
2866+
self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
2867+
}
2868+
28272869
/// Parses a `try {...}` expression (`try` token already eaten).
28282870
fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
28292871
let (attrs, body) = self.parse_inner_attrs_and_block()?;

compiler/rustc_parse/src/parser/item.rs

+8
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,9 @@ impl<'a> Parser<'a> {
265265
// UNION ITEM
266266
self.bump(); // `union`
267267
self.parse_item_union()?
268+
} else if self.is_builtin() {
269+
// BUILTIN# ITEM
270+
return self.parse_item_builtin();
268271
} else if self.eat_keyword(kw::Macro) {
269272
// MACROS 2.0 ITEM
270273
self.parse_item_decl_macro(lo)?
@@ -434,6 +437,11 @@ impl<'a> Parser<'a> {
434437
}
435438
}
436439

440+
fn parse_item_builtin(&mut self) -> PResult<'a, Option<ItemInfo>> {
441+
// To be expanded
442+
return Ok(None);
443+
}
444+
437445
/// Parses an item macro, e.g., `item!();`.
438446
fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> {
439447
let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`

compiler/rustc_parse/src/parser/stmt.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,11 @@ impl<'a> Parser<'a> {
9090
attrs,
9191
errors::InvalidVariableDeclarationSub::UseLetNotVar,
9292
)?
93-
} else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
93+
} else if self.check_path()
94+
&& !self.token.is_qpath_start()
95+
&& !self.is_path_start_item()
96+
&& !self.is_builtin()
97+
{
9498
// We have avoided contextual keywords like `union`, items with `crate` visibility,
9599
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
96100
// that starts like a path (1 token), but it fact not a path.

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ symbols! {
9595

9696
// Weak keywords, have special meaning only in specific contexts.
9797
Auto: "auto",
98+
Builtin: "builtin",
9899
Catch: "catch",
99100
Default: "default",
100101
MacroRules: "macro_rules",

tests/ui/parser/builtin-syntax.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
builtin # foobar(); //~ ERROR unknown `builtin #` construct
3+
}
4+
5+
fn not_identifier() {
6+
builtin # {}(); //~ ERROR expected identifier after
7+
}

tests/ui/parser/builtin-syntax.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: unknown `builtin #` construct `foobar`
2+
--> $DIR/builtin-syntax.rs:2:5
3+
|
4+
LL | builtin # foobar();
5+
| ^^^^^^^^^^^^^^^^
6+
7+
error: expected identifier after `builtin #`
8+
--> $DIR/builtin-syntax.rs:6:15
9+
|
10+
LL | builtin # {}();
11+
| ^
12+
13+
error: aborting due to 2 previous errors
14+

0 commit comments

Comments
 (0)