10085: fix: avoid panic when parsing extern block r=matklad a=matklad

bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2021-08-30 12:57:39 +00:00 committed by GitHub
commit bb1987b45e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 41 deletions

View File

@ -93,6 +93,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> {
}; };
let mut has_mods = false; let mut has_mods = false;
let mut has_extern = false;
// modifiers // modifiers
if p.at(T![const]) && p.nth(1) != T!['{'] { 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 // test_err async_without_semicolon
// fn foo() { let _ = async {} } // 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]); p.eat(T![async]);
has_mods = true; has_mods = true;
} }
@ -114,7 +115,8 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> {
has_mods = true; 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; has_mods = true;
abi(p); abi(p);
} }
@ -211,25 +213,24 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> {
type_alias(p, m); type_alias(p, m);
} }
// test extern_block
// unsafe extern "C" {} // unsafe extern "C" {}
T![extern] => { // extern {}
abi(p); T!['{'] if has_extern => {
extern_item_list(p); extern_item_list(p);
m.complete(p, EXTERN_BLOCK); m.complete(p, EXTERN_BLOCK);
} }
_ => { _ if has_visibility || has_mods => {
if !has_visibility && !has_mods { if has_mods {
return Err(m); p.error("expected existential, fn, trait or impl");
} else { } else {
if has_mods { p.error("expected an item");
p.error("expected existential, fn, trait or impl");
} else {
p.error("expected an item");
}
m.complete(p, ERROR);
} }
m.complete(p, ERROR);
} }
_ => return Err(m),
} }
Ok(()) Ok(())
} }
@ -240,10 +241,11 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
// test extern_crate // test extern_crate
// extern crate foo; // extern crate foo;
T![extern] if la == T![crate] => extern_crate(p, m), T![extern] if la == T![crate] => extern_crate(p, m),
T![type] => { T![use] => use_item::use_(p, m),
type_alias(p, m);
}
T![mod] => mod_item(p, m), T![mod] => mod_item(p, m),
T![type] => type_alias(p, m),
T![struct] => { T![struct] => {
// test struct_items // test struct_items
// struct Foo; // struct Foo;
@ -256,14 +258,7 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
// } // }
adt::strukt(p, m); adt::strukt(p, m);
} }
// test pub_macro_def T![enum] => adt::enum_(p, m),
// 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);
}
IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => { IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
// test union_items // test union_items
// union Foo {} // union Foo {}
@ -273,17 +268,19 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
// } // }
adt::union(p, m); 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![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m),
T![static] => consts::static_(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), _ => return Err(m),
}; };
Ok(()) Ok(())
@ -292,6 +289,7 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
fn extern_crate(p: &mut Parser, m: Marker) { fn extern_crate(p: &mut Parser, m: Marker) {
assert!(p.at(T![extern])); assert!(p.at(T![extern]));
p.bump(T![extern]); p.bump(T![extern]);
assert!(p.at(T![crate])); assert!(p.at(T![crate]));
p.bump(T![crate]); p.bump(T![crate]);

View File

@ -0,0 +1,15 @@
SOURCE_FILE@0..22
ERROR@0..10
ABI@0..10
EXTERN_KW@0..6 "extern"
WHITESPACE@6..7 " "
STRING@7..10 "\"C\""
WHITESPACE@10..11 " "
ERROR@11..21
ABI@11..21
EXTERN_KW@11..17 "extern"
WHITESPACE@17..18 " "
STRING@18..21 "\"C\""
WHITESPACE@21..22 "\n"
error 10..10: expected existential, fn, trait or impl
error 21..21: expected existential, fn, trait or impl

View File

@ -0,0 +1 @@
extern "C" extern "C"

View File

@ -1,9 +1,21 @@
SOURCE_FILE@0..10 SOURCE_FILE@0..31
EXTERN_BLOCK@0..9 EXTERN_BLOCK@0..20
ABI@0..6 UNSAFE_KW@0..6 "unsafe"
EXTERN_KW@0..6 "extern"
WHITESPACE@6..7 " " WHITESPACE@6..7 " "
EXTERN_ITEM_LIST@7..9 ABI@7..17
L_CURLY@7..8 "{" EXTERN_KW@7..13 "extern"
R_CURLY@8..9 "}" WHITESPACE@13..14 " "
WHITESPACE@9..10 "\n" STRING@14..17 "\"C\""
WHITESPACE@17..18 " "
EXTERN_ITEM_LIST@18..20
L_CURLY@18..19 "{"
R_CURLY@19..20 "}"
WHITESPACE@20..21 "\n"
EXTERN_BLOCK@21..30
ABI@21..27
EXTERN_KW@21..27 "extern"
WHITESPACE@27..28 " "
EXTERN_ITEM_LIST@28..30
L_CURLY@28..29 "{"
R_CURLY@29..30 "}"
WHITESPACE@30..31 "\n"

View File

@ -1 +1,2 @@
unsafe extern "C" {}
extern {} extern {}