Skip to content

Commit

Permalink
Auto merge of #33706 - jseyfried:refactor_cfg, r=nrc
Browse files Browse the repository at this point in the history
Perform `cfg` attribute processing during macro expansion and fix bugs

This PR refactors `cfg` attribute processing and fixes bugs. More specifically:
 - It merges gated feature checking for stmt/expr attributes, `cfg_attr` processing, and `cfg` processing into a single fold.
  - This allows feature gated `cfg` variables to be used in `cfg_attr` on unconfigured items. All other feature gated attributes can already be used on unconfigured items.
 - It performs `cfg` attribute processing during macro expansion instead of after expansion so that macro-expanded items are configured the same as ordinary items. In particular, to match their non-expanded counterparts,
  - macro-expanded unconfigured macro invocations are no longer expanded,
  - macro-expanded unconfigured macro definitions are no longer usable, and
  - feature gated `cfg` variables on macro-expanded macro definitions/invocations are now errors.

This is a [breaking-change]. For example, the following would break:
```rust
macro_rules! m {
    () => {
        #[cfg(attr)]
        macro_rules! foo { () => {} }
        foo!(); // This will be an error

        macro_rules! bar { () => { fn f() {} } }
        #[cfg(attr)] bar!(); // This will no longer be expanded ...
        fn g() { f(); } // ... so that `f` will be unresolved.

        #[cfg(target_thread_local)] // This will be a gated feature error
        macro_rules! baz { () => {} }
    }
}

m!();
```

r? @nrc
  • Loading branch information
bors committed May 28, 2016
2 parents 7bddce6 + 53ab137 commit 8b012ed
Show file tree
Hide file tree
Showing 8 changed files with 355 additions and 613 deletions.
9 changes: 0 additions & 9 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,16 +720,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
ret
});

// JBC: make CFG processing part of expansion to avoid this problem:

// strip again, in case expansion added anything with a #[cfg].
krate = sess.track_errors(|| {
let krate = time(time_passes, "configuration 2", || {
syntax::config::strip_unconfigured_items(sess.diagnostic(),
krate,
&mut feature_gated_cfgs)
});

time(time_passes, "gated configuration checking", || {
let features = sess.features.borrow();
feature_gated_cfgs.sort();
Expand Down
25 changes: 5 additions & 20 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub use self::UnsafeSource::*;
pub use self::ViewPath_::*;
pub use self::PathParameters::*;

use attr::ThinAttributes;
use attr::{ThinAttributes, HasAttrs};
use codemap::{mk_sp, respan, Span, Spanned, DUMMY_SP, ExpnId};
use abi::Abi;
use errors;
Expand Down Expand Up @@ -831,13 +831,7 @@ impl StmtKind {
}

pub fn attrs(&self) -> &[Attribute] {
match *self {
StmtKind::Decl(ref d, _) => d.attrs(),
StmtKind::Expr(ref e, _) |
StmtKind::Semi(ref e, _) => e.attrs(),
StmtKind::Mac(_, _, Some(ref b)) => b,
StmtKind::Mac(_, _, None) => &[],
}
HasAttrs::attrs(self)
}
}

Expand Down Expand Up @@ -870,10 +864,7 @@ pub struct Local {

impl Local {
pub fn attrs(&self) -> &[Attribute] {
match self.attrs {
Some(ref b) => b,
None => &[],
}
HasAttrs::attrs(self)
}
}

Expand All @@ -889,10 +880,7 @@ pub enum DeclKind {

impl Decl {
pub fn attrs(&self) -> &[Attribute] {
match self.node {
DeclKind::Local(ref l) => l.attrs(),
DeclKind::Item(ref i) => i.attrs(),
}
HasAttrs::attrs(self)
}
}

Expand Down Expand Up @@ -937,10 +925,7 @@ pub struct Expr {

impl Expr {
pub fn attrs(&self) -> &[Attribute] {
match self.attrs {
Some(ref b) => b,
None => &[],
}
HasAttrs::attrs(self)
}
}

Expand Down
141 changes: 84 additions & 57 deletions src/libsyntax/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -884,82 +884,109 @@ impl AttributesExt for Vec<Attribute> {
}
}

pub trait HasAttrs: Sized {
fn attrs(&self) -> &[ast::Attribute];
fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self;
}

/// A cheap way to add Attributes to an AST node.
pub trait WithAttrs {
// FIXME: Could be extended to anything IntoIter<Item=Attribute>
fn with_attrs(self, attrs: ThinAttributes) -> Self;
}

impl WithAttrs for P<Expr> {
impl<T: HasAttrs> WithAttrs for T {
fn with_attrs(self, attrs: ThinAttributes) -> Self {
self.map(|mut e| {
e.attrs.update(|a| a.append(attrs));
e
self.map_attrs(|mut orig_attrs| {
orig_attrs.extend(attrs.into_attr_vec());
orig_attrs
})
}
}

impl WithAttrs for P<Item> {
fn with_attrs(self, attrs: ThinAttributes) -> Self {
self.map(|Item { ident, attrs: mut ats, id, node, vis, span }| {
ats.extend(attrs.into_attr_vec());
Item {
ident: ident,
attrs: ats,
id: id,
node: node,
vis: vis,
span: span,
}
})
impl HasAttrs for Vec<Attribute> {
fn attrs(&self) -> &[Attribute] {
&self
}
fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
f(self)
}
}

impl WithAttrs for P<Local> {
fn with_attrs(self, attrs: ThinAttributes) -> Self {
self.map(|Local { pat, ty, init, id, span, attrs: mut ats }| {
ats.update(|a| a.append(attrs));
Local {
pat: pat,
ty: ty,
init: init,
id: id,
span: span,
attrs: ats,
}
})
impl HasAttrs for ThinAttributes {
fn attrs(&self) -> &[Attribute] {
self.as_attr_slice()
}
fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
self.map_thin_attrs(f)
}
}

impl WithAttrs for P<Decl> {
fn with_attrs(self, attrs: ThinAttributes) -> Self {
self.map(|Spanned { span, node }| {
Spanned {
span: span,
node: match node {
DeclKind::Local(local) => DeclKind::Local(local.with_attrs(attrs)),
DeclKind::Item(item) => DeclKind::Item(item.with_attrs(attrs)),
}
}
})
impl<T: HasAttrs + 'static> HasAttrs for P<T> {
fn attrs(&self) -> &[Attribute] {
(**self).attrs()
}
fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
self.map(|t| t.map_attrs(f))
}
}

impl WithAttrs for P<Stmt> {
fn with_attrs(self, attrs: ThinAttributes) -> Self {
self.map(|Spanned { span, node }| {
Spanned {
span: span,
node: match node {
StmtKind::Decl(decl, id) => StmtKind::Decl(decl.with_attrs(attrs), id),
StmtKind::Expr(expr, id) => StmtKind::Expr(expr.with_attrs(attrs), id),
StmtKind::Semi(expr, id) => StmtKind::Semi(expr.with_attrs(attrs), id),
StmtKind::Mac(mac, style, mut ats) => {
ats.update(|a| a.append(attrs));
StmtKind::Mac(mac, style, ats)
}
},
}
})
impl HasAttrs for DeclKind {
fn attrs(&self) -> &[Attribute] {
match *self {
DeclKind::Local(ref local) => local.attrs(),
DeclKind::Item(ref item) => item.attrs(),
}
}

fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
match self {
DeclKind::Local(local) => DeclKind::Local(local.map_attrs(f)),
DeclKind::Item(item) => DeclKind::Item(item.map_attrs(f)),
}
}
}

impl HasAttrs for StmtKind {
fn attrs(&self) -> &[Attribute] {
match *self {
StmtKind::Decl(ref decl, _) => decl.attrs(),
StmtKind::Expr(ref expr, _) | StmtKind::Semi(ref expr, _) => expr.attrs(),
StmtKind::Mac(_, _, ref attrs) => attrs.attrs(),
}
}

fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
match self {
StmtKind::Decl(decl, id) => StmtKind::Decl(decl.map_attrs(f), id),
StmtKind::Expr(expr, id) => StmtKind::Expr(expr.map_attrs(f), id),
StmtKind::Semi(expr, id) => StmtKind::Semi(expr.map_attrs(f), id),
StmtKind::Mac(mac, style, attrs) =>
StmtKind::Mac(mac, style, attrs.map_attrs(f)),
}
}
}

macro_rules! derive_has_attrs_from_field {
($($ty:path),*) => { derive_has_attrs_from_field!($($ty: .attrs),*); };
($($ty:path : $(.$field:ident)*),*) => { $(
impl HasAttrs for $ty {
fn attrs(&self) -> &[Attribute] {
self $(.$field)* .attrs()
}

fn map_attrs<F>(mut self, f: F) -> Self
where F: FnOnce(Vec<Attribute>) -> Vec<Attribute>,
{
self $(.$field)* = self $(.$field)* .map_attrs(f);
self
}
}
)* }
}

derive_has_attrs_from_field! {
Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm
}

derive_has_attrs_from_field! { Decl: .node, Stmt: .node, ast::Variant: .node.attrs }
25 changes: 0 additions & 25 deletions src/libsyntax/codemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1258,31 +1258,6 @@ impl CodeMap {
return a;
}

/// Check if the backtrace `subtrace` contains `suptrace` as a prefix.
pub fn more_specific_trace(&self,
mut subtrace: ExpnId,
suptrace: ExpnId)
-> bool {
loop {
if subtrace == suptrace {
return true;
}

let stop = self.with_expn_info(subtrace, |opt_expn_info| {
if let Some(expn_info) = opt_expn_info {
subtrace = expn_info.call_site.expn_id;
false
} else {
true
}
});

if stop {
return false;
}
}
}

pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId {
let mut expansions = self.expansions.borrow_mut();
expansions.push(expn_info);
Expand Down
Loading

0 comments on commit 8b012ed

Please sign in to comment.