Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e60e6f0

Browse files
author
Keegan McAllister
committedMar 7, 2015
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)
Please sign in to comment.