Rollup merge of #22364 - Manishearth:rfc-572-forbid-attr, r=nikomatsakis

fixes #22203

r? @nikomatsakis

This breaks code that might be using attributes randomly, so it's technically a

[breaking-change]
This commit is contained in:
Manish Goregaokar 2015-02-17 15:51:53 +05:30
commit 4647d89205
37 changed files with 244 additions and 118 deletions

View file

@ -2398,6 +2398,10 @@ The currently implemented features of the reference compiler are:
ways insufficient for concatenating identifiers, and may be
removed entirely for something more wholesome.
* `custom_attribute` - Allows the usage of attributes unknown to the compiler
so that new attributes can be added in a bacwards compatible
manner (RFC 572).
* `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
are inherently unstable and no promise about them is made.
@ -2458,6 +2462,9 @@ The currently implemented features of the reference compiler are:
implemented very poorly and will likely change significantly
with a proper implementation.
* `rustc_attrs` - Gates internal `#[rustc_*]` attributes which may be
for internal use only or have meaning added to them in the future.
* `rustc_diagnostic_macros`- A mysterious feature, used in the implementation
of rustc, not meant for mortals.

View file

@ -67,6 +67,7 @@
#![feature(simd, unsafe_destructor)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(rustc_attrs)]
#[macro_use]
mod macros;

View file

@ -47,6 +47,7 @@ use syntax::{abi, ast, ast_map};
use syntax::ast_util::is_shift_binop;
use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::{self, Span};
use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType};
use syntax::parse::token;
use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64};
use syntax::ast_util;
@ -640,67 +641,19 @@ impl LintPass for UnusedAttributes {
}
fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) {
static ATTRIBUTE_WHITELIST: &'static [&'static str] = &[
// FIXME: #14408 whitelist docs since rustdoc looks at them
"doc",
// FIXME: #14406 these are processed in trans, which happens after the
// lint pass
"cold",
"export_name",
"inline",
"link",
"link_name",
"link_section",
"linkage",
"no_builtins",
"no_mangle",
"no_split_stack",
"no_stack_check",
"packed",
"static_assert",
"thread_local",
"no_debug",
"omit_gdb_pretty_printer_section",
"unsafe_no_drop_flag",
// used in resolve
"prelude_import",
// FIXME: #14407 these are only looked at on-demand so we can't
// guarantee they'll have already been checked
"deprecated",
"must_use",
"stable",
"unstable",
"rustc_on_unimplemented",
"rustc_error",
// FIXME: #19470 this shouldn't be needed forever
"old_orphan_check",
"old_impl_check",
"rustc_paren_sugar", // FIXME: #18101 temporary unboxed closure hack
];
static CRATE_ATTRS: &'static [&'static str] = &[
"crate_name",
"crate_type",
"feature",
"no_start",
"no_main",
"no_std",
"no_builtins",
];
for &name in ATTRIBUTE_WHITELIST {
if attr.check_name(name) {
break;
for &(ref name, ty) in KNOWN_ATTRIBUTES {
match ty {
AttributeType::Whitelisted
| AttributeType::Gated(_, _) if attr.check_name(name) => {
break;
},
_ => ()
}
}
if !attr::is_used(attr) {
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
if CRATE_ATTRS.contains(&&attr.name()[]) {
if KNOWN_ATTRIBUTES.contains(&(&attr.name()[], AttributeType::CrateLevel)) {
let msg = match attr.node.style {
ast::AttrOuter => "crate-level attribute should be an inner \
attribute: add an exclamation mark: #![foo]",

View file

@ -23,6 +23,7 @@
//! becomes stable.
use self::Status::*;
use self::AttributeType::*;
use abi::RustIntrinsic;
use ast::NodeId;
@ -35,7 +36,6 @@ use visit;
use visit::Visitor;
use parse::token::{self, InternedString};
use std::slice;
use std::ascii::AsciiExt;
// If you change this list without updating src/doc/reference.md, @cmr will be sad
@ -133,6 +133,12 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
// Allows using the unsafe_no_drop_flag attribute (unlikely to
// switch to Accepted; see RFC 320)
("unsafe_no_drop_flag", "1.0.0", Active),
// Allows the use of custom attributes; RFC 572
("custom_attribute", "1.0.0", Active),
// Allows the use of rustc_* attributes; RFC 572
("rustc_attrs", "1.0.0", Active),
];
// (changing above list without updating src/doc/reference.md makes @cmr sad)
@ -152,6 +158,138 @@ enum Status {
Accepted,
}
// Attributes that have a special meaning to rustc or rustdoc
pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
// Normal attributes
("warn", Normal),
("allow", Normal),
("forbid", Normal),
("deny", Normal),
("macro_reexport", Normal),
("macro_use", Normal),
("macro_export", Normal),
("plugin_registrar", Normal),
("cfg", Normal),
("main", Normal),
("start", Normal),
("test", Normal),
("bench", Normal),
("simd", Normal),
("repr", Normal),
("path", Normal),
("abi", Normal),
("unsafe_destructor", Normal),
("automatically_derived", Normal),
("no_mangle", Normal),
("no_link", Normal),
("derive", Normal),
("should_fail", Normal),
("ignore", Normal),
("no_implicit_prelude", Normal),
("reexport_test_harness_main", Normal),
("link_args", Normal),
("macro_escape", Normal),
("staged_api", Gated("staged_api",
"staged_api is for use by rustc only")),
("plugin", Gated("plugin",
"compiler plugins are experimental \
and possibly buggy")),
("no_std", Gated("no_std",
"no_std is experimental")),
("lang", Gated("lang_items",
"language items are subject to change")),
("linkage", Gated("linkage",
"the `linkage` attribute is experimental \
and not portable across platforms")),
("thread_local", Gated("thread_local",
"`#[thread_local]` is an experimental feature, and does not \
currently handle destructors. There is no corresponding \
`#[task_local]` mapping to the task model")),
("rustc_on_unimplemented", Gated("on_unimplemented",
"the `#[rustc_on_unimplemented]` attribute \
is an experimental feature")),
("rustc_variance", Gated("rustc_attrs",
"the `#[rustc_variance]` attribute \
is an experimental feature")),
("rustc_error", Gated("rustc_attrs",
"the `#[rustc_error]` attribute \
is an experimental feature")),
("rustc_move_fragments", Gated("rustc_attrs",
"the `#[rustc_move_fragments]` attribute \
is an experimental feature")),
// FIXME: #14408 whitelist docs since rustdoc looks at them
("doc", Whitelisted),
// FIXME: #14406 these are processed in trans, which happens after the
// lint pass
("cold", Whitelisted),
("export_name", Whitelisted),
("inline", Whitelisted),
("link", Whitelisted),
("link_name", Whitelisted),
("link_section", Whitelisted),
("no_builtins", Whitelisted),
("no_mangle", Whitelisted),
("no_split_stack", Whitelisted),
("no_stack_check", Whitelisted),
("packed", Whitelisted),
("static_assert", Whitelisted),
("no_debug", Whitelisted),
("omit_gdb_pretty_printer_section", Whitelisted),
("unsafe_no_drop_flag", Whitelisted),
// used in resolve
("prelude_import", Whitelisted),
// FIXME: #14407 these are only looked at on-demand so we can't
// guarantee they'll have already been checked
("deprecated", Whitelisted),
("must_use", Whitelisted),
("stable", Whitelisted),
("unstable", Whitelisted),
// FIXME: #19470 this shouldn't be needed forever
("old_orphan_check", Whitelisted),
("old_impl_check", Whitelisted),
("rustc_paren_sugar", Whitelisted), // FIXME: #18101 temporary unboxed closure hack
// Crate level attributes
("crate_name", CrateLevel),
("crate_type", CrateLevel),
("crate_id", CrateLevel),
("feature", CrateLevel),
("no_start", CrateLevel),
("no_main", CrateLevel),
("no_builtins", CrateLevel),
("recursion_limit", CrateLevel),
];
#[derive(PartialEq, Copy)]
pub enum AttributeType {
/// Normal, builtin attribute that is consumed
/// by the compiler before the unused_attribute check
Normal,
/// Builtin attribute that may not be consumed by the compiler
/// before the unused_attribute check. These attributes
/// will be ignored by the unused_attribute lint
Whitelisted,
/// Is gated by a given feature gate and reason
/// These get whitelisted too
Gated(&'static str, &'static str),
/// Builtin attribute that is only allowed at the crate level
CrateLevel,
}
/// A set of features to be used by later passes.
pub struct Features {
pub unboxed_closures: bool,
@ -274,22 +412,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
}
fn visit_item(&mut self, i: &ast::Item) {
for attr in &i.attrs {
if attr.name() == "thread_local" {
self.gate_feature("thread_local", i.span,
"`#[thread_local]` is an experimental feature, and does not \
currently handle destructors. There is no corresponding \
`#[task_local]` mapping to the task model");
} else if attr.name() == "linkage" {
self.gate_feature("linkage", i.span,
"the `linkage` attribute is experimental \
and not portable across platforms")
} else if attr.name() == "rustc_on_unimplemented" {
self.gate_feature("on_unimplemented", i.span,
"the `#[rustc_on_unimplemented]` attribute \
is an experimental feature")
}
}
match i.node {
ast::ItemExternCrate(_) => {
if attr::contains_name(&i.attrs[], "macro_reexport") {
@ -463,30 +585,27 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
}
fn visit_attribute(&mut self, attr: &ast::Attribute) {
if attr.check_name("staged_api") {
self.gate_feature("staged_api", attr.span,
"staged_api is for use by rustc only");
} else if attr.check_name("plugin") {
self.gate_feature("plugin", attr.span,
"compiler plugins are experimental \
and possibly buggy");
let name = &*attr.name();
for &(n, ty) in KNOWN_ATTRIBUTES {
if n == name {
if let Gated(gate, desc) = ty {
self.gate_feature(gate, attr.span, desc);
}
return;
}
}
if attr::contains_name(slice::ref_slice(attr), "lang") {
self.gate_feature("lang_items",
attr.span,
"language items are subject to change");
}
if attr.check_name("no_std") {
self.gate_feature("no_std", attr.span,
"no_std is experimental");
}
if attr.check_name("unsafe_no_drop_flag") {
self.gate_feature("unsafe_no_drop_flag", attr.span,
"unsafe_no_drop_flag has unstable semantics \
and may be removed in the future");
if name.starts_with("rustc_") {
self.gate_feature("rustc_attrs", attr.span,
"unless otherwise specified, attributes \
with the prefix `rustc_` \
are reserved for internal compiler diagnostics");
} else {
self.gate_feature("custom_attribute", attr.span,
format!("The attribute `{}` is currently \
unknown to the the compiler and \
may have meaning \
added to it in the future",
name).as_slice());
}
}

View file

@ -64,16 +64,6 @@ impl MethodTester {
pub fn method_stable(&self) {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
pub fn method_stable_text(&self) {}
#[locked]
pub fn method_locked(&self) {}
#[locked="text"]
pub fn method_locked_text(&self) {}
#[frozen]
pub fn method_frozen(&self) {}
#[frozen="text"]
pub fn method_frozen_text(&self) {}
}
#[stable(feature = "test_feature", since = "1.0.0")]
@ -101,16 +91,6 @@ pub trait Trait {
fn trait_stable(&self) {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
fn trait_stable_text(&self) {}
#[locked]
fn trait_locked(&self) {}
#[locked="text"]
fn trait_locked_text(&self) {}
#[frozen]
fn trait_frozen(&self) {}
#[frozen="text"]
fn trait_frozen_text(&self) {}
}
impl Trait for MethodTester {}

View file

@ -0,0 +1,14 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[foo] //~ ERROR The attribute `foo`
fn main() {
}

View file

@ -11,4 +11,5 @@
extern {
#[linkage = "extern_weak"] static foo: isize;
//~^ ERROR: the `linkage` attribute is experimental and not portable
//~^^ ERROR: the `linkage` attribute is experimental and not portable
}

View file

@ -10,6 +10,6 @@
#[linkage = "external"]
static foo: isize = 0;
//~^ ERROR: the `linkage` attribute is experimental and not portable
//~^^ ERROR: the `linkage` attribute is experimental and not portable
fn main() {}

View file

@ -13,6 +13,7 @@
#![deny(unused_attributes)]
#![allow(dead_code)]
#![feature(custom_attribute)]
#[abi="stdcall"] extern {} //~ ERROR unused attribute

View file

@ -11,6 +11,7 @@
// When denying at the crate level, be sure to not get random warnings from the
// injected intrinsics by the compiler.
#![feature(custom_attribute)]
#![deny(unused_attributes)]
#![mutable_doc] //~ ERROR unused attribute

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(custom_attribute)]
macro_rules! test { ($nm:ident,
#[$a:meta],
$i:item) => (mod $nm { #![$a] $i }); }

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(custom_attribute)]
macro_rules! test { ($nm:ident,
#[$a:meta],
$i:item) => (mod $nm { #[$a] $i }); }

View file

@ -18,6 +18,8 @@
// These are all fairly trivial cases: unused variables or direct
// drops of substructure.
#![feature(rustc_attrs)]
pub struct D { d: isize }
impl Drop for D { fn drop(&mut self) { } }

View file

@ -18,6 +18,8 @@
// These are checking that enums are tracked; note that their output
// paths include "downcasts" of the path to a particular enum.
#![feature(rustc_attrs)]
use self::Lonely::{Zero, One, Two};
pub struct D { d: isize }

View file

@ -18,6 +18,8 @@
// This checks the handling of `_` within variants, especially when mixed
// with bindings.
#![feature(rustc_attrs)]
use self::Lonely::{Zero, One, Two};
pub struct D { d: isize }

View file

@ -19,6 +19,8 @@
// early draft of the code did not properly traverse up through all of
// the parents of the leaf fragment.)
#![feature(rustc_attrs)]
pub struct D { d: isize }
impl Drop for D { fn drop(&mut self) { } }

View file

@ -17,6 +17,8 @@
// This is the first test that checks moving into local variables.
#![feature(rustc_attrs)]
pub struct D { d: isize }
impl Drop for D { fn drop(&mut self) { } }

View file

@ -18,6 +18,8 @@
// Test that moving into a field (i.e. overwriting it) fragments the
// receiver.
#![feature(rustc_attrs)]
use std::mem::drop;
pub struct Pair<X,Y> { x: X, y: Y }

View file

@ -19,6 +19,8 @@
// both moving out of the structure (i.e. reading `*p.x`) and writing
// into the container (i.e. writing `*p.x`).
#![feature(rustc_attrs)]
pub struct D { d: isize }
impl Drop for D { fn drop(&mut self) { } }

View file

@ -22,6 +22,8 @@
// also that in this case we cannot do a move out of `&T`, so we only
// test writing `*p.x` here.
#![feature(rustc_attrs)]
pub struct D { d: isize }
impl Drop for D { fn drop(&mut self) { } }

View file

@ -14,6 +14,8 @@
// Note also that the `test_move_array_then_overwrite` tests represent
// cases that we probably should make illegal.
#![feature(rustc_attrs)]
pub struct D { d: isize }
impl Drop for D { fn drop(&mut self) { } }

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_attrs)]
#[rustc_error]
fn main() {
//~^ ERROR compilation successful

View file

@ -7,9 +7,10 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![deny(unused_attributes)]
#![allow(dead_code, unused_imports)]
#![feature(core)]
#![feature(core, custom_attribute)]
#![foo] //~ ERROR unused attribute

View file

@ -11,6 +11,8 @@
// Test that the variance computation considers types/regions that
// appear in projections to be invariant.
#![feature(rustc_attrs)]
trait Trait<'a> {
type Type;

View file

@ -11,6 +11,8 @@
// Test that Cell is considered invariant with respect to its
// type.
#![feature(rustc_attrs)]
use std::cell::Cell;
// For better or worse, associated types are invariant, and hence we

View file

@ -11,6 +11,8 @@
// Test that we correctly infer variance for region parameters in
// various self-contained types.
#![feature(rustc_attrs)]
// Regions that just appear in normal spots are contravariant:
#[rustc_variance]

View file

@ -12,6 +12,8 @@
// case that involve multiple intricate types.
// Try enums too.
#![feature(rustc_attrs)]
#[rustc_variance]
enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]]
Test8A(extern "Rust" fn(&'a isize)),

View file

@ -14,6 +14,8 @@
//
// Issue #18262.
#![feature(rustc_attrs)]
use std::mem;
trait T { fn foo(); }

View file

@ -10,6 +10,8 @@
// error-pattern:expected item
#![feature(custom_attribute)]
#[foo = "bar"]
extern crate test;

View file

@ -10,6 +10,8 @@
// error-pattern:expected item
#![feature(custom_attribute)]
mod m {
#[foo = "bar"]
extern crate test;

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(unused_attribute)]
#![feature(custom_attribute)]
#[foo(bar)]
mod foo {

View file

@ -11,6 +11,9 @@
// Static recursion check shouldn't fail when given a foreign item (#18279)
// aux-build:check_static_recursion_foreign_helper.rs
#![feature(custom_attribute)]
extern crate check_static_recursion_foreign_helper;
extern crate libc;

View file

@ -10,6 +10,7 @@
// pp-exact - Make sure we actually print the attributes
#![allow(unused_attribute)]
#![feature(custom_attribute)]
struct cat {
name: String,

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(unused_attribute)]
#![feature(custom_attribute)]
struct cat {
name: String,

View file

@ -11,6 +11,8 @@
// These are attributes of the implicit crate. Really this just needs to parse
// for completeness since .rs files linked from .rc files support this
// notation to specify their module's attributes
#![feature(custom_attribute)]
#![allow(unused_attribute)]
#![attr1 = "val"]
#![attr2 = "val"]

View file

@ -10,6 +10,7 @@
// pp-exact - Make sure we print all the attributes
#![allow(unused_attribute)]
#![feature(custom_attribute)]
#[frobable]
trait frobable {

View file

@ -9,6 +9,7 @@
// except according to those terms.
// pp-exact - Make sure we actually print the attributes
#![feature(custom_attribute)]
enum crew_of_enterprise_d {