Skip to content

Commit dbd090c

Browse files
authored
Rollup merge of #110694 - est31:builtin, r=petrochenkov
Implement builtin # syntax and use it for offset_of!(...) Add `builtin #` syntax to the parser, as well as a generic infrastructure to support both item and expression position builtin syntaxes. The PR also uses this infrastructure for the implementation of the `offset_of!` macro, added by #106934. cc `@petrochenkov` `@DrMeepster` cc #110680 `builtin #` tracking issue cc #106655 `offset_of!` tracking issue
2 parents ff30b8c + 83b4df4 commit dbd090c

File tree

25 files changed

+333
-136
lines changed

25 files changed

+333
-136
lines changed

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
603603
gate_all!(yeet_expr, "`do yeet` expression is experimental");
604604
gate_all!(dyn_star, "`dyn*` trait objects are experimental");
605605
gate_all!(const_closures, "const closures are experimental");
606+
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
606607

607608
if !visitor.features.negative_bounds {
608609
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,7 @@ impl<'a> State<'a> {
556556
self.pclose();
557557
}
558558
ast::ExprKind::OffsetOf(container, fields) => {
559-
// FIXME: This should have its own syntax, distinct from a macro invocation.
560-
self.word("offset_of!");
559+
self.word("builtin # offset_of");
561560
self.popen();
562561
self.rbox(0, Inconsistent);
563562
self.print_type(container);

compiler/rustc_builtin_macros/messages.ftl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,6 @@ builtin_macros_format_pos_mismatch = {$n} positional {$n ->
150150
*[more] arguments
151151
} in format string, but {$desc}
152152
153-
builtin_macros_offset_of_expected_field = expected field
154-
155-
builtin_macros_offset_of_expected_two_args = expected 2 arguments
156-
157153
builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items
158154
159155
builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests

compiler/rustc_builtin_macros/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ mod format;
4444
mod format_foreign;
4545
mod global_allocator;
4646
mod log_syntax;
47-
mod offset_of;
4847
mod source_util;
4948
mod test;
5049
mod trace_macros;
@@ -92,7 +91,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
9291
line: source_util::expand_line,
9392
log_syntax: log_syntax::expand_log_syntax,
9493
module_path: source_util::expand_mod,
95-
offset_of: offset_of::expand_offset_of,
9694
option_env: env::expand_option_env,
9795
core_panic: edition_panic::expand_panic,
9896
std_panic: edition_panic::expand_panic,

compiler/rustc_builtin_macros/src/offset_of.rs

Lines changed: 0 additions & 99 deletions
This file was deleted.

compiler/rustc_feature/src/active.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ declare_features! (
313313
(active, async_closure, "1.37.0", Some(62290), None),
314314
/// Allows async functions to be declared, implemented, and used in traits.
315315
(active, async_fn_in_trait, "1.66.0", Some(91611), None),
316+
/// Allows builtin # foo() syntax
317+
(active, builtin_syntax, "CURRENT_RUSTC_VERSION", Some(110680), None),
316318
/// Allows `c"foo"` literals.
317319
(active, c_str_literals, "CURRENT_RUSTC_VERSION", Some(105723), None),
318320
/// Treat `extern "C"` function as nounwind.

compiler/rustc_parse/messages.ftl

Lines changed: 4 additions & 0 deletions
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

Lines changed: 15 additions & 0 deletions
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

Lines changed: 61 additions & 0 deletions
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)
@@ -1766,6 +1768,61 @@ impl<'a> Parser<'a> {
17661768
self.maybe_recover_from_bad_qpath(expr)
17671769
}
17681770

1771+
/// Parse `builtin # ident(args,*)`.
1772+
fn parse_expr_builtin(&mut self) -> PResult<'a, P<Expr>> {
1773+
self.parse_builtin(|this, lo, ident| {
1774+
if ident.name == sym::offset_of {
1775+
return Ok(Some(this.parse_expr_offset_of(lo)?));
1776+
}
1777+
1778+
Ok(None)
1779+
})
1780+
}
1781+
1782+
pub(crate) fn parse_builtin<T>(
1783+
&mut self,
1784+
parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
1785+
) -> PResult<'a, T> {
1786+
let lo = self.token.span;
1787+
1788+
self.bump(); // `builtin`
1789+
self.bump(); // `#`
1790+
1791+
let Some((ident, false)) = self.token.ident() else {
1792+
let err = errors::ExpectedBuiltinIdent { span: self.token.span }
1793+
.into_diagnostic(&self.sess.span_diagnostic);
1794+
return Err(err);
1795+
};
1796+
self.sess.gated_spans.gate(sym::builtin_syntax, ident.span);
1797+
self.bump();
1798+
1799+
self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?;
1800+
let ret = if let Some(res) = parse(self, lo, ident)? {
1801+
Ok(res)
1802+
} else {
1803+
let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name }
1804+
.into_diagnostic(&self.sess.span_diagnostic);
1805+
return Err(err);
1806+
};
1807+
self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?;
1808+
1809+
ret
1810+
}
1811+
1812+
pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
1813+
let container = self.parse_ty()?;
1814+
self.expect(&TokenKind::Comma)?;
1815+
1816+
let seq_sep = SeqSep { sep: Some(token::Dot), trailing_sep_allowed: false };
1817+
let (fields, _trailing, _recovered) = self.parse_seq_to_before_end(
1818+
&TokenKind::CloseDelim(Delimiter::Parenthesis),
1819+
seq_sep,
1820+
Parser::parse_field_name,
1821+
)?;
1822+
let span = lo.to(self.token.span);
1823+
Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec().into())))
1824+
}
1825+
17691826
/// Returns a string literal if the next token is a string literal.
17701827
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
17711828
/// and returns `None` if the next token is not literal at all.
@@ -2835,6 +2892,10 @@ impl<'a> Parser<'a> {
28352892
})
28362893
}
28372894

2895+
pub(crate) fn is_builtin(&self) -> bool {
2896+
self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
2897+
}
2898+
28382899
/// Parses a `try {...}` expression (`try` token already eaten).
28392900
fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
28402901
let (attrs, body) = self.parse_inner_attrs_and_block()?;

compiler/rustc_parse/src/parser/item.rs

Lines changed: 8 additions & 0 deletions
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`

0 commit comments

Comments
 (0)