Skip to content

Commit 4b571b0

Browse files
Handle gateage of built-in attributes seperately
This allows marking attributes as whitelisted/crate-only independent of their feature gate status. Closes #24213
1 parent 6f28232 commit 4b571b0

File tree

4 files changed

+149
-127
lines changed

4 files changed

+149
-127
lines changed

src/librustc/plugin/registry.rs

-5
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,6 @@ impl<'a> Registry<'a> {
145145
/// `Whitelisted` attributes will additionally not trigger the `unused_attribute`
146146
/// lint. `CrateLevel` attributes will not be allowed on anything other than a crate.
147147
pub fn register_attribute(&mut self, name: String, ty: AttributeType) {
148-
if let AttributeType::Gated(..) = ty {
149-
self.sess.span_err(self.krate_span, "plugin tried to register a gated \
150-
attribute. Only `Normal`, `Whitelisted`, \
151-
and `CrateLevel` attributes are allowed");
152-
}
153148
self.attributes.push((name, ty));
154149
}
155150
}

src/librustc_lint/builtin.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -887,10 +887,9 @@ impl LintPass for UnusedAttributes {
887887

888888
fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) {
889889
// Note that check_name() marks the attribute as used if it matches.
890-
for &(ref name, ty) in KNOWN_ATTRIBUTES {
890+
for &(ref name, ty, _) in KNOWN_ATTRIBUTES {
891891
match ty {
892-
AttributeType::Whitelisted
893-
| AttributeType::Gated(_, _) if attr.check_name(name) => {
892+
AttributeType::Whitelisted if attr.check_name(name) => {
894893
break;
895894
},
896895
_ => ()
@@ -907,8 +906,11 @@ impl LintPass for UnusedAttributes {
907906
if !attr::is_used(attr) {
908907
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
909908
// Is it a builtin attribute that must be used at the crate level?
910-
let known_crate = KNOWN_ATTRIBUTES.contains(&(&attr.name(),
911-
AttributeType::CrateLevel));
909+
let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| {
910+
attr.name() == name &&
911+
ty == AttributeType::CrateLevel
912+
}).is_some();
913+
912914
// Has a plugin registered this attribute as one which must be used at
913915
// the crate level?
914916
let plugin_crate = plugin_attributes.iter()

src/libsyntax/feature_gate.rs

+125-117
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
2525
use self::Status::*;
2626
use self::AttributeType::*;
27+
use self::AttributeGate::*;
2728

2829
use abi::Abi;
2930
use ast::NodeId;
@@ -203,135 +204,137 @@ enum Status {
203204
}
204205

205206
// Attributes that have a special meaning to rustc or rustdoc
206-
pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
207+
pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
207208
// Normal attributes
208209

209-
("warn", Normal),
210-
("allow", Normal),
211-
("forbid", Normal),
212-
("deny", Normal),
213-
214-
("macro_reexport", Normal),
215-
("macro_use", Normal),
216-
("macro_export", Normal),
217-
("plugin_registrar", Normal),
218-
219-
("cfg", Normal),
220-
("cfg_attr", Normal),
221-
("main", Normal),
222-
("start", Normal),
223-
("test", Normal),
224-
("bench", Normal),
225-
("simd", Normal),
226-
("repr", Normal),
227-
("path", Normal),
228-
("abi", Normal),
229-
("automatically_derived", Normal),
230-
("no_mangle", Normal),
231-
("no_link", Normal),
232-
("derive", Normal),
233-
("should_panic", Normal),
234-
("ignore", Normal),
235-
("no_implicit_prelude", Normal),
236-
("reexport_test_harness_main", Normal),
237-
("link_args", Normal),
238-
("macro_escape", Normal),
210+
("warn", Normal, Ungated),
211+
("allow", Normal, Ungated),
212+
("forbid", Normal, Ungated),
213+
("deny", Normal, Ungated),
214+
215+
("macro_reexport", Normal, Ungated),
216+
("macro_use", Normal, Ungated),
217+
("macro_export", Normal, Ungated),
218+
("plugin_registrar", Normal, Ungated),
219+
220+
("cfg", Normal, Ungated),
221+
("cfg_attr", Normal, Ungated),
222+
("main", Normal, Ungated),
223+
("start", Normal, Ungated),
224+
("test", Normal, Ungated),
225+
("bench", Normal, Ungated),
226+
("simd", Normal, Ungated),
227+
("repr", Normal, Ungated),
228+
("path", Normal, Ungated),
229+
("abi", Normal, Ungated),
230+
("automatically_derived", Normal, Ungated),
231+
("no_mangle", Normal, Ungated),
232+
("no_link", Normal, Ungated),
233+
("derive", Normal, Ungated),
234+
("should_panic", Normal, Ungated),
235+
("ignore", Normal, Ungated),
236+
("no_implicit_prelude", Normal, Ungated),
237+
("reexport_test_harness_main", Normal, Ungated),
238+
("link_args", Normal, Ungated),
239+
("macro_escape", Normal, Ungated),
239240

240241
// Not used any more, but we can't feature gate it
241-
("no_stack_check", Normal),
242-
243-
("staged_api", Gated("staged_api",
244-
"staged_api is for use by rustc only")),
245-
("plugin", Gated("plugin",
246-
"compiler plugins are experimental \
247-
and possibly buggy")),
248-
("no_std", Gated("no_std",
249-
"no_std is experimental")),
250-
("no_core", Gated("no_core",
251-
"no_core is experimental")),
252-
("lang", Gated("lang_items",
253-
"language items are subject to change")),
254-
("linkage", Gated("linkage",
255-
"the `linkage` attribute is experimental \
256-
and not portable across platforms")),
257-
("thread_local", Gated("thread_local",
258-
"`#[thread_local]` is an experimental feature, and does not \
259-
currently handle destructors. There is no corresponding \
260-
`#[task_local]` mapping to the task model")),
261-
262-
("rustc_on_unimplemented", Gated("on_unimplemented",
263-
"the `#[rustc_on_unimplemented]` attribute \
242+
("no_stack_check", Normal, Ungated),
243+
244+
("staged_api", CrateLevel, Gated("staged_api",
245+
"staged_api is for use by rustc only")),
246+
("plugin", CrateLevel, Gated("plugin",
247+
"compiler plugins are experimental \
248+
and possibly buggy")),
249+
("no_std", CrateLevel, Gated("no_std",
250+
"no_std is experimental")),
251+
("no_core", CrateLevel, Gated("no_core",
252+
"no_core is experimental")),
253+
("lang", Normal, Gated("lang_items",
254+
"language items are subject to change")),
255+
("linkage", Whitelisted, Gated("linkage",
256+
"the `linkage` attribute is experimental \
257+
and not portable across platforms")),
258+
("thread_local", Whitelisted, Gated("thread_local",
259+
"`#[thread_local]` is an experimental feature, and does \
260+
not currently handle destructors. There is no \
261+
corresponding `#[task_local]` mapping to the task \
262+
model")),
263+
264+
("rustc_on_unimplemented", Normal, Gated("on_unimplemented",
265+
"the `#[rustc_on_unimplemented]` attribute \
266+
is an experimental feature")),
267+
("allocator", Whitelisted, Gated("allocator",
268+
"the `#[allocator]` attribute is an experimental feature")),
269+
("needs_allocator", Normal, Gated("needs_allocator",
270+
"the `#[needs_allocator]` \
271+
attribute is an experimental \
272+
feature")),
273+
("rustc_variance", Normal, Gated("rustc_attrs",
274+
"the `#[rustc_variance]` attribute \
264275
is an experimental feature")),
265-
("allocator", Gated("allocator",
266-
"the `#[allocator]` attribute is an experimental feature")),
267-
("needs_allocator", Gated("needs_allocator", "the `#[needs_allocator]` \
268-
attribute is an experimental \
269-
feature")),
270-
("rustc_variance", Gated("rustc_attrs",
271-
"the `#[rustc_variance]` attribute \
272-
is an experimental feature")),
273-
("rustc_error", Gated("rustc_attrs",
274-
"the `#[rustc_error]` attribute \
275-
is an experimental feature")),
276-
("rustc_move_fragments", Gated("rustc_attrs",
277-
"the `#[rustc_move_fragments]` attribute \
278-
is an experimental feature")),
279-
280-
("allow_internal_unstable", Gated("allow_internal_unstable",
281-
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
282-
283-
("fundamental", Gated("fundamental",
284-
"the `#[fundamental]` attribute \
285-
is an experimental feature")),
286-
287-
("linked_from", Gated("linked_from",
288-
"the `#[linked_from]` attribute \
289-
is an experimental feature")),
276+
("rustc_error", Whitelisted, Gated("rustc_attrs",
277+
"the `#[rustc_error]` attribute \
278+
is an experimental feature")),
279+
("rustc_move_fragments", Normal, Gated("rustc_attrs",
280+
"the `#[rustc_move_fragments]` attribute \
281+
is an experimental feature")),
282+
283+
("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
284+
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
285+
286+
("fundamental", Whitelisted, Gated("fundamental",
287+
"the `#[fundamental]` attribute \
288+
is an experimental feature")),
289+
290+
("linked_from", Normal, Gated("linked_from",
291+
"the `#[linked_from]` attribute \
292+
is an experimental feature")),
290293

291294
// FIXME: #14408 whitelist docs since rustdoc looks at them
292-
("doc", Whitelisted),
295+
("doc", Whitelisted, Ungated),
293296

294297
// FIXME: #14406 these are processed in trans, which happens after the
295298
// lint pass
296-
("cold", Whitelisted),
297-
("export_name", Whitelisted),
298-
("inline", Whitelisted),
299-
("link", Whitelisted),
300-
("link_name", Whitelisted),
301-
("link_section", Whitelisted),
302-
("no_builtins", Whitelisted),
303-
("no_mangle", Whitelisted),
304-
("no_debug", Whitelisted),
305-
("omit_gdb_pretty_printer_section", Whitelisted),
306-
("unsafe_no_drop_flag", Gated("unsafe_no_drop_flag",
307-
"unsafe_no_drop_flag has unstable semantics \
308-
and may be removed in the future")),
299+
("cold", Whitelisted, Ungated),
300+
("export_name", Whitelisted, Ungated),
301+
("inline", Whitelisted, Ungated),
302+
("link", Whitelisted, Ungated),
303+
("link_name", Whitelisted, Ungated),
304+
("link_section", Whitelisted, Ungated),
305+
("no_builtins", Whitelisted, Ungated),
306+
("no_mangle", Whitelisted, Ungated),
307+
("no_debug", Whitelisted, Ungated),
308+
("omit_gdb_pretty_printer_section", Whitelisted, Ungated),
309+
("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
310+
"unsafe_no_drop_flag has unstable semantics \
311+
and may be removed in the future")),
309312

310313
// used in resolve
311-
("prelude_import", Gated("prelude_import",
312-
"`#[prelude_import]` is for use by rustc only")),
314+
("prelude_import", Whitelisted, Gated("prelude_import",
315+
"`#[prelude_import]` is for use by rustc only")),
313316

314317
// FIXME: #14407 these are only looked at on-demand so we can't
315318
// guarantee they'll have already been checked
316-
("deprecated", Whitelisted),
317-
("must_use", Whitelisted),
318-
("stable", Whitelisted),
319-
("unstable", Whitelisted),
319+
("deprecated", Whitelisted, Ungated),
320+
("must_use", Whitelisted, Ungated),
321+
("stable", Whitelisted, Ungated),
322+
("unstable", Whitelisted, Ungated),
320323

321-
("rustc_paren_sugar", Gated("unboxed_closures",
322-
"unboxed_closures are still evolving")),
323-
("rustc_reflect_like", Gated("reflect",
324-
"defining reflective traits is still evolving")),
324+
("rustc_paren_sugar", Normal, Gated("unboxed_closures",
325+
"unboxed_closures are still evolving")),
326+
("rustc_reflect_like", Whitelisted, Gated("reflect",
327+
"defining reflective traits is still evolving")),
325328

326329
// Crate level attributes
327-
("crate_name", CrateLevel),
328-
("crate_type", CrateLevel),
329-
("crate_id", CrateLevel),
330-
("feature", CrateLevel),
331-
("no_start", CrateLevel),
332-
("no_main", CrateLevel),
333-
("no_builtins", CrateLevel),
334-
("recursion_limit", CrateLevel),
330+
("crate_name", CrateLevel, Ungated),
331+
("crate_type", CrateLevel, Ungated),
332+
("crate_id", CrateLevel, Ungated),
333+
("feature", CrateLevel, Ungated),
334+
("no_start", CrateLevel, Ungated),
335+
("no_main", CrateLevel, Ungated),
336+
("no_builtins", CrateLevel, Ungated),
337+
("recursion_limit", CrateLevel, Ungated),
335338
];
336339

337340
macro_rules! cfg_fn {
@@ -398,12 +401,17 @@ pub enum AttributeType {
398401
/// will be ignored by the unused_attribute lint
399402
Whitelisted,
400403

404+
/// Builtin attribute that is only allowed at the crate level
405+
CrateLevel,
406+
}
407+
408+
#[derive(PartialEq, Copy, Clone, Debug)]
409+
pub enum AttributeGate {
401410
/// Is gated by a given feature gate and reason
402-
/// These get whitelisted too
403411
Gated(&'static str, &'static str),
404412

405-
/// Builtin attribute that is only allowed at the crate level
406-
CrateLevel,
413+
/// Ungated attribute, can be used on all release channels
414+
Ungated,
407415
}
408416

409417
/// A set of features to be used by later passes.
@@ -522,12 +530,12 @@ impl<'a> Context<'a> {
522530
fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
523531
debug!("check_attribute(attr = {:?})", attr);
524532
let name = &*attr.name();
525-
for &(n, ty) in KNOWN_ATTRIBUTES {
533+
for &(n, ty, gateage) in KNOWN_ATTRIBUTES {
526534
if n == name {
527-
if let Gated(gate, desc) = ty {
535+
if let Gated(gate, desc) = gateage {
528536
self.gate_feature(gate, attr.span, desc);
529537
}
530-
debug!("check_attribute: {:?} is known, {:?}", name, ty);
538+
debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
531539
return;
532540
}
533541
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![deny(unused_attributes)]
12+
#![feature(plugin)]
13+
14+
#[plugin(bla)] //~ ERROR unused attribute
15+
//~^ ERROR should be an inner attribute
16+
17+
fn main() {}

0 commit comments

Comments
 (0)