Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs12
-rw-r--r--crates/parser/test_data/generated/runner.rs4
-rw-r--r--crates/parser/test_data/parser/inline/ok/offset_of_parens.rast42
-rw-r--r--crates/parser/test_data/parser/inline/ok/offset_of_parens.rs3
4 files changed, 61 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index 407320e1d0..c66afed91c 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -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]);
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index 2ea29345ed..a8fe61e7af 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -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"); }
diff --git a/crates/parser/test_data/parser/inline/ok/offset_of_parens.rast b/crates/parser/test_data/parser/inline/ok/offset_of_parens.rast
new file mode 100644
index 0000000000..4e23455cfc
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/offset_of_parens.rast
@@ -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"
diff --git a/crates/parser/test_data/parser/inline/ok/offset_of_parens.rs b/crates/parser/test_data/parser/inline/ok/offset_of_parens.rs
new file mode 100644
index 0000000000..a797d5c820
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/offset_of_parens.rs
@@ -0,0 +1,3 @@
+fn foo() {
+ builtin#offset_of(Foo, (bar.baz.0));
+}