1- use super :: { Parser , PathStyle , TokenType } ;
1+ use super :: { Parser , PathStyle } ;
22use rustc_ast:: ast;
33use rustc_ast:: attr;
44use rustc_ast:: token:: { self , Nonterminal } ;
@@ -10,63 +10,65 @@ use rustc_span::{Span, Symbol};
1010use log:: debug;
1111
1212#[ derive( Debug ) ]
13- enum InnerAttributeParsePolicy < ' a > {
13+ pub ( super ) enum InnerAttrPolicy < ' a > {
1414 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 > } ,
1616}
1717
1818const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG : & str = "an inner attribute is not \
1919 permitted in this context";
2020
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+
2127impl < ' a > Parser < ' a > {
2228 /// Parses attributes that appear before an item.
2329 pub ( super ) fn parse_outer_attributes ( & mut self ) -> PResult < ' a , Vec < ast:: Attribute > > {
2430 let mut attrs: Vec < ast:: Attribute > = Vec :: new ( ) ;
2531 let mut just_parsed_doc_comment = false ;
2632 loop {
2733 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 (
5255 "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 ( ) ;
6059 }
61- _ => break ,
60+ attrs. push ( attr) ;
61+ self . bump ( ) ;
62+ just_parsed_doc_comment = true ;
63+ } else {
64+ break ;
6265 }
6366 }
6467 Ok ( attrs)
6568 }
6669
6770 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 )
7072 }
7173
7274 /// Matches `attribute = # ! [ meta_item ]`.
@@ -75,96 +77,67 @@ impl<'a> Parser<'a> {
7577 /// attribute.
7678 pub fn parse_attribute ( & mut self , permit_inner : bool ) -> PResult < ' a , ast:: Attribute > {
7779 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 } ;
8782 self . parse_attribute_with_inner_parse_policy ( inner_parse_policy)
8883 }
8984
90- /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy `
85+ /// The same as `parse_attribute`, except it takes in an `InnerAttrPolicy `
9186 /// that prescribes how to handle inner attributes.
9287 fn parse_attribute_with_inner_parse_policy (
9388 & mut self ,
94- inner_parse_policy : InnerAttributeParsePolicy < ' _ > ,
89+ inner_parse_policy : InnerAttrPolicy < ' _ > ,
9590 ) -> PResult < ' a , ast:: Attribute > {
9691 debug ! (
9792 "parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}" ,
9893 inner_parse_policy, self . token
9994 ) ;
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 } ;
11599
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 ) ;
155104
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) ;
162108 }
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) ) ;
163115 } ;
164116
165117 Ok ( attr:: mk_attr_from_item ( style, item, span) )
166118 }
167119
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+
168141 /// Parses an inner part of an attribute (the path and following tokens).
169142 /// The tokens must be either a delimited token stream, or empty token stream,
170143 /// or the "legacy" key-value form.
@@ -200,28 +173,22 @@ impl<'a> Parser<'a> {
200173 crate fn parse_inner_attributes ( & mut self ) -> PResult < ' a , Vec < ast:: Attribute > > {
201174 let mut attrs: Vec < ast:: Attribute > = vec ! [ ] ;
202175 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 {
212185 attrs. push ( attr) ;
186+ self . bump ( ) ;
187+ } else {
188+ break ;
213189 }
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 ;
225192 }
226193 }
227194 Ok ( attrs)
@@ -232,12 +199,10 @@ impl<'a> Parser<'a> {
232199 debug ! ( "checking if {:?} is unusuffixed" , lit) ;
233200
234201 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" )
237203 . 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.)",
241206 )
242207 . emit ( ) ;
243208 }
0 commit comments