Skip to content

Commit e60e6f0

Browse files
author
Keegan McAllister
committed
Check gated attributes before and after macro expansion
This is important because attributes can affect expansion.
1 parent 63ee3fe commit e60e6f0

11 files changed

+79
-43
lines changed

src/libsyntax/feature_gate.rs

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
196196
("no_mangle", Normal),
197197
("no_link", Normal),
198198
("derive", Normal),
199+
("deriving", Normal), // deprecation err in expansion
199200
("should_fail", Normal),
200201
("should_panic", Normal),
201202
("ignore", Normal),
@@ -235,6 +236,9 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
235236
"the `#[rustc_move_fragments]` attribute \
236237
is an experimental feature")),
237238

239+
("allow_internal_unstable", Gated("allow_internal_unstable",
240+
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
241+
238242
// FIXME: #14408 whitelist docs since rustdoc looks at them
239243
("doc", Whitelisted),
240244

@@ -369,6 +373,33 @@ impl<'a> Context<'a> {
369373
fn has_feature(&self, feature: &str) -> bool {
370374
self.features.iter().any(|&n| n == feature)
371375
}
376+
377+
fn check_attribute(&self, attr: &ast::Attribute) {
378+
debug!("check_attribute(attr = {:?})", attr);
379+
let name = &*attr.name();
380+
for &(n, ty) in KNOWN_ATTRIBUTES {
381+
if n == name {
382+
if let Gated(gate, desc) = ty {
383+
self.gate_feature(gate, attr.span, desc);
384+
}
385+
debug!("check_attribute: {:?} is known, {:?}", name, ty);
386+
return;
387+
}
388+
}
389+
if name.starts_with("rustc_") {
390+
self.gate_feature("rustc_attrs", attr.span,
391+
"unless otherwise specified, attributes \
392+
with the prefix `rustc_` \
393+
are reserved for internal compiler diagnostics");
394+
} else {
395+
self.gate_feature("custom_attribute", attr.span,
396+
format!("The attribute `{}` is currently \
397+
unknown to the the compiler and \
398+
may have meaning \
399+
added to it in the future",
400+
name).as_slice());
401+
}
402+
}
372403
}
373404

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

438469
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
439-
if attr.name() == "allow_internal_unstable" {
440-
self.context.gate_feature("allow_internal_unstable", attr.span,
441-
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)
442-
}
470+
self.context.check_attribute(attr);
443471
}
444472
}
445473

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

458486
impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
487+
fn visit_attribute(&mut self, attr: &ast::Attribute) {
488+
if !self.context.cm.span_allows_unstable(attr.span) {
489+
self.context.check_attribute(attr);
490+
}
491+
}
492+
459493
fn visit_name(&mut self, sp: Span, name: ast::Name) {
460494
if !token::get_name(name).is_ascii() {
461495
self.gate_feature("non_ascii_idents", sp,
@@ -556,12 +590,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
556590
}
557591

558592
fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
559-
if attr::contains_name(&i.attrs, "linkage") {
560-
self.gate_feature("linkage", i.span,
561-
"the `linkage` attribute is experimental \
562-
and not portable across platforms")
563-
}
564-
565593
let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
566594
"link_name") {
567595
Some(val) => val.starts_with("llvm."),
@@ -636,33 +664,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
636664
visit::walk_expr(self, e);
637665
}
638666

639-
fn visit_attribute(&mut self, attr: &ast::Attribute) {
640-
debug!("visit_attribute(attr = {:?})", attr);
641-
let name = &*attr.name();
642-
for &(n, ty) in KNOWN_ATTRIBUTES {
643-
if n == name {
644-
if let Gated(gate, desc) = ty {
645-
self.gate_feature(gate, attr.span, desc);
646-
}
647-
debug!("visit_attribute: {:?} is known, {:?}", name, ty);
648-
return;
649-
}
650-
}
651-
if name.starts_with("rustc_") {
652-
self.gate_feature("rustc_attrs", attr.span,
653-
"unless otherwise specified, attributes \
654-
with the prefix `rustc_` \
655-
are reserved for internal compiler diagnostics");
656-
} else {
657-
self.gate_feature("custom_attribute", attr.span,
658-
format!("The attribute `{}` is currently \
659-
unknown to the the compiler and \
660-
may have meaning \
661-
added to it in the future",
662-
name).as_slice());
663-
}
664-
}
665-
666667
fn visit_pat(&mut self, pattern: &ast::Pat) {
667668
match pattern.node {
668669
ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {

src/test/compile-fail/deprecated-phase.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(custom_attribute)]
12+
1113
#[phase(blah)]
1214
//~^ ERROR #[phase] is deprecated
1315
extern crate foo;

src/test/compile-fail/feature-gate-intrinsics-and-lang-items.rs renamed to src/test/compile-fail/feature-gate-intrinsics.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#[lang="foo"] //~ ERROR language items are subject to change
12-
trait Foo {}
13-
1411
extern "rust-intrinsic" { //~ ERROR intrinsics are subject to change
1512
fn bar();
1613
}
@@ -20,4 +17,3 @@ extern "rust-intrinsic" fn baz() { //~ ERROR intrinsics are subject to change
2017

2118
fn main() {
2219
}
23-
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2014 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+
#[lang="foo"] //~ ERROR language items are subject to change
12+
trait Foo {}
13+
14+
fn main() {
15+
}

src/test/compile-fail/linkage1.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@
1111
extern {
1212
#[linkage = "extern_weak"] static foo: isize;
1313
//~^ ERROR: the `linkage` attribute is experimental and not portable
14-
//~^^ ERROR: the `linkage` attribute is experimental and not portable
1514
}

src/test/compile-fail/malformed-plugin-1.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(plugin)]
1112
#![plugin] //~ ERROR malformed plugin attribute
1213

1314
fn main() {}

src/test/compile-fail/malformed-plugin-2.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

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

1314
fn main() {}

src/test/compile-fail/malformed-plugin-3.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

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

1314
fn main() {}

src/test/compile-fail/plugin-extern-crate-attr-deprecated.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(plugin)]
12+
1113
#[plugin] //~ ERROR #[plugin] on `extern crate` is deprecated
1214
//~^ HELP use a crate attribute instead, i.e. #![plugin(std)]
1315
extern crate std;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
#[rustc_attribute_should_be_reserved] //~ ERROR attributes with the prefix `rustc_` are reserved
12+
macro_rules! foo {
13+
() => (());
14+
}
15+
16+
fn main() {
17+
foo!();
18+
}

src/test/run-pass-fulldeps/macro-crate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// aux-build:macro_crate_test.rs
1212
// ignore-stage1
1313

14-
#![feature(plugin)]
14+
#![feature(plugin, custom_attribute)]
1515
#![plugin(macro_crate_test)]
1616

1717
#[macro_use] #[no_link]

0 commit comments

Comments
 (0)