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,68 @@ 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 \
134
+ enclosing them, and are usually found at the beginning of \
135
+ source files. Outer attributes, like `#[test]`, annotate the \
136
+ item following them.",
137
+ )
138
+ . emit ( ) ;
139
+ }
140
+ }
141
+
168
142
/// Parses an inner part of an attribute (the path and following tokens).
169
143
/// The tokens must be either a delimited token stream, or empty token stream,
170
144
/// or the "legacy" key-value form.
@@ -200,24 +174,22 @@ impl<'a> Parser<'a> {
200
174
crate fn parse_inner_attributes ( & mut self ) -> PResult < ' a , Vec < ast:: Attribute > > {
201
175
let mut attrs: Vec < ast:: Attribute > = vec ! [ ] ;
202
176
loop {
203
- match self . token . kind {
204
- // Only try to parse if it is an inner attribute (has `!`).
205
- token:: Pound if self . look_ahead ( 1 , |t| t == & token:: Not ) => {
206
- let attr = self . parse_attribute ( true ) ?;
207
- assert_eq ! ( attr. style, ast:: AttrStyle :: Inner ) ;
177
+ // Only try to parse if it is an inner attribute (has `!`).
178
+ if self . check ( & token:: Pound ) && self . look_ahead ( 1 , |t| t == & token:: Not ) {
179
+ let attr = self . parse_attribute ( true ) ?;
180
+ assert_eq ! ( attr. style, ast:: AttrStyle :: Inner ) ;
181
+ attrs. push ( attr) ;
182
+ } else if let token:: DocComment ( s) = self . token . kind {
183
+ // We need to get the position of this token before we bump.
184
+ let attr = self . mk_doc_comment ( s) ;
185
+ if attr. style == ast:: AttrStyle :: Inner {
208
186
attrs. push ( attr) ;
187
+ self . bump ( ) ;
188
+ } else {
189
+ break ;
209
190
}
210
- token:: DocComment ( s) => {
211
- // We need to get the position of this token before we bump.
212
- let attr = self . mk_doc_comment ( s) ;
213
- if attr. style == ast:: AttrStyle :: Inner {
214
- attrs. push ( attr) ;
215
- self . bump ( ) ;
216
- } else {
217
- break ;
218
- }
219
- }
220
- _ => break ,
191
+ } else {
192
+ break ;
221
193
}
222
194
}
223
195
Ok ( attrs)
@@ -228,8 +200,7 @@ impl<'a> Parser<'a> {
228
200
debug ! ( "checking if {:?} is unusuffixed" , lit) ;
229
201
230
202
if !lit. kind . is_unsuffixed ( ) {
231
- let msg = "suffixed literals are not allowed in attributes" ;
232
- self . struct_span_err ( lit. span , msg)
203
+ self . struct_span_err ( lit. span , "suffixed literals are not allowed in attributes" )
233
204
. help (
234
205
"instead of using a suffixed literal \
235
206
(`1u8`, `1.0f32`, etc.), use an unsuffixed version \
0 commit comments