Allow wrapping builtin#offset_of fields argument in parentheses

This is necessary to correctly handle nested fields (`foo.bar`), see the comments in the code for explanation.
This commit is contained in:
Chayim Refael Friedman 2025-04-21 03:43:15 +03:00
parent 2f2cff19f8
commit db6db2aacc
4 changed files with 61 additions and 0 deletions

View file

@ -258,6 +258,15 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
p.expect(T!['(']);
type_(p);
p.expect(T![,]);
// Due to our incomplete handling of macro groups, especially
// those with empty delimiters, we wrap `expr` fragments in
// parentheses sometimes. Since `offset_of` is a macro, and takes
// `expr`, the field names could be wrapped in parentheses.
let wrapped_in_parens = p.eat(T!['(']);
// test offset_of_parens
// fn foo() {
// builtin#offset_of(Foo, (bar.baz.0));
// }
while !p.at(EOF) && !p.at(T![')']) {
name_ref_mod_path_or_index(p);
if !p.at(T![')']) {
@ -265,6 +274,9 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
}
}
p.expect(T![')']);
if wrapped_in_parens {
p.expect(T![')']);
}
Some(m.complete(p, OFFSET_OF_EXPR))
} else if p.at_contextual_kw(T![format_args]) {
p.bump_remap(T![format_args]);

View file

@ -416,6 +416,10 @@ mod ok {
run_and_expect_no_errors("test_data/parser/inline/ok/nocontentexpr_after_item.rs");
}
#[test]
fn offset_of_parens() {
run_and_expect_no_errors("test_data/parser/inline/ok/offset_of_parens.rs");
}
#[test]
fn or_pattern() { run_and_expect_no_errors("test_data/parser/inline/ok/or_pattern.rs"); }
#[test]
fn param_list() { run_and_expect_no_errors("test_data/parser/inline/ok/param_list.rs"); }

View file

@ -0,0 +1,42 @@
SOURCE_FILE
FN
FN_KW "fn"
WHITESPACE " "
NAME
IDENT "foo"
PARAM_LIST
L_PAREN "("
R_PAREN ")"
WHITESPACE " "
BLOCK_EXPR
STMT_LIST
L_CURLY "{"
WHITESPACE "\n "
EXPR_STMT
OFFSET_OF_EXPR
BUILTIN_KW "builtin"
POUND "#"
OFFSET_OF_KW "offset_of"
L_PAREN "("
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Foo"
COMMA ","
WHITESPACE " "
L_PAREN "("
NAME_REF
IDENT "bar"
DOT "."
NAME_REF
IDENT "baz"
DOT "."
NAME_REF
INT_NUMBER "0"
R_PAREN ")"
R_PAREN ")"
SEMICOLON ";"
WHITESPACE "\n"
R_CURLY "}"
WHITESPACE "\n"

View file

@ -0,0 +1,3 @@
fn foo() {
builtin#offset_of(Foo, (bar.baz.0));
}