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 @@ +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 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 @@ -SOURCE_FILE@0..10 - EXTERN_BLOCK@0..9 - ABI@0..6 - EXTERN_KW@0..6 "extern" +SOURCE_FILE@0..31 + EXTERN_BLOCK@0..20 + UNSAFE_KW@0..6 "unsafe" WHITESPACE@6..7 " " - EXTERN_ITEM_LIST@7..9 - L_CURLY@7..8 "{" - R_CURLY@8..9 "}" - WHITESPACE@9..10 "\n" + ABI@7..17 + EXTERN_KW@7..13 "extern" + WHITESPACE@13..14 " " + 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" 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 {}