1
- use super :: { Parser , PathStyle , TokenType } ;
1
+ use super :: { Parser , PathStyle } ;
2
2
use rustc_ast:: ast;
3
3
use rustc_ast:: attr;
4
4
use rustc_ast:: token:: { self , Nonterminal } ;
@@ -10,63 +10,65 @@ use rustc_span::{Span, Symbol};
10
10
use log:: debug;
11
11
12
12
#[ derive( Debug ) ]
13
- enum InnerAttributeParsePolicy < ' a > {
13
+ pub ( super ) enum InnerAttrPolicy < ' a > {
14
14
Permitted ,
15
- NotPermitted { reason : & ' a str , saw_doc_comment : bool , prev_attr_sp : Option < Span > } ,
15
+ Forbidden { reason : & ' a str , saw_doc_comment : bool , prev_attr_sp : Option < Span > } ,
16
16
}
17
17
18
18
const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG : & str = "an inner attribute is not \
19
19
permitted in this context";
20
20
21
+ pub ( super ) const DEFAULT_INNER_ATTR_FORBIDDEN : InnerAttrPolicy < ' _ > = InnerAttrPolicy :: Forbidden {
22
+ reason : DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG ,
23
+ saw_doc_comment : false ,
24
+ prev_attr_sp : None ,
25
+ } ;
26
+
21
27
impl < ' a > Parser < ' a > {
22
28
/// Parses attributes that appear before an item.
23
29
pub ( super ) fn parse_outer_attributes ( & mut self ) -> PResult < ' a , Vec < ast:: Attribute > > {
24
30
let mut attrs: Vec < ast:: Attribute > = Vec :: new ( ) ;
25
31
let mut just_parsed_doc_comment = false ;
26
32
loop {
27
33
debug ! ( "parse_outer_attributes: self.token={:?}" , self . token) ;
28
- match self . token . kind {
29
- token:: Pound => {
30
- let inner_error_reason = if just_parsed_doc_comment {
31
- "an inner attribute is not permitted following an outer doc comment"
32
- } else if !attrs. is_empty ( ) {
33
- "an inner attribute is not permitted following an outer attribute"
34
- } else {
35
- DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
36
- } ;
37
- let inner_parse_policy = InnerAttributeParsePolicy :: NotPermitted {
38
- reason : inner_error_reason,
39
- saw_doc_comment : just_parsed_doc_comment,
40
- prev_attr_sp : attrs. last ( ) . map ( |a| a. span ) ,
41
- } ;
42
- let attr = self . parse_attribute_with_inner_parse_policy ( inner_parse_policy) ?;
43
- attrs. push ( attr) ;
44
- just_parsed_doc_comment = false ;
45
- }
46
- token:: DocComment ( s) => {
47
- let attr = self . mk_doc_comment ( s) ;
48
- if attr. style != ast:: AttrStyle :: Outer {
49
- let span = self . token . span ;
50
- let mut err = self . struct_span_err ( span, "expected outer doc comment" ) ;
51
- err. note (
34
+ if self . check ( & token:: Pound ) {
35
+ let inner_error_reason = if just_parsed_doc_comment {
36
+ "an inner attribute is not permitted following an outer doc comment"
37
+ } else if !attrs. is_empty ( ) {
38
+ "an inner attribute is not permitted following an outer attribute"
39
+ } else {
40
+ DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
41
+ } ;
42
+ let inner_parse_policy = InnerAttrPolicy :: Forbidden {
43
+ reason : inner_error_reason,
44
+ saw_doc_comment : just_parsed_doc_comment,
45
+ prev_attr_sp : attrs. last ( ) . map ( |a| a. span ) ,
46
+ } ;
47
+ let attr = self . parse_attribute_with_inner_parse_policy ( inner_parse_policy) ?;
48
+ attrs. push ( attr) ;
49
+ just_parsed_doc_comment = false ;
50
+ } else if let token:: DocComment ( s) = self . token . kind {
51
+ let attr = self . mk_doc_comment ( s) ;
52
+ if attr. style != ast:: AttrStyle :: Outer {
53
+ self . struct_span_err ( self . token . span , "expected outer doc comment" )
54
+ . note (
52
55
"inner doc comments like this (starting with \
53
- `//!` or `/*!`) can only appear before items",
54
- ) ;
55
- return Err ( err) ;
56
- }
57
- attrs. push ( attr) ;
58
- self . bump ( ) ;
59
- just_parsed_doc_comment = true ;
56
+ `//!` or `/*!`) can only appear before items",
57
+ )
58
+ . emit ( ) ;
60
59
}
61
- _ => break ,
60
+ attrs. push ( attr) ;
61
+ self . bump ( ) ;
62
+ just_parsed_doc_comment = true ;
63
+ } else {
64
+ break ;
62
65
}
63
66
}
64
67
Ok ( attrs)
65
68
}
66
69
67
70
fn mk_doc_comment ( & self , s : Symbol ) -> ast:: Attribute {
68
- let style = comments:: doc_comment_style ( & s. as_str ( ) ) ;
69
- attr:: mk_doc_comment ( style, s, self . token . span )
71
+ attr:: mk_doc_comment ( comments:: doc_comment_style ( & s. as_str ( ) ) , s, self . token . span )
70
72
}
71
73
72
74
/// Matches `attribute = # ! [ meta_item ]`.
@@ -75,96 +77,67 @@ impl<'a> Parser<'a> {
75
77
/// attribute.
76
78
pub fn parse_attribute ( & mut self , permit_inner : bool ) -> PResult < ' a , ast:: Attribute > {
77
79
debug ! ( "parse_attribute: permit_inner={:?} self.token={:?}" , permit_inner, self . token) ;
78
- let inner_parse_policy = if permit_inner {
79
- InnerAttributeParsePolicy :: Permitted
80
- } else {
81
- InnerAttributeParsePolicy :: NotPermitted {
82
- reason : DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG ,
83
- saw_doc_comment : false ,
84
- prev_attr_sp : None ,
85
- }
86
- } ;
80
+ let inner_parse_policy =
81
+ if permit_inner { InnerAttrPolicy :: Permitted } else { DEFAULT_INNER_ATTR_FORBIDDEN } ;
87
82
self . parse_attribute_with_inner_parse_policy ( inner_parse_policy)
88
83
}
89
84
90
- /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy `
85
+ /// The same as `parse_attribute`, except it takes in an `InnerAttrPolicy `
91
86
/// that prescribes how to handle inner attributes.
92
87
fn parse_attribute_with_inner_parse_policy (
93
88
& mut self ,
94
- inner_parse_policy : InnerAttributeParsePolicy < ' _ > ,
89
+ inner_parse_policy : InnerAttrPolicy < ' _ > ,
95
90
) -> PResult < ' a , ast:: Attribute > {
96
91
debug ! (
97
92
"parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}" ,
98
93
inner_parse_policy, self . token
99
94
) ;
100
- let ( span, item, style) = match self . token . kind {
101
- token:: Pound => {
102
- let lo = self . token . span ;
103
- self . bump ( ) ;
104
-
105
- if let InnerAttributeParsePolicy :: Permitted = inner_parse_policy {
106
- self . expected_tokens . push ( TokenType :: Token ( token:: Not ) ) ;
107
- }
108
-
109
- let style = if self . token == token:: Not {
110
- self . bump ( ) ;
111
- ast:: AttrStyle :: Inner
112
- } else {
113
- ast:: AttrStyle :: Outer
114
- } ;
95
+ let lo = self . token . span ;
96
+ let ( span, item, style) = if self . eat ( & token:: Pound ) {
97
+ let style =
98
+ if self . eat ( & token:: Not ) { ast:: AttrStyle :: Inner } else { ast:: AttrStyle :: Outer } ;
115
99
116
- self . expect ( & token:: OpenDelim ( token:: Bracket ) ) ?;
117
- let item = self . parse_attr_item ( ) ?;
118
- self . expect ( & token:: CloseDelim ( token:: Bracket ) ) ?;
119
- let hi = self . prev_token . span ;
120
-
121
- let attr_sp = lo. to ( hi) ;
122
-
123
- // Emit error if inner attribute is encountered and not permitted
124
- if style == ast:: AttrStyle :: Inner {
125
- if let InnerAttributeParsePolicy :: NotPermitted {
126
- reason,
127
- saw_doc_comment,
128
- prev_attr_sp,
129
- } = inner_parse_policy
130
- {
131
- let prev_attr_note = if saw_doc_comment {
132
- "previous doc comment"
133
- } else {
134
- "previous outer attribute"
135
- } ;
136
-
137
- let mut diagnostic = self . struct_span_err ( attr_sp, reason) ;
138
-
139
- if let Some ( prev_attr_sp) = prev_attr_sp {
140
- diagnostic
141
- . span_label ( attr_sp, "not permitted following an outer attribute" )
142
- . span_label ( prev_attr_sp, prev_attr_note) ;
143
- }
144
-
145
- diagnostic
146
- . note (
147
- "inner attributes, like `#![no_std]`, annotate the item \
148
- enclosing them, and are usually found at the beginning of \
149
- source files. Outer attributes, like `#[test]`, annotate the \
150
- item following them.",
151
- )
152
- . emit ( ) ;
153
- }
154
- }
100
+ self . expect ( & token:: OpenDelim ( token:: Bracket ) ) ?;
101
+ let item = self . parse_attr_item ( ) ?;
102
+ self . expect ( & token:: CloseDelim ( token:: Bracket ) ) ?;
103
+ let attr_sp = lo. to ( self . prev_token . span ) ;
155
104
156
- ( attr_sp, item, style)
157
- }
158
- _ => {
159
- let token_str = pprust:: token_to_string ( & self . token ) ;
160
- let msg = & format ! ( "expected `#`, found `{}`" , token_str) ;
161
- return Err ( self . struct_span_err ( self . token . span , msg) ) ;
105
+ // Emit error if inner attribute is encountered and forbidden.
106
+ if style == ast:: AttrStyle :: Inner {
107
+ self . error_on_forbidden_inner_attr ( attr_sp, inner_parse_policy) ;
162
108
}
109
+
110
+ ( attr_sp, item, style)
111
+ } else {
112
+ let token_str = pprust:: token_to_string ( & self . token ) ;
113
+ let msg = & format ! ( "expected `#`, found `{}`" , token_str) ;
114
+ return Err ( self . struct_span_err ( self . token . span , msg) ) ;
163
115
} ;
164
116
165
117
Ok ( attr:: mk_attr_from_item ( style, item, span) )
166
118
}
167
119
120
+ pub ( super ) fn error_on_forbidden_inner_attr ( & self , attr_sp : Span , policy : InnerAttrPolicy < ' _ > ) {
121
+ if let InnerAttrPolicy :: Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy {
122
+ let prev_attr_note =
123
+ if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" } ;
124
+
125
+ let mut diag = self . struct_span_err ( attr_sp, reason) ;
126
+
127
+ if let Some ( prev_attr_sp) = prev_attr_sp {
128
+ diag. span_label ( attr_sp, "not permitted following an outer attribute" )
129
+ . span_label ( prev_attr_sp, prev_attr_note) ;
130
+ }
131
+
132
+ diag. note (
133
+ "inner attributes, like `#![no_std]`, annotate the item enclosing them, \
134
+ and are usually found at the beginning of source files. \
135
+ Outer attributes, like `#[test]`, annotate the item following them.",
136
+ )
137
+ . emit ( ) ;
138
+ }
139
+ }
140
+
168
141
/// Parses an inner part of an attribute (the path and following tokens).
169
142
/// The tokens must be either a delimited token stream, or empty token stream,
170
143
/// or the "legacy" key-value form.
@@ -200,28 +173,22 @@ impl<'a> Parser<'a> {
200
173
crate fn parse_inner_attributes ( & mut self ) -> PResult < ' a , Vec < ast:: Attribute > > {
201
174
let mut attrs: Vec < ast:: Attribute > = vec ! [ ] ;
202
175
loop {
203
- match self . token . kind {
204
- token:: Pound => {
205
- // Don't even try to parse if it's not an inner attribute.
206
- if ! self . look_ahead ( 1 , |t| t == & token :: Not ) {
207
- break ;
208
- }
209
-
210
- let attr = self . parse_attribute ( true ) ? ;
211
- assert_eq ! ( attr. style, ast:: AttrStyle :: Inner ) ;
176
+ // Only try to parse if it is an inner attribute (has `!`).
177
+ if self . check ( & token:: Pound ) && self . look_ahead ( 1 , |t| t == & token :: Not ) {
178
+ let attr = self . parse_attribute ( true ) ? ;
179
+ assert_eq ! ( attr . style , ast :: AttrStyle :: Inner ) ;
180
+ attrs . push ( attr ) ;
181
+ } else if let token :: DocComment ( s ) = self . token . kind {
182
+ // We need to get the position of this token before we bump.
183
+ let attr = self . mk_doc_comment ( s ) ;
184
+ if attr. style == ast:: AttrStyle :: Inner {
212
185
attrs. push ( attr) ;
186
+ self . bump ( ) ;
187
+ } else {
188
+ break ;
213
189
}
214
- token:: DocComment ( s) => {
215
- // We need to get the position of this token before we bump.
216
- let attr = self . mk_doc_comment ( s) ;
217
- if attr. style == ast:: AttrStyle :: Inner {
218
- attrs. push ( attr) ;
219
- self . bump ( ) ;
220
- } else {
221
- break ;
222
- }
223
- }
224
- _ => break ,
190
+ } else {
191
+ break ;
225
192
}
226
193
}
227
194
Ok ( attrs)
@@ -232,12 +199,10 @@ impl<'a> Parser<'a> {
232
199
debug ! ( "checking if {:?} is unusuffixed" , lit) ;
233
200
234
201
if !lit. kind . is_unsuffixed ( ) {
235
- let msg = "suffixed literals are not allowed in attributes" ;
236
- self . struct_span_err ( lit. span , msg)
202
+ self . struct_span_err ( lit. span , "suffixed literals are not allowed in attributes" )
237
203
. help (
238
- "instead of using a suffixed literal \
239
- (`1u8`, `1.0f32`, etc.), use an unsuffixed version \
240
- (`1`, `1.0`, etc.)",
204
+ "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \
205
+ use an unsuffixed version (`1`, `1.0`, etc.)",
241
206
)
242
207
. emit ( ) ;
243
208
}
0 commit comments