Unnamed repository; edit this file 'description' to name the repository.
Merge #10085
10085: fix: avoid panic when parsing extern block r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
bors[bot] 2021-08-30
parent cbae596 · parent 4452f9e · commit bb1987b
-rw-r--r--crates/parser/src/grammar/items.rs64
-rw-r--r--crates/syntax/test_data/parser/err/0048_repated_extern_modifier.rast15
-rw-r--r--crates/syntax/test_data/parser/err/0048_repated_extern_modifier.rs1
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0010_extern_block.rast28
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0010_extern_block.rs1
5 files changed, 68 insertions, 41 deletions
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs
index 1057ca8c29..3421078bba 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,24 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> {
type_alias(p, m);
}
+ // test extern_block
// unsafe extern "C" {}
- T![extern] => {
- abi(p);
+ // extern {}
+ 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(())
}
@@ -240,10 +241,11 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
// test extern_crate
// extern crate foo;
T![extern] if la == T![crate] => extern_crate(p, m),
- T![type] => {
- type_alias(p, m);
- }
+ T![use] => use_item::use_(p, m),
T![mod] => mod_item(p, m),
+
+ T![type] => type_alias(p, m),
+
T![struct] => {
// test struct_items
// struct Foo;
@@ -256,14 +258,7 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
// }
adt::strukt(p, m);
}
- // test pub_macro_def
- // pub macro m($:ident) {}
- T![macro] => {
- macro_def(p, m);
- }
- IDENT if p.at_contextual_kw("macro_rules") && p.nth(1) == BANG => {
- macro_rules(p, m);
- }
+ T![enum] => adt::enum_(p, m),
IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
// test union_items
// union Foo {}
@@ -273,17 +268,19 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
// }
adt::union(p, m);
}
- T![enum] => adt::enum_(p, m),
- T![use] => use_item::use_(p, m),
+
+ // test pub_macro_def
+ // pub macro m($:ident) {}
+ T![macro] => {
+ macro_def(p, m);
+ }
+ IDENT if p.at_contextual_kw("macro_rules") && p.nth(1) == BANG => {
+ macro_rules(p, m);
+ }
+
T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m),
T![static] => consts::static_(p, m),
- // test extern_block
- // extern {}
- T![extern] if la == T!['{'] || (la == STRING && p.nth(2) == T!['{']) => {
- abi(p);
- extern_item_list(p);
- m.complete(p, EXTERN_BLOCK);
- }
+
_ => return Err(m),
};
Ok(())
@@ -292,6 +289,7 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
fn extern_crate(p: &mut Parser, m: Marker) {
assert!(p.at(T![extern]));
p.bump(T![extern]);
+
assert!(p.at(T![crate]));
p.bump(T![crate]);
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 @@
+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/0010_extern_block.rast b/crates/syntax/test_data/parser/inline/ok/0010_extern_block.rast
index 869875875e..beac566e59 100644
--- a/crates/syntax/test_data/parser/inline/ok/0010_extern_block.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0010_extern_block.rast
@@ -1,9 +1,21 @@
diff --git a/crates/syntax/test_data/parser/inline/ok/0010_extern_block.rs b/crates/syntax/test_data/parser/inline/ok/0010_extern_block.rs
index 26a9ccd1e6..bee5ac8453 100644
--- a/crates/syntax/test_data/parser/inline/ok/0010_extern_block.rs
+++ b/crates/syntax/test_data/parser/inline/ok/0010_extern_block.rs
@@ -1 +1,2 @@
+unsafe extern "C" {}
extern {}