@@ -18,23 +18,43 @@ use parse::token;
18
18
use parse:: parser:: { Parser , TokenType } ;
19
19
use ptr:: P ;
20
20
21
+ #[ derive( PartialEq , Eq , Debug ) ]
22
+ enum InnerAttributeParsePolicy < ' a > {
23
+ Permitted ,
24
+ NotPermitted { reason : & ' a str } ,
25
+ }
26
+
27
+ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG : & ' static str = "an inner attribute is not \
28
+ permitted in this context";
29
+
21
30
impl < ' a > Parser < ' a > {
22
31
/// Parse attributes that appear before an item
23
32
pub fn parse_outer_attributes ( & mut self ) -> PResult < ' a , Vec < ast:: Attribute > > {
24
33
let mut attrs: Vec < ast:: Attribute > = Vec :: new ( ) ;
34
+ let mut just_parsed_doc_comment = false ;
25
35
loop {
26
36
debug ! ( "parse_outer_attributes: self.token={:?}" , self . token) ;
27
37
match self . token {
28
38
token:: Pound => {
29
- attrs. push ( self . parse_attribute ( false ) ?) ;
39
+ let inner_error_reason = if just_parsed_doc_comment {
40
+ "an inner attribute is not permitted following an outer doc comment"
41
+ } else if !attrs. is_empty ( ) {
42
+ "an inner attribute is not permitted following an outer attribute"
43
+ } else {
44
+ DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
45
+ } ;
46
+ let inner_parse_policy =
47
+ InnerAttributeParsePolicy :: NotPermitted { reason : inner_error_reason } ;
48
+ attrs. push ( self . parse_attribute_with_inner_parse_policy ( inner_parse_policy) ?) ;
49
+ just_parsed_doc_comment = false ;
30
50
}
31
51
token:: DocComment ( s) => {
32
52
let attr = :: attr:: mk_sugared_doc_attr (
33
- attr:: mk_attr_id ( ) ,
34
- self . id_to_interned_str ( ast:: Ident :: with_empty_ctxt ( s) ) ,
35
- self . span . lo ,
36
- self . span . hi
37
- ) ;
53
+ attr:: mk_attr_id ( ) ,
54
+ self . id_to_interned_str ( ast:: Ident :: with_empty_ctxt ( s) ) ,
55
+ self . span . lo ,
56
+ self . span . hi
57
+ ) ;
38
58
if attr. node . style != ast:: AttrStyle :: Outer {
39
59
let mut err = self . fatal ( "expected outer doc comment" ) ;
40
60
err. note ( "inner doc comments like this (starting with \
@@ -43,6 +63,7 @@ impl<'a> Parser<'a> {
43
63
}
44
64
attrs. push ( attr) ;
45
65
self . bump ( ) ;
66
+ just_parsed_doc_comment = true ;
46
67
}
47
68
_ => break ,
48
69
}
@@ -55,26 +76,46 @@ impl<'a> Parser<'a> {
55
76
/// If permit_inner is true, then a leading `!` indicates an inner
56
77
/// attribute
57
78
pub fn parse_attribute ( & mut self , permit_inner : bool ) -> PResult < ' a , ast:: Attribute > {
58
- debug ! ( "parse_attributes : permit_inner={:?} self.token={:?}" ,
79
+ debug ! ( "parse_attribute : permit_inner={:?} self.token={:?}" ,
59
80
permit_inner,
60
81
self . token) ;
82
+ let inner_parse_policy = if permit_inner {
83
+ InnerAttributeParsePolicy :: Permitted
84
+ } else {
85
+ InnerAttributeParsePolicy :: NotPermitted
86
+ { reason : DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }
87
+ } ;
88
+ self . parse_attribute_with_inner_parse_policy ( inner_parse_policy)
89
+ }
90
+
91
+ /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
92
+ /// that prescribes how to handle inner attributes.
93
+ fn parse_attribute_with_inner_parse_policy ( & mut self ,
94
+ inner_parse_policy : InnerAttributeParsePolicy )
95
+ -> PResult < ' a , ast:: Attribute > {
96
+ debug ! ( "parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}" ,
97
+ inner_parse_policy,
98
+ self . token) ;
61
99
let ( span, value, mut style) = match self . token {
62
100
token:: Pound => {
63
101
let lo = self . span . lo ;
64
102
self . bump ( ) ;
65
103
66
- if permit_inner {
104
+ if inner_parse_policy == InnerAttributeParsePolicy :: Permitted {
67
105
self . expected_tokens . push ( TokenType :: Token ( token:: Not ) ) ;
68
106
}
69
107
let style = if self . token == token:: Not {
70
108
self . bump ( ) ;
71
- if !permit_inner {
109
+ if let InnerAttributeParsePolicy :: NotPermitted { reason } = inner_parse_policy
110
+ {
72
111
let span = self . span ;
73
112
self . diagnostic ( )
74
- . struct_span_err ( span,
75
- "an inner attribute is not permitted in this context" )
76
- . help ( "place inner attribute at the top of the module or \
77
- block")
113
+ . struct_span_err ( span, reason)
114
+ . note ( "inner attributes and doc comments, like `#![no_std]` or \
115
+ `//! My crate`, annotate the item enclosing them, and are \
116
+ usually found at the beginning of source files. Outer \
117
+ attributes and doc comments, like `#[test]` and
118
+ `/// My function`, annotate the item following them." )
78
119
. emit ( )
79
120
}
80
121
ast:: AttrStyle :: Inner
@@ -95,7 +136,8 @@ impl<'a> Parser<'a> {
95
136
}
96
137
} ;
97
138
98
- if permit_inner && self . token == token:: Semi {
139
+ if inner_parse_policy == InnerAttributeParsePolicy :: Permitted &&
140
+ self . token == token:: Semi {
99
141
self . bump ( ) ;
100
142
self . span_warn ( span,
101
143
"this inner attribute syntax is deprecated. The new syntax is \
0 commit comments