Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #18446 from ChayimFriedman2/safe-statement
fix: Only parse `safe` as contextual kw in extern blocks
Lukas Wirth 2024-10-31
parent cd206f5 · parent 3a8dc27 · commit 8244f30
-rw-r--r--crates/parser/src/grammar.rs3
-rw-r--r--crates/parser/src/grammar/expressions.rs2
-rw-r--r--crates/parser/src/grammar/items.rs13
-rw-r--r--crates/parser/src/grammar/items/traits.rs2
-rw-r--r--crates/parser/test_data/generated/runner.rs4
-rw-r--r--crates/parser/test_data/parser/inline/ok/safe_outside_of_extern.rast30
-rw-r--r--crates/parser/test_data/parser/inline/ok/safe_outside_of_extern.rs1
7 files changed, 47 insertions, 8 deletions
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 7ae1e5f82e..a5c031ad60 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -80,7 +80,8 @@ pub(crate) mod entry {
paths::type_path(p);
}
pub(crate) fn item(p: &mut Parser<'_>) {
- items::item_or_macro(p, true);
+ // We can set `is_in_extern=true`, because it only allows `safe fn`, and there is no ambiguity here.
+ items::item_or_macro(p, true, true);
}
// Parse a meta item , which excluded [], e.g : #[ MetaItem ]
pub(crate) fn meta_item(p: &mut Parser<'_>) {
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 861fcedda2..e565874a42 100644
--- a/crates/parser/src/grammar/expressions.rs
+++ b/crates/parser/src/grammar/expressions.rs
@@ -66,7 +66,7 @@ pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) {
// test block_items
// fn a() { fn b() {} }
- let m = match items::opt_item(p, m) {
+ let m = match items::opt_item(p, m, false) {
Ok(()) => return,
Err(m) => m,
};
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs
index c4dce0daa5..7d98499008 100644
--- a/crates/parser/src/grammar/items.rs
+++ b/crates/parser/src/grammar/items.rs
@@ -20,7 +20,8 @@ use super::*;
pub(super) fn mod_contents(p: &mut Parser<'_>, stop_on_r_curly: bool) {
attributes::inner_attrs(p);
while !(p.at(EOF) || (p.at(T!['}']) && stop_on_r_curly)) {
- item_or_macro(p, stop_on_r_curly);
+ // We can set `is_in_extern=true`, because it only allows `safe fn`, and there is no ambiguity here.
+ item_or_macro(p, stop_on_r_curly, true);
}
}
@@ -41,11 +42,11 @@ pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[
T![;],
]);
-pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) {
+pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool, is_in_extern: bool) {
let m = p.start();
attributes::outer_attrs(p);
- let m = match opt_item(p, m) {
+ let m = match opt_item(p, m, is_in_extern) {
Ok(()) => {
if p.at(T![;]) {
p.err_and_bump(
@@ -91,7 +92,7 @@ pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) {
}
/// Try to parse an item, completing `m` in case of success.
-pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> {
+pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker, is_in_extern: bool) -> Result<(), Marker> {
// test_err pub_expr
// fn foo() { pub 92; }
let has_visibility = opt_visibility(p, false);
@@ -135,7 +136,9 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> {
has_mods = true;
}
- if p.at_contextual_kw(T![safe]) {
+ // test safe_outside_of_extern
+ // fn foo() { safe = true; }
+ if is_in_extern && p.at_contextual_kw(T![safe]) {
p.eat_contextual_kw(T![safe]);
has_mods = true;
}
diff --git a/crates/parser/src/grammar/items/traits.rs b/crates/parser/src/grammar/items/traits.rs
index c215185d63..47f86ce8c6 100644
--- a/crates/parser/src/grammar/items/traits.rs
+++ b/crates/parser/src/grammar/items/traits.rs
@@ -94,7 +94,7 @@ pub(crate) fn assoc_item_list(p: &mut Parser<'_>) {
error_block(p, "expected an item");
continue;
}
- item_or_macro(p, true);
+ item_or_macro(p, true, false);
}
p.expect(T!['}']);
m.complete(p, ASSOC_ITEM_LIST);
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index 164d0f36f1..5b41dd07ad 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -527,6 +527,10 @@ mod ok {
run_and_expect_no_errors("test_data/parser/inline/ok/return_type_syntax_in_path.rs");
}
#[test]
+ fn safe_outside_of_extern() {
+ run_and_expect_no_errors("test_data/parser/inline/ok/safe_outside_of_extern.rs");
+ }
+ #[test]
fn self_param() { run_and_expect_no_errors("test_data/parser/inline/ok/self_param.rs"); }
#[test]
fn self_param_outer_attr() {
diff --git a/crates/parser/test_data/parser/inline/ok/safe_outside_of_extern.rast b/crates/parser/test_data/parser/inline/ok/safe_outside_of_extern.rast
new file mode 100644
index 0000000000..c9398eaa99
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/safe_outside_of_extern.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "safe"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/safe_outside_of_extern.rs b/crates/parser/test_data/parser/inline/ok/safe_outside_of_extern.rs
new file mode 100644
index 0000000000..a4d75e63ea
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/safe_outside_of_extern.rs
@@ -0,0 +1 @@
+fn foo() { safe = true; }