Skip to content

Commit

Permalink
Check gated attributes before and after macro expansion
Browse files Browse the repository at this point in the history
This is important because attributes can affect expansion.
  • Loading branch information
Keegan McAllister committed Mar 7, 2015
1 parent 63ee3fe commit e60e6f0
Show file tree
Hide file tree
Showing 11 changed files with 79 additions and 43 deletions.
75 changes: 38 additions & 37 deletions src/libsyntax/feature_gate.rs
Expand Up @@ -196,6 +196,7 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
("no_mangle", Normal),
("no_link", Normal),
("derive", Normal),
("deriving", Normal), // deprecation err in expansion
("should_fail", Normal),
("should_panic", Normal),
("ignore", Normal),
Expand Down Expand Up @@ -235,6 +236,9 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
"the `#[rustc_move_fragments]` attribute \
is an experimental feature")),

("allow_internal_unstable", Gated("allow_internal_unstable",
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),

// FIXME: #14408 whitelist docs since rustdoc looks at them
("doc", Whitelisted),

Expand Down Expand Up @@ -369,6 +373,33 @@ impl<'a> Context<'a> {
fn has_feature(&self, feature: &str) -> bool {
self.features.iter().any(|&n| n == feature)
}

fn check_attribute(&self, attr: &ast::Attribute) {
debug!("check_attribute(attr = {:?})", attr);
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);
}
debug!("check_attribute: {:?} is known, {:?}", name, ty);
return;
}
}
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());
}
}
}

pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, explain: &str) {
Expand Down Expand Up @@ -436,10 +467,7 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
}

fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
if attr.name() == "allow_internal_unstable" {
self.context.gate_feature("allow_internal_unstable", attr.span,
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)
}
self.context.check_attribute(attr);
}
}

Expand All @@ -456,6 +484,12 @@ impl<'a> PostExpansionVisitor<'a> {
}

impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
fn visit_attribute(&mut self, attr: &ast::Attribute) {
if !self.context.cm.span_allows_unstable(attr.span) {
self.context.check_attribute(attr);
}
}

fn visit_name(&mut self, sp: Span, name: ast::Name) {
if !token::get_name(name).is_ascii() {
self.gate_feature("non_ascii_idents", sp,
Expand Down Expand Up @@ -556,12 +590,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
}

fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
if attr::contains_name(&i.attrs, "linkage") {
self.gate_feature("linkage", i.span,
"the `linkage` attribute is experimental \
and not portable across platforms")
}

let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
"link_name") {
Some(val) => val.starts_with("llvm."),
Expand Down Expand Up @@ -636,33 +664,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
visit::walk_expr(self, e);
}

fn visit_attribute(&mut self, attr: &ast::Attribute) {
debug!("visit_attribute(attr = {:?})", attr);
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);
}
debug!("visit_attribute: {:?} is known, {:?}", name, ty);
return;
}
}
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());
}
}

fn visit_pat(&mut self, pattern: &ast::Pat) {
match pattern.node {
ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
Expand Down
2 changes: 2 additions & 0 deletions src/test/compile-fail/deprecated-phase.rs
Expand Up @@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(custom_attribute)]

#[phase(blah)]
//~^ ERROR #[phase] is deprecated
extern crate foo;
Expand Down
Expand Up @@ -8,9 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[lang="foo"] //~ ERROR language items are subject to change
trait Foo {}

extern "rust-intrinsic" { //~ ERROR intrinsics are subject to change
fn bar();
}
Expand All @@ -20,4 +17,3 @@ extern "rust-intrinsic" fn baz() { //~ ERROR intrinsics are subject to change

fn main() {
}

15 changes: 15 additions & 0 deletions src/test/compile-fail/feature-gate-lang-items.rs
@@ -0,0 +1,15 @@
// 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.

#[lang="foo"] //~ ERROR language items are subject to change
trait Foo {}

fn main() {
}
1 change: 0 additions & 1 deletion src/test/compile-fail/linkage1.rs
Expand Up @@ -11,5 +11,4 @@
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
}
1 change: 1 addition & 0 deletions src/test/compile-fail/malformed-plugin-1.rs
Expand Up @@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(plugin)]
#![plugin] //~ ERROR malformed plugin attribute

fn main() {}
1 change: 1 addition & 0 deletions src/test/compile-fail/malformed-plugin-2.rs
Expand Up @@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(plugin)]
#![plugin="bleh"] //~ ERROR malformed plugin attribute

fn main() {}
1 change: 1 addition & 0 deletions src/test/compile-fail/malformed-plugin-3.rs
Expand Up @@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(plugin)]
#![plugin(foo="bleh")] //~ ERROR malformed plugin attribute

fn main() {}
2 changes: 2 additions & 0 deletions src/test/compile-fail/plugin-extern-crate-attr-deprecated.rs
Expand Up @@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(plugin)]

#[plugin] //~ ERROR #[plugin] on `extern crate` is deprecated
//~^ HELP use a crate attribute instead, i.e. #![plugin(std)]
extern crate std;
Expand Down
18 changes: 18 additions & 0 deletions src/test/compile-fail/reserved-attr-on-macro.rs
@@ -0,0 +1,18 @@
// Copyright 2015 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.

#[rustc_attribute_should_be_reserved] //~ ERROR attributes with the prefix `rustc_` are reserved
macro_rules! foo {
() => (());
}

fn main() {
foo!();
}
2 changes: 1 addition & 1 deletion src/test/run-pass-fulldeps/macro-crate.rs
Expand Up @@ -11,7 +11,7 @@
// aux-build:macro_crate_test.rs
// ignore-stage1

#![feature(plugin)]
#![feature(plugin, custom_attribute)]
#![plugin(macro_crate_test)]

#[macro_use] #[no_link]
Expand Down

0 comments on commit e60e6f0

Please sign in to comment.