1
Fork 0

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
This commit is contained in:
Dylan DPC 2023-05-09 12:33:45 +05:30 committed by GitHub
commit dbd090c655
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 333 additions and 136 deletions

View file

@ -1300,6 +1300,8 @@ impl<'a> Parser<'a> {
})
} else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
self.parse_expr_array_or_repeat(Delimiter::Bracket)
} else if self.is_builtin() {
self.parse_expr_builtin()
} else if self.check_path() {
self.parse_expr_path_start()
} else if self.check_keyword(kw::Move)
@ -1766,6 +1768,61 @@ impl<'a> Parser<'a> {
self.maybe_recover_from_bad_qpath(expr)
}
/// Parse `builtin # ident(args,*)`.
fn parse_expr_builtin(&mut self) -> PResult<'a, P<Expr>> {
self.parse_builtin(|this, lo, ident| {
if ident.name == sym::offset_of {
return Ok(Some(this.parse_expr_offset_of(lo)?));
}
Ok(None)
})
}
pub(crate) fn parse_builtin<T>(
&mut self,
parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
) -> PResult<'a, T> {
let lo = self.token.span;
self.bump(); // `builtin`
self.bump(); // `#`
let Some((ident, false)) = self.token.ident() else {
let err = errors::ExpectedBuiltinIdent { span: self.token.span }
.into_diagnostic(&self.sess.span_diagnostic);
return Err(err);
};
self.sess.gated_spans.gate(sym::builtin_syntax, ident.span);
self.bump();
self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?;
let ret = if let Some(res) = parse(self, lo, ident)? {
Ok(res)
} else {
let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name }
.into_diagnostic(&self.sess.span_diagnostic);
return Err(err);
};
self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?;
ret
}
pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
let container = self.parse_ty()?;
self.expect(&TokenKind::Comma)?;
let seq_sep = SeqSep { sep: Some(token::Dot), trailing_sep_allowed: false };
let (fields, _trailing, _recovered) = self.parse_seq_to_before_end(
&TokenKind::CloseDelim(Delimiter::Parenthesis),
seq_sep,
Parser::parse_field_name,
)?;
let span = lo.to(self.token.span);
Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec().into())))
}
/// Returns a string literal if the next token is a string literal.
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
/// and returns `None` if the next token is not literal at all.
@ -2835,6 +2892,10 @@ impl<'a> Parser<'a> {
})
}
pub(crate) fn is_builtin(&self) -> bool {
self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
}
/// Parses a `try {...}` expression (`try` token already eaten).
fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
let (attrs, body) = self.parse_inner_attrs_and_block()?;