Unnamed repository; edit this file 'description' to name the repository.
fix: avoid panic when parsing extern block
closes #10083
5 files changed, 43 insertions, 13 deletions
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs index 1057ca8c29..9763df63f2 100644 --- a/crates/parser/src/grammar/items.rs +++ b/crates/parser/src/grammar/items.rs @@ -93,6 +93,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> { }; let mut has_mods = false; + let mut has_extern = false; // modifiers if p.at(T![const]) && p.nth(1) != T!['{'] { @@ -102,7 +103,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> { // test_err async_without_semicolon // fn foo() { let _ = async {} } - if p.at(T![async]) && p.nth(1) != T!['{'] && p.nth(1) != T![move] && p.nth(1) != T![|] { + if p.at(T![async]) && !matches!(p.nth(1), T!['{'] | T![move] | T![|]) { p.eat(T![async]); has_mods = true; } @@ -114,7 +115,8 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> { has_mods = true; } - if p.at(T![extern]) && p.nth(1) != T!['{'] && (p.nth(1) != STRING || p.nth(2) != T!['{']) { + if p.at(T![extern]) { + has_extern = true; has_mods = true; abi(p); } @@ -211,25 +213,23 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> { type_alias(p, m); } + // test unsafe_extern_block // unsafe extern "C" {} - T![extern] => { - abi(p); + T!['{'] if has_extern => { extern_item_list(p); m.complete(p, EXTERN_BLOCK); } - _ => { - if !has_visibility && !has_mods { - return Err(m); + _ if has_visibility || has_mods => { + if has_mods { + p.error("expected existential, fn, trait or impl"); } else { - if has_mods { - p.error("expected existential, fn, trait or impl"); - } else { - p.error("expected an item"); - } - m.complete(p, ERROR); + p.error("expected an item"); } + m.complete(p, ERROR); } + + _ => return Err(m), } Ok(()) } diff --git a/crates/syntax/test_data/parser/err/0048_repated_extern_modifier.rast b/crates/syntax/test_data/parser/err/0048_repated_extern_modifier.rast new file mode 100644 index 0000000000..85e10ca36d --- /dev/null +++ b/crates/syntax/test_data/parser/err/0048_repated_extern_modifier.rast @@ -0,0 +1,15 @@ + [email protected] "extern" + [email protected] " " + [email protected] "\"C\"" + [email protected] " " + [email protected] "extern" + [email protected] " " + [email protected] "\"C\"" + [email protected] "\n" +error 10..10: expected existential, fn, trait or impl +error 21..21: expected existential, fn, trait or impl diff --git a/crates/syntax/test_data/parser/err/0048_repated_extern_modifier.rs b/crates/syntax/test_data/parser/err/0048_repated_extern_modifier.rs new file mode 100644 index 0000000000..1fb18eaf1b --- /dev/null +++ b/crates/syntax/test_data/parser/err/0048_repated_extern_modifier.rs @@ -0,0 +1 @@ +extern "C" extern "C"
diff --git a/crates/syntax/test_data/parser/inline/ok/0167_unsafe_extern_block.rast b/crates/syntax/test_data/parser/inline/ok/0167_unsafe_extern_block.rast new file mode 100644 index 0000000000..8044e6674d --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0167_unsafe_extern_block.rast @@ -0,0 +1,13 @@ + [email protected] "unsafe" + [email protected] " " + [email protected] "extern" + [email protected] " " + [email protected] "\"C\"" + [email protected] " " + [email protected] "{" + [email protected] "}" + [email protected] "\n" diff --git a/crates/syntax/test_data/parser/inline/ok/0167_unsafe_extern_block.rs b/crates/syntax/test_data/parser/inline/ok/0167_unsafe_extern_block.rs new file mode 100644 index 0000000000..9475aec15c --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0167_unsafe_extern_block.rs @@ -0,0 +1 @@ +unsafe extern "C" {} |