aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/grammar/expressions.rs29
-rw-r--r--src/grammar/items/mod.rs298
-rw-r--r--src/grammar/items/traits.rs2
-rw-r--r--tests/data/parser/err/0001_item_recovery_in_file.txt4
-rw-r--r--tests/data/parser/err/0002_duplicate_shebang.txt2
-rw-r--r--tests/data/parser/err/0003_C++_semicolon.txt6
-rw-r--r--tests/data/parser/err/0004_use_path_bad_segment.txt5
-rw-r--r--tests/data/parser/err/0007_stray_curly_in_file.txt6
-rw-r--r--tests/data/parser/err/0008_item_block_recovery.txt8
-rw-r--r--tests/data/parser/err/0009_broken_struct_type_parameter.txt8
-rw-r--r--tests/data/parser/err/0011_extern_struct.rs (renamed from tests/data/parser/inline/0006_extern_struct.rs)0
-rw-r--r--tests/data/parser/err/0011_extern_struct.txt (renamed from tests/data/parser/inline/0006_extern_struct.txt)9
-rw-r--r--tests/data/parser/inline/0013_unsafe_block_in_mod.txt8
-rw-r--r--tests/data/parser/inline/0023_array_type_missing_semi.txt7
-rw-r--r--tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt7
-rw-r--r--tests/data/parser/inline/0068_pub_expr.rs1
-rw-r--r--tests/data/parser/inline/0068_pub_expr.txt25
-rw-r--r--tests/data/parser/ok/0025_extern_fn_in_block.rs3
-rw-r--r--tests/data/parser/ok/0025_extern_fn_in_block.txt31
-rw-r--r--tests/data/parser/ok/0026_const_fn_in_block.rs3
-rw-r--r--tests/data/parser/ok/0026_const_fn_in_block.txt30
-rw-r--r--tests/data/parser/ok/0027_unsafe_fn_in_block.rs4
-rw-r--r--tests/data/parser/ok/0027_unsafe_fn_in_block.txt40
-rw-r--r--tests/testutils/src/lib.rs1
24 files changed, 328 insertions, 209 deletions
diff --git a/src/grammar/expressions.rs b/src/grammar/expressions.rs
index 423e1a95a..c68419929 100644
--- a/src/grammar/expressions.rs
+++ b/src/grammar/expressions.rs
@@ -229,18 +229,27 @@ fn block_expr(p: &mut Parser) -> CompletedMarker {
229 while !p.at(EOF) && !p.at(R_CURLY) { 229 while !p.at(EOF) && !p.at(R_CURLY) {
230 match p.current() { 230 match p.current() {
231 LET_KW => let_stmt(p), 231 LET_KW => let_stmt(p),
232 c => { 232 _ => {
233 // test block_items 233 // test block_items
234 // fn a() { fn b() {} } 234 // fn a() { fn b() {} }
235 if items::ITEM_FIRST.contains(c) { 235 let m = p.start();
236 items::item(p) 236 match items::maybe_item(p) {
237 } else { 237 items::MaybeItem::Item(kind) => {
238 let expr_stmt = p.start(); 238 m.complete(p, kind);
239 expressions::expr(p); 239 }
240 if p.eat(SEMI) { 240 items::MaybeItem::Modifiers => {
241 expr_stmt.complete(p, EXPR_STMT); 241 m.abandon(p);
242 } else { 242 p.error("expected an item");
243 expr_stmt.abandon(p); 243 }
244 // test pub_expr
245 // fn foo() { pub 92; } //FIXME
246 items::MaybeItem::None => {
247 expressions::expr(p);
248 if p.eat(SEMI) {
249 m.complete(p, EXPR_STMT);
250 } else {
251 m.abandon(p);
252 }
244 } 253 }
245 } 254 }
246 } 255 }
diff --git a/src/grammar/items/mod.rs b/src/grammar/items/mod.rs
index a1150e2ac..1ed0aea07 100644
--- a/src/grammar/items/mod.rs
+++ b/src/grammar/items/mod.rs
@@ -8,173 +8,136 @@ mod use_item;
8pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { 8pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
9 attributes::inner_attributes(p); 9 attributes::inner_attributes(p);
10 while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) { 10 while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
11 item(p); 11 item(p, stop_on_r_curly)
12 }
13}
14
15pub(super) fn item(p: &mut Parser, stop_on_r_curly: bool) {
16 let m = p.start();
17 match maybe_item(p) {
18 MaybeItem::Item(kind) => {
19 m.complete(p, kind);
20 }
21 MaybeItem::None => {
22 m.abandon(p);
23 if p.at(L_CURLY) {
24 error_block(p, "expected an item");
25 } else if !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
26 p.err_and_bump("expected an item");
27 } else {
28 p.error("expected an item");
29 }
30 }
31 MaybeItem::Modifiers => {
32 p.error("expected fn, trait or impl");
33 m.complete(p, ERROR);
34 }
12 } 35 }
13} 36}
14 37
15pub(super) const ITEM_FIRST: TokenSet = 38pub(super) const ITEM_FIRST: TokenSet =
16 token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND]; 39 token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND];
17 40
18pub(super) fn item(p: &mut Parser) { 41pub(super) enum MaybeItem {
19 let item = p.start(); 42 None,
43 Item(SyntaxKind),
44 Modifiers,
45}
46
47pub(super) fn maybe_item(p: &mut Parser) -> MaybeItem {
20 attributes::outer_attributes(p); 48 attributes::outer_attributes(p);
21 visibility(p); 49 visibility(p);
22 let la = p.nth(1); 50 if let Some(kind) = items_without_modifiers(p) {
23 let item_kind = match p.current() { 51 return MaybeItem::Item(kind);
24 USE_KW => { 52 }
25 use_item::use_item(p); 53
26 USE_ITEM 54 let mut has_mods = false;
27 } 55 // modifiers
28 // test extern_crate 56 has_mods |= p.eat(CONST_KW);
29 // extern crate foo; 57
30 EXTERN_KW if la == CRATE_KW => { 58 // test unsafe_block_in_mod
31 extern_crate_item(p); 59 // fn foo(){} unsafe { } fn bar(){}
32 EXTERN_CRATE_ITEM 60 if p.at(UNSAFE_KW) && p.nth(1) != L_CURLY {
33 } 61 p.eat(UNSAFE_KW);
34 EXTERN_KW => { 62 has_mods = true;
35 abi(p); 63 }
36 match p.current() { 64 if p.at(EXTERN_KW) {
37 // test extern_fn 65 has_mods = true;
38 // extern fn foo() {} 66 abi(p);
39 FN_KW => { 67 }
40 fn_item(p); 68 if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == TRAIT_KW {
41 FN_ITEM 69 p.bump_remap(AUTO_KW);
42 } 70 has_mods = true;
43 // test extern_block 71 }
44 // extern {} 72 if p.at(IDENT) && p.at_contextual_kw("default") && p.nth(1) == IMPL_KW {
45 L_CURLY => { 73 p.bump_remap(DEFAULT_KW);
46 extern_block(p); 74 has_mods = true;
47 EXTERN_BLOCK_EXPR 75 }
48 } 76
49 // test extern_struct 77 // items
50 // extern struct Foo; 78 let kind = match p.current() {
51 _ => { 79 // test extern_fn
52 item.abandon(p); 80 // extern fn foo() {}
53 p.error("expected `fn` or `{`"); 81
54 return; 82 // test const_fn
55 } 83 // const fn foo() {}
56 } 84
57 } 85 // test const_unsafe_fn
58 STATIC_KW => { 86 // const unsafe fn foo() {}
59 consts::static_item(p); 87
60 STATIC_ITEM 88 // test unsafe_extern_fn
61 } 89 // unsafe extern "C" fn foo() {}
62 CONST_KW => match p.nth(1) { 90
63 // test const_fn 91 // test unsafe_fn
64 // const fn foo() {} 92 // unsafe fn foo() {}
65 FN_KW => { 93 FN_KW => {
66 p.bump(); 94 fn_item(p);
67 fn_item(p); 95 FN_ITEM
68 FN_ITEM
69 }
70 // test const_unsafe_fn
71 // const unsafe fn foo() {}
72 UNSAFE_KW if p.nth(2) == FN_KW => {
73 p.bump();
74 p.bump();
75 fn_item(p);
76 FN_ITEM
77 }
78 _ => {
79 consts::const_item(p);
80 CONST_ITEM
81 }
82 },
83 UNSAFE_KW => {
84 p.bump();
85 let la = p.nth(1);
86 match p.current() {
87 // test unsafe_trait
88 // unsafe trait T {}
89 TRAIT_KW => {
90 traits::trait_item(p);
91 TRAIT_ITEM
92 }
93
94 // test unsafe_auto_trait
95 // unsafe auto trait T {}
96 IDENT if p.at_contextual_kw("auto") && la == TRAIT_KW => {
97 p.bump_remap(AUTO_KW);
98 traits::trait_item(p);
99 TRAIT_ITEM
100 }
101
102 // test unsafe_impl
103 // unsafe impl Foo {}
104 IMPL_KW => {
105 traits::impl_item(p);
106 IMPL_ITEM
107 }
108
109 // test unsafe_default_impl
110 // unsafe default impl Foo {}
111 IDENT if p.at_contextual_kw("default") && la == IMPL_KW => {
112 p.bump_remap(DEFAULT_KW);
113 traits::impl_item(p);
114 IMPL_ITEM
115 }
116
117 // test unsafe_extern_fn
118 // unsafe extern "C" fn foo() {}
119 EXTERN_KW => {
120 abi(p);
121 if !p.at(FN_KW) {
122 item.abandon(p);
123 p.error("expected function");
124 return;
125 }
126 fn_item(p);
127 FN_ITEM
128 }
129
130 // test unsafe_fn
131 // unsafe fn foo() {}
132 FN_KW => {
133 fn_item(p);
134 FN_ITEM
135 }
136
137 t => {
138 item.abandon(p);
139 let message = "expected `trait`, `impl` or `fn`";
140
141 // test unsafe_block_in_mod
142 // fn foo(){} unsafe { } fn bar(){}
143 if t == L_CURLY {
144 error_block(p, message);
145 } else {
146 p.error(message);
147 }
148 return;
149 }
150 }
151 }
152 TRAIT_KW => {
153 traits::trait_item(p);
154 TRAIT_ITEM
155 } 96 }
97
98 // test unsafe_trait
99 // unsafe trait T {}
100
156 // test auto_trait 101 // test auto_trait
157 // auto trait T {} 102 // auto trait T {}
158 IDENT if p.at_contextual_kw("auto") && la == TRAIT_KW => { 103
159 p.bump_remap(AUTO_KW); 104 // test unsafe_auto_trait
105 // unsafe auto trait T {}
106 TRAIT_KW => {
160 traits::trait_item(p); 107 traits::trait_item(p);
161 TRAIT_ITEM 108 TRAIT_ITEM
162 } 109 }
163 IMPL_KW => { 110
164 traits::impl_item(p); 111 // test unsafe_impl
165 IMPL_ITEM 112 // unsafe impl Foo {}
166 } 113
167 // test default_impl 114 // test default_impl
168 // default impl Foo {} 115 // default impl Foo {}
169 IDENT if p.at_contextual_kw("default") && la == IMPL_KW => { 116
170 p.bump_remap(DEFAULT_KW); 117 // test unsafe_default_impl
118 // unsafe default impl Foo {}
119 IMPL_KW => {
171 traits::impl_item(p); 120 traits::impl_item(p);
172 IMPL_ITEM 121 IMPL_ITEM
173 } 122 }
123 _ => return if has_mods {
124 MaybeItem::Modifiers
125 } else {
126 MaybeItem::None
127 }
128 };
174 129
175 FN_KW => { 130 MaybeItem::Item(kind)
176 fn_item(p); 131}
177 FN_ITEM 132
133fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> {
134 let la = p.nth(1);
135 let kind = match p.current() {
136 // test extern_crate
137 // extern crate foo;
138 EXTERN_KW if la == CRATE_KW => {
139 extern_crate_item(p);
140 EXTERN_CRATE_ITEM
178 } 141 }
179 TYPE_KW => { 142 TYPE_KW => {
180 type_item(p); 143 type_item(p);
@@ -186,31 +149,40 @@ pub(super) fn item(p: &mut Parser) {
186 } 149 }
187 STRUCT_KW => { 150 STRUCT_KW => {
188 structs::struct_item(p); 151 structs::struct_item(p);
152 if p.at(SEMI) {
153 p.err_and_bump(
154 "expected item, found `;`\n\
155 consider removing this semicolon"
156 );
157 }
189 STRUCT_ITEM 158 STRUCT_ITEM
190 } 159 }
191 ENUM_KW => { 160 ENUM_KW => {
192 structs::enum_item(p); 161 structs::enum_item(p);
193 ENUM_ITEM 162 ENUM_ITEM
194 } 163 }
195 L_CURLY => { 164 USE_KW => {
196 item.abandon(p); 165 use_item::use_item(p);
197 error_block(p, "expected item"); 166 USE_ITEM
198 return;
199 } 167 }
200 err_token => { 168 CONST_KW if (la == IDENT || la == MUT_KW) => {
201 item.abandon(p); 169 consts::const_item(p);
202 let message = if err_token == SEMI { 170 CONST_ITEM
203 //TODO: if the item is incomplete, this message is misleading 171 }
204 "expected item, found `;`\n\ 172 STATIC_KW => {
205 consider removing this semicolon" 173 consts::static_item(p);
206 } else { 174 STATIC_ITEM
207 "expected item" 175 }
208 }; 176 // test extern_block
209 p.err_and_bump(message); 177 // extern {}
210 return; 178 EXTERN_KW if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) => {
179 abi(p);
180 extern_block(p);
181 EXTERN_BLOCK_EXPR
211 } 182 }
183 _ => return None,
212 }; 184 };
213 item.complete(p, item_kind); 185 Some(kind)
214} 186}
215 187
216fn extern_crate_item(p: &mut Parser) { 188fn extern_crate_item(p: &mut Parser) {
diff --git a/src/grammar/items/traits.rs b/src/grammar/items/traits.rs
index bda13e565..0614e8ab6 100644
--- a/src/grammar/items/traits.rs
+++ b/src/grammar/items/traits.rs
@@ -45,7 +45,7 @@ pub(super) fn impl_item(p: &mut Parser) {
45 // fn bar(&self) {} 45 // fn bar(&self) {}
46 // } 46 // }
47 while !p.at(EOF) && !p.at(R_CURLY) { 47 while !p.at(EOF) && !p.at(R_CURLY) {
48 item(p); 48 item(p, true);
49 } 49 }
50 p.expect(R_CURLY); 50 p.expect(R_CURLY);
51} 51}
diff --git a/tests/data/parser/err/0001_item_recovery_in_file.txt b/tests/data/parser/err/0001_item_recovery_in_file.txt
index f35b97b48..49612ac73 100644
--- a/tests/data/parser/err/0001_item_recovery_in_file.txt
+++ b/tests/data/parser/err/0001_item_recovery_in_file.txt
@@ -1,9 +1,9 @@
1FILE@[0; 21) 1FILE@[0; 21)
2 ERROR@[0; 3) 2 ERROR@[0; 3)
3 IF_KW@[0; 2) 3 IF_KW@[0; 2)
4 err: `expected item` 4 err: `expected an item`
5 WHITESPACE@[2; 3) 5 WHITESPACE@[2; 3)
6 err: `expected item` 6 err: `expected an item`
7 ERROR@[3; 10) 7 ERROR@[3; 10)
8 MATCH_KW@[3; 8) 8 MATCH_KW@[3; 8)
9 WHITESPACE@[8; 10) 9 WHITESPACE@[8; 10)
diff --git a/tests/data/parser/err/0002_duplicate_shebang.txt b/tests/data/parser/err/0002_duplicate_shebang.txt
index 1a4b37da8..ef0ddb09a 100644
--- a/tests/data/parser/err/0002_duplicate_shebang.txt
+++ b/tests/data/parser/err/0002_duplicate_shebang.txt
@@ -1,6 +1,6 @@
1FILE@[0; 42) 1FILE@[0; 42)
2 SHEBANG@[0; 20) 2 SHEBANG@[0; 20)
3 err: `expected item` 3 err: `expected an item`
4 ERROR@[20; 42) 4 ERROR@[20; 42)
5 WHITESPACE@[20; 21) 5 WHITESPACE@[20; 21)
6 SHEBANG@[21; 41) 6 SHEBANG@[21; 41)
diff --git a/tests/data/parser/err/0003_C++_semicolon.txt b/tests/data/parser/err/0003_C++_semicolon.txt
index dc3cf6c73..0a2dad70d 100644
--- a/tests/data/parser/err/0003_C++_semicolon.txt
+++ b/tests/data/parser/err/0003_C++_semicolon.txt
@@ -1,5 +1,5 @@
1FILE@[0; 40) 1FILE@[0; 40)
2 STRUCT_ITEM@[0; 39) 2 STRUCT_ITEM@[0; 40)
3 STRUCT_KW@[0; 6) 3 STRUCT_KW@[0; 6)
4 NAME@[6; 9) 4 NAME@[6; 9)
5 WHITESPACE@[6; 7) 5 WHITESPACE@[6; 7)
@@ -34,5 +34,5 @@ FILE@[0; 40)
34 R_CURLY@[38; 39) 34 R_CURLY@[38; 39)
35 err: `expected item, found `;` 35 err: `expected item, found `;`
36consider removing this semicolon` 36consider removing this semicolon`
37 ERROR@[39; 40) 37 ERROR@[39; 40)
38 SEMI@[39; 40) 38 SEMI@[39; 40)
diff --git a/tests/data/parser/err/0004_use_path_bad_segment.txt b/tests/data/parser/err/0004_use_path_bad_segment.txt
index 6eb6123ec..9b827d862 100644
--- a/tests/data/parser/err/0004_use_path_bad_segment.txt
+++ b/tests/data/parser/err/0004_use_path_bad_segment.txt
@@ -11,11 +11,10 @@ FILE@[0; 12)
11 COLONCOLON@[7; 9) 11 COLONCOLON@[7; 9)
12 err: `expected identifier` 12 err: `expected identifier`
13 err: `expected SEMI` 13 err: `expected SEMI`
14 err: `expected item` 14 err: `expected an item`
15 PATH_SEGMENT@[9; 9) 15 PATH_SEGMENT@[9; 9)
16 ERROR@[9; 11) 16 ERROR@[9; 11)
17 INT_NUMBER@[9; 11) "92" 17 INT_NUMBER@[9; 11) "92"
18 err: `expected item, found `;` 18 err: `expected an item`
19consider removing this semicolon`
20 ERROR@[11; 12) 19 ERROR@[11; 12)
21 SEMI@[11; 12) 20 SEMI@[11; 12)
diff --git a/tests/data/parser/err/0007_stray_curly_in_file.txt b/tests/data/parser/err/0007_stray_curly_in_file.txt
index 9758a969f..473fe17cb 100644
--- a/tests/data/parser/err/0007_stray_curly_in_file.txt
+++ b/tests/data/parser/err/0007_stray_curly_in_file.txt
@@ -1,7 +1,7 @@
1FILE@[0; 31) 1FILE@[0; 31)
2 ERROR@[0; 3) 2 ERROR@[0; 3)
3 R_CURLY@[0; 1) 3 R_CURLY@[0; 1)
4 err: `expected item` 4 err: `expected an item`
5 WHITESPACE@[1; 3) 5 WHITESPACE@[1; 3)
6 STRUCT_ITEM@[3; 14) 6 STRUCT_ITEM@[3; 14)
7 STRUCT_KW@[3; 9) 7 STRUCT_KW@[3; 9)
@@ -10,7 +10,7 @@ FILE@[0; 31)
10 IDENT@[10; 11) "S" 10 IDENT@[10; 11) "S"
11 SEMI@[11; 12) 11 SEMI@[11; 12)
12 WHITESPACE@[12; 14) 12 WHITESPACE@[12; 14)
13 err: `expected item` 13 err: `expected an item`
14 ERROR@[14; 17) 14 ERROR@[14; 17)
15 R_CURLY@[14; 15) 15 R_CURLY@[14; 15)
16 WHITESPACE@[15; 17) 16 WHITESPACE@[15; 17)
@@ -26,7 +26,7 @@ FILE@[0; 31)
26 L_CURLY@[25; 26) 26 L_CURLY@[25; 26)
27 R_CURLY@[26; 27) 27 R_CURLY@[26; 27)
28 WHITESPACE@[27; 29) 28 WHITESPACE@[27; 29)
29 err: `expected item` 29 err: `expected an item`
30 ERROR@[29; 31) 30 ERROR@[29; 31)
31 R_CURLY@[29; 30) 31 R_CURLY@[29; 30)
32 WHITESPACE@[30; 31) 32 WHITESPACE@[30; 31)
diff --git a/tests/data/parser/err/0008_item_block_recovery.txt b/tests/data/parser/err/0008_item_block_recovery.txt
index 5bc62b6e1..80253d8af 100644
--- a/tests/data/parser/err/0008_item_block_recovery.txt
+++ b/tests/data/parser/err/0008_item_block_recovery.txt
@@ -13,17 +13,17 @@ FILE@[0; 95)
13 WHITESPACE@[10; 11) 13 WHITESPACE@[10; 11)
14 R_CURLY@[11; 12) 14 R_CURLY@[11; 12)
15 WHITESPACE@[12; 14) 15 WHITESPACE@[12; 14)
16 err: `expected item` 16 err: `expected an item`
17 ERROR@[14; 17) 17 ERROR@[14; 17)
18 IDENT@[14; 17) "bar" 18 IDENT@[14; 17) "bar"
19 err: `expected item` 19 err: `expected an item`
20 ERROR@[17; 18) 20 ERROR@[17; 18)
21 L_PAREN@[17; 18) 21 L_PAREN@[17; 18)
22 err: `expected item` 22 err: `expected an item`
23 ERROR@[18; 20) 23 ERROR@[18; 20)
24 R_PAREN@[18; 19) 24 R_PAREN@[18; 19)
25 WHITESPACE@[19; 20) 25 WHITESPACE@[19; 20)
26 err: `expected item` 26 err: `expected an item`
27 ERROR@[20; 82) 27 ERROR@[20; 82)
28 L_CURLY@[20; 21) 28 L_CURLY@[20; 21)
29 WHITESPACE@[21; 26) 29 WHITESPACE@[21; 26)
diff --git a/tests/data/parser/err/0009_broken_struct_type_parameter.txt b/tests/data/parser/err/0009_broken_struct_type_parameter.txt
index 700fc550f..72e5b36e5 100644
--- a/tests/data/parser/err/0009_broken_struct_type_parameter.txt
+++ b/tests/data/parser/err/0009_broken_struct_type_parameter.txt
@@ -13,18 +13,18 @@ FILE@[0; 43)
13 err: `expected COMMA` 13 err: `expected COMMA`
14 err: `expected R_ANGLE` 14 err: `expected R_ANGLE`
15 err: `expected `;`, `{`, or `(`` 15 err: `expected `;`, `{`, or `(``
16 err: `expected item` 16 err: `expected an item`
17 ERROR@[12; 14) 17 ERROR@[12; 14)
18 PLUS@[12; 13) 18 PLUS@[12; 13)
19 WHITESPACE@[13; 14) 19 WHITESPACE@[13; 14)
20 err: `expected item` 20 err: `expected an item`
21 ERROR@[14; 15) 21 ERROR@[14; 15)
22 INT_NUMBER@[14; 15) "2" 22 INT_NUMBER@[14; 15) "2"
23 err: `expected item` 23 err: `expected an item`
24 ERROR@[15; 17) 24 ERROR@[15; 17)
25 R_ANGLE@[15; 16) 25 R_ANGLE@[15; 16)
26 WHITESPACE@[16; 17) 26 WHITESPACE@[16; 17)
27 err: `expected item` 27 err: `expected an item`
28 ERROR@[17; 33) 28 ERROR@[17; 33)
29 L_CURLY@[17; 18) 29 L_CURLY@[17; 18)
30 WHITESPACE@[18; 23) 30 WHITESPACE@[18; 23)
diff --git a/tests/data/parser/inline/0006_extern_struct.rs b/tests/data/parser/err/0011_extern_struct.rs
index c1bd0a2d1..c1bd0a2d1 100644
--- a/tests/data/parser/inline/0006_extern_struct.rs
+++ b/tests/data/parser/err/0011_extern_struct.rs
diff --git a/tests/data/parser/inline/0006_extern_struct.txt b/tests/data/parser/err/0011_extern_struct.txt
index f310e1225..288f3469b 100644
--- a/tests/data/parser/inline/0006_extern_struct.txt
+++ b/tests/data/parser/err/0011_extern_struct.txt
@@ -1,8 +1,9 @@
1FILE@[0; 19) 1FILE@[0; 19)
2 ABI@[0; 7) 2 ERROR@[0; 7)
3 EXTERN_KW@[0; 6) 3 ABI@[0; 7)
4 WHITESPACE@[6; 7) 4 EXTERN_KW@[0; 6)
5 err: `expected `fn` or `{`` 5 WHITESPACE@[6; 7)
6 err: `expected fn, trait or impl`
6 STRUCT_ITEM@[7; 19) 7 STRUCT_ITEM@[7; 19)
7 STRUCT_KW@[7; 13) 8 STRUCT_KW@[7; 13)
8 NAME@[13; 17) 9 NAME@[13; 17)
diff --git a/tests/data/parser/inline/0013_unsafe_block_in_mod.txt b/tests/data/parser/inline/0013_unsafe_block_in_mod.txt
index e5581d615..142838692 100644
--- a/tests/data/parser/inline/0013_unsafe_block_in_mod.txt
+++ b/tests/data/parser/inline/0013_unsafe_block_in_mod.txt
@@ -11,10 +11,12 @@ FILE@[0; 33)
11 L_CURLY@[8; 9) 11 L_CURLY@[8; 9)
12 R_CURLY@[9; 10) 12 R_CURLY@[9; 10)
13 WHITESPACE@[10; 11) 13 WHITESPACE@[10; 11)
14 UNSAFE_KW@[11; 17) 14 err: `expected an item`
15 err: `expected `trait`, `impl` or `fn`` 15 ERROR@[11; 18)
16 ERROR@[17; 22) 16 UNSAFE_KW@[11; 17)
17 WHITESPACE@[17; 18) 17 WHITESPACE@[17; 18)
18 err: `expected an item`
19 ERROR@[18; 22)
18 L_CURLY@[18; 19) 20 L_CURLY@[18; 19)
19 WHITESPACE@[19; 20) 21 WHITESPACE@[19; 20)
20 R_CURLY@[20; 21) 22 R_CURLY@[20; 21)
diff --git a/tests/data/parser/inline/0023_array_type_missing_semi.txt b/tests/data/parser/inline/0023_array_type_missing_semi.txt
index f3e9ffe4a..aa600eab4 100644
--- a/tests/data/parser/inline/0023_array_type_missing_semi.txt
+++ b/tests/data/parser/inline/0023_array_type_missing_semi.txt
@@ -15,14 +15,13 @@ FILE@[0; 18)
15 WHITESPACE@[12; 13) 15 WHITESPACE@[12; 13)
16 err: `expected `;` or `]`` 16 err: `expected `;` or `]``
17 err: `expected SEMI` 17 err: `expected SEMI`
18 err: `expected item` 18 err: `expected an item`
19 ERROR@[13; 15) 19 ERROR@[13; 15)
20 INT_NUMBER@[13; 15) "92" 20 INT_NUMBER@[13; 15) "92"
21 err: `expected item` 21 err: `expected an item`
22 ERROR@[15; 16) 22 ERROR@[15; 16)
23 R_BRACK@[15; 16) 23 R_BRACK@[15; 16)
24 err: `expected item, found `;` 24 err: `expected an item`
25consider removing this semicolon`
26 ERROR@[16; 18) 25 ERROR@[16; 18)
27 SEMI@[16; 17) 26 SEMI@[16; 17)
28 WHITESPACE@[17; 18) 27 WHITESPACE@[17; 18)
diff --git a/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt b/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt
index c99714ed4..82632b7bf 100644
--- a/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt
+++ b/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt
@@ -11,14 +11,13 @@ FILE@[0; 20)
11 err: `expected `fn`` 11 err: `expected `fn``
12 err: `expected SEMI` 12 err: `expected SEMI`
13 WHITESPACE@[15; 16) 13 WHITESPACE@[15; 16)
14 err: `expected item` 14 err: `expected an item`
15 ERROR@[16; 17) 15 ERROR@[16; 17)
16 L_PAREN@[16; 17) 16 L_PAREN@[16; 17)
17 err: `expected item` 17 err: `expected an item`
18 ERROR@[17; 18) 18 ERROR@[17; 18)
19 R_PAREN@[17; 18) 19 R_PAREN@[17; 18)
20 err: `expected item, found `;` 20 err: `expected an item`
21consider removing this semicolon`
22 ERROR@[18; 20) 21 ERROR@[18; 20)
23 SEMI@[18; 19) 22 SEMI@[18; 19)
24 WHITESPACE@[19; 20) 23 WHITESPACE@[19; 20)
diff --git a/tests/data/parser/inline/0068_pub_expr.rs b/tests/data/parser/inline/0068_pub_expr.rs
new file mode 100644
index 000000000..d9d99d2d3
--- /dev/null
+++ b/tests/data/parser/inline/0068_pub_expr.rs
@@ -0,0 +1 @@
fn foo() { pub 92; } //FIXME
diff --git a/tests/data/parser/inline/0068_pub_expr.txt b/tests/data/parser/inline/0068_pub_expr.txt
new file mode 100644
index 000000000..09cf9b262
--- /dev/null
+++ b/tests/data/parser/inline/0068_pub_expr.txt
@@ -0,0 +1,25 @@
1FILE@[0; 29)
2 FN_ITEM@[0; 29)
3 FN_KW@[0; 2)
4 NAME@[2; 6)
5 WHITESPACE@[2; 3)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 9)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 29)
12 L_CURLY@[9; 10)
13 EXPR_STMT@[10; 19)
14 VISIBILITY@[10; 15)
15 WHITESPACE@[10; 11)
16 PUB_KW@[11; 14)
17 WHITESPACE@[14; 15)
18 LITERAL@[15; 17)
19 INT_NUMBER@[15; 17) "92"
20 SEMI@[17; 18)
21 WHITESPACE@[18; 19)
22 R_CURLY@[19; 20)
23 WHITESPACE@[20; 21)
24 COMMENT@[21; 28)
25 WHITESPACE@[28; 29)
diff --git a/tests/data/parser/ok/0025_extern_fn_in_block.rs b/tests/data/parser/ok/0025_extern_fn_in_block.rs
new file mode 100644
index 000000000..289809809
--- /dev/null
+++ b/tests/data/parser/ok/0025_extern_fn_in_block.rs
@@ -0,0 +1,3 @@
1fn main() {
2 extern fn f() {}
3}
diff --git a/tests/data/parser/ok/0025_extern_fn_in_block.txt b/tests/data/parser/ok/0025_extern_fn_in_block.txt
new file mode 100644
index 000000000..0623740aa
--- /dev/null
+++ b/tests/data/parser/ok/0025_extern_fn_in_block.txt
@@ -0,0 +1,31 @@
1FILE@[0; 35)
2 FN_ITEM@[0; 35)
3 FN_KW@[0; 2)
4 NAME@[2; 7)
5 WHITESPACE@[2; 3)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 10)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 35)
12 L_CURLY@[10; 11)
13 FN_ITEM@[11; 33)
14 ABI@[11; 23)
15 WHITESPACE@[11; 16)
16 EXTERN_KW@[16; 22)
17 WHITESPACE@[22; 23)
18 FN_KW@[23; 25)
19 NAME@[25; 27)
20 WHITESPACE@[25; 26)
21 IDENT@[26; 27) "f"
22 PARAM_LIST@[27; 30)
23 L_PAREN@[27; 28)
24 R_PAREN@[28; 29)
25 WHITESPACE@[29; 30)
26 BLOCK_EXPR@[30; 33)
27 L_CURLY@[30; 31)
28 R_CURLY@[31; 32)
29 WHITESPACE@[32; 33)
30 R_CURLY@[33; 34)
31 WHITESPACE@[34; 35)
diff --git a/tests/data/parser/ok/0026_const_fn_in_block.rs b/tests/data/parser/ok/0026_const_fn_in_block.rs
new file mode 100644
index 000000000..7641a3d28
--- /dev/null
+++ b/tests/data/parser/ok/0026_const_fn_in_block.rs
@@ -0,0 +1,3 @@
1fn main() {
2 const fn f() {}
3}
diff --git a/tests/data/parser/ok/0026_const_fn_in_block.txt b/tests/data/parser/ok/0026_const_fn_in_block.txt
new file mode 100644
index 000000000..329c65846
--- /dev/null
+++ b/tests/data/parser/ok/0026_const_fn_in_block.txt
@@ -0,0 +1,30 @@
1FILE@[0; 34)
2 FN_ITEM@[0; 34)
3 FN_KW@[0; 2)
4 NAME@[2; 7)
5 WHITESPACE@[2; 3)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 10)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 34)
12 L_CURLY@[10; 11)
13 FN_ITEM@[11; 32)
14 WHITESPACE@[11; 16)
15 CONST_KW@[16; 21)
16 WHITESPACE@[21; 22)
17 FN_KW@[22; 24)
18 NAME@[24; 26)
19 WHITESPACE@[24; 25)
20 IDENT@[25; 26) "f"
21 PARAM_LIST@[26; 29)
22 L_PAREN@[26; 27)
23 R_PAREN@[27; 28)
24 WHITESPACE@[28; 29)
25 BLOCK_EXPR@[29; 32)
26 L_CURLY@[29; 30)
27 R_CURLY@[30; 31)
28 WHITESPACE@[31; 32)
29 R_CURLY@[32; 33)
30 WHITESPACE@[33; 34)
diff --git a/tests/data/parser/ok/0027_unsafe_fn_in_block.rs b/tests/data/parser/ok/0027_unsafe_fn_in_block.rs
new file mode 100644
index 000000000..f3c5ff938
--- /dev/null
+++ b/tests/data/parser/ok/0027_unsafe_fn_in_block.rs
@@ -0,0 +1,4 @@
1fn main() {
2 unsafe fn f() {}
3 unsafe { 92 }
4}
diff --git a/tests/data/parser/ok/0027_unsafe_fn_in_block.txt b/tests/data/parser/ok/0027_unsafe_fn_in_block.txt
new file mode 100644
index 000000000..9982d0308
--- /dev/null
+++ b/tests/data/parser/ok/0027_unsafe_fn_in_block.txt
@@ -0,0 +1,40 @@
1FILE@[0; 53)
2 FN_ITEM@[0; 53)
3 FN_KW@[0; 2)
4 NAME@[2; 7)
5 WHITESPACE@[2; 3)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 10)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 53)
12 L_CURLY@[10; 11)
13 FN_ITEM@[11; 37)
14 WHITESPACE@[11; 16)
15 UNSAFE_KW@[16; 22)
16 WHITESPACE@[22; 23)
17 FN_KW@[23; 25)
18 NAME@[25; 27)
19 WHITESPACE@[25; 26)
20 IDENT@[26; 27) "f"
21 PARAM_LIST@[27; 30)
22 L_PAREN@[27; 28)
23 R_PAREN@[28; 29)
24 WHITESPACE@[29; 30)
25 BLOCK_EXPR@[30; 37)
26 L_CURLY@[30; 31)
27 R_CURLY@[31; 32)
28 WHITESPACE@[32; 37)
29 BLOCK_EXPR@[37; 51)
30 UNSAFE_KW@[37; 43)
31 WHITESPACE@[43; 44)
32 L_CURLY@[44; 45)
33 LITERAL@[45; 49)
34 WHITESPACE@[45; 46)
35 INT_NUMBER@[46; 48) "92"
36 WHITESPACE@[48; 49)
37 R_CURLY@[49; 50)
38 WHITESPACE@[50; 51)
39 R_CURLY@[51; 52)
40 WHITESPACE@[52; 53)
diff --git a/tests/testutils/src/lib.rs b/tests/testutils/src/lib.rs
index deeb707d3..39c821661 100644
--- a/tests/testutils/src/lib.rs
+++ b/tests/testutils/src/lib.rs
@@ -90,6 +90,7 @@ fn print_difference(expected: &str, actual: &str, path: &Path) {
90 return; 90 return;
91 } 91 }
92 let changeset = Changeset::new(actual, expected, "\n"); 92 let changeset = Changeset::new(actual, expected, "\n");
93 println!("Expected:\n{}\n\nActual:\n{}\n", expected, actual);
93 print!("{}", changeset); 94 print!("{}", changeset);
94 println!("file: {}\n", path.display()); 95 println!("file: {}\n", path.display());
95 panic!("Comparison failed") 96 panic!("Comparison failed")