@@ -4,7 +4,7 @@ use crate::parse_in;
44
55use rustc_ast:: tokenstream:: { DelimSpan , TokenTree } ;
66use rustc_ast:: { self as ast, Attribute , MacArgs , MacDelimiter , MetaItem , MetaItemKind } ;
7- use rustc_errors:: { Applicability , PResult } ;
7+ use rustc_errors:: { Applicability , FatalError , PResult } ;
88use rustc_feature:: { AttributeTemplate , BUILTIN_ATTRIBUTE_MAP } ;
99use rustc_session:: lint:: builtin:: ILL_FORMED_ATTRIBUTE_INPUT ;
1010use rustc_session:: parse:: ParseSess ;
@@ -91,73 +91,86 @@ pub fn check_builtin_attribute(
9191 // Some special attributes like `cfg` must be checked
9292 // before the generic check, so we skip them here.
9393 let should_skip = |name| name == sym:: cfg;
94- // Some of previously accepted forms were used in practice,
95- // report them as warnings for now.
96- let should_warn = |name| {
97- name == sym:: doc
98- || name == sym:: ignore
99- || name == sym:: inline
100- || name == sym:: link
101- || name == sym:: test
102- || name == sym:: bench
103- } ;
10494
10595 match parse_meta ( sess, attr) {
10696 Ok ( meta) => {
10797 if !should_skip ( name) && !is_attr_template_compatible ( & template, & meta. kind ) {
108- let error_msg = format ! ( "malformed `{}` attribute input" , name) ;
109- let mut msg = "attribute must be of the form " . to_owned ( ) ;
110- let mut suggestions = vec ! [ ] ;
111- let mut first = true ;
112- if template. word {
113- first = false ;
114- let code = format ! ( "#[{}]" , name) ;
115- msg. push_str ( & format ! ( "`{}`" , & code) ) ;
116- suggestions. push ( code) ;
117- }
118- if let Some ( descr) = template. list {
119- if !first {
120- msg. push_str ( " or " ) ;
121- }
122- first = false ;
123- let code = format ! ( "#[{}({})]" , name, descr) ;
124- msg. push_str ( & format ! ( "`{}`" , & code) ) ;
125- suggestions. push ( code) ;
126- }
127- if let Some ( descr) = template. name_value_str {
128- if !first {
129- msg. push_str ( " or " ) ;
130- }
131- let code = format ! ( "#[{} = \" {}\" ]" , name, descr) ;
132- msg. push_str ( & format ! ( "`{}`" , & code) ) ;
133- suggestions. push ( code) ;
134- }
135- if should_warn ( name) {
136- sess. buffer_lint (
137- & ILL_FORMED_ATTRIBUTE_INPUT ,
138- meta. span ,
139- ast:: CRATE_NODE_ID ,
140- & msg,
141- ) ;
142- } else {
143- sess. span_diagnostic
144- . struct_span_err ( meta. span , & error_msg)
145- . span_suggestions (
146- meta. span ,
147- if suggestions. len ( ) == 1 {
148- "must be of the form"
149- } else {
150- "the following are the possible correct uses"
151- } ,
152- suggestions. into_iter ( ) ,
153- Applicability :: HasPlaceholders ,
154- )
155- . emit ( ) ;
156- }
98+ emit_malformed_attribute ( sess, attr, name, template) ;
15799 }
158100 }
159101 Err ( mut err) => {
160102 err. emit ( ) ;
161103 }
162104 }
163105}
106+
107+ fn emit_malformed_attribute (
108+ sess : & ParseSess ,
109+ attr : & Attribute ,
110+ name : Symbol ,
111+ template : AttributeTemplate ,
112+ ) {
113+ // Some of previously accepted forms were used in practice,
114+ // report them as warnings for now.
115+ let should_warn = |name| {
116+ matches ! ( name, sym:: doc | sym:: ignore | sym:: inline | sym:: link | sym:: test | sym:: bench)
117+ } ;
118+
119+ let error_msg = format ! ( "malformed `{}` attribute input" , name) ;
120+ let mut msg = "attribute must be of the form " . to_owned ( ) ;
121+ let mut suggestions = vec ! [ ] ;
122+ let mut first = true ;
123+ let inner = if attr. style == ast:: AttrStyle :: Inner { "!" } else { "" } ;
124+ if template. word {
125+ first = false ;
126+ let code = format ! ( "#{}[{}]" , inner, name) ;
127+ msg. push_str ( & format ! ( "`{}`" , & code) ) ;
128+ suggestions. push ( code) ;
129+ }
130+ if let Some ( descr) = template. list {
131+ if !first {
132+ msg. push_str ( " or " ) ;
133+ }
134+ first = false ;
135+ let code = format ! ( "#{}[{}({})]" , inner, name, descr) ;
136+ msg. push_str ( & format ! ( "`{}`" , & code) ) ;
137+ suggestions. push ( code) ;
138+ }
139+ if let Some ( descr) = template. name_value_str {
140+ if !first {
141+ msg. push_str ( " or " ) ;
142+ }
143+ let code = format ! ( "#{}[{} = \" {}\" ]" , inner, name, descr) ;
144+ msg. push_str ( & format ! ( "`{}`" , & code) ) ;
145+ suggestions. push ( code) ;
146+ }
147+ if should_warn ( name) {
148+ sess. buffer_lint ( & ILL_FORMED_ATTRIBUTE_INPUT , attr. span , ast:: CRATE_NODE_ID , & msg) ;
149+ } else {
150+ sess. span_diagnostic
151+ . struct_span_err ( attr. span , & error_msg)
152+ . span_suggestions (
153+ attr. span ,
154+ if suggestions. len ( ) == 1 {
155+ "must be of the form"
156+ } else {
157+ "the following are the possible correct uses"
158+ } ,
159+ suggestions. into_iter ( ) ,
160+ Applicability :: HasPlaceholders ,
161+ )
162+ . emit ( ) ;
163+ }
164+ }
165+
166+ pub fn emit_fatal_malformed_builtin_attribute (
167+ sess : & ParseSess ,
168+ attr : & Attribute ,
169+ name : Symbol ,
170+ ) -> ! {
171+ let template = BUILTIN_ATTRIBUTE_MAP . get ( & name) . expect ( "builtin attr defined" ) . 2 ;
172+ emit_malformed_attribute ( sess, attr, name, template) ;
173+ // This is fatal, otherwise it will likely cause a cascade of other errors
174+ // (and an error here is expected to be very rare).
175+ FatalError . raise ( )
176+ }
0 commit comments