@@ -18,23 +18,43 @@ use parse::token;
1818use parse:: parser:: { Parser , TokenType } ;
1919use ptr:: P ;
2020
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+
2130impl < ' a > Parser < ' a > {
2231 /// Parse attributes that appear before an item
2332 pub fn parse_outer_attributes ( & mut self ) -> PResult < ' a , Vec < ast:: Attribute > > {
2433 let mut attrs: Vec < ast:: Attribute > = Vec :: new ( ) ;
34+ let mut just_parsed_doc_comment = false ;
2535 loop {
2636 debug ! ( "parse_outer_attributes: self.token={:?}" , self . token) ;
2737 match self . token {
2838 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 ;
3050 }
3151 token:: DocComment ( s) => {
3252 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+ ) ;
3858 if attr. node . style != ast:: AttrStyle :: Outer {
3959 let mut err = self . fatal ( "expected outer doc comment" ) ;
4060 err. note ( "inner doc comments like this (starting with \
@@ -43,6 +63,7 @@ impl<'a> Parser<'a> {
4363 }
4464 attrs. push ( attr) ;
4565 self . bump ( ) ;
66+ just_parsed_doc_comment = true ;
4667 }
4768 _ => break ,
4869 }
@@ -55,26 +76,46 @@ impl<'a> Parser<'a> {
5576 /// If permit_inner is true, then a leading `!` indicates an inner
5677 /// attribute
5778 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={:?}" ,
5980 permit_inner,
6081 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) ;
6199 let ( span, value, mut style) = match self . token {
62100 token:: Pound => {
63101 let lo = self . span . lo ;
64102 self . bump ( ) ;
65103
66- if permit_inner {
104+ if inner_parse_policy == InnerAttributeParsePolicy :: Permitted {
67105 self . expected_tokens . push ( TokenType :: Token ( token:: Not ) ) ;
68106 }
69107 let style = if self . token == token:: Not {
70108 self . bump ( ) ;
71- if !permit_inner {
109+ if let InnerAttributeParsePolicy :: NotPermitted { reason } = inner_parse_policy
110+ {
72111 let span = self . span ;
73112 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." )
78119 . emit ( )
79120 }
80121 ast:: AttrStyle :: Inner
@@ -95,7 +136,8 @@ impl<'a> Parser<'a> {
95136 }
96137 } ;
97138
98- if permit_inner && self . token == token:: Semi {
139+ if inner_parse_policy == InnerAttributeParsePolicy :: Permitted &&
140+ self . token == token:: Semi {
99141 self . bump ( ) ;
100142 self . span_warn ( span,
101143 "this inner attribute syntax is deprecated. The new syntax is \
0 commit comments