Skip to content

Commit

Permalink
Auto merge of #44528 - tmnilsson:attr_proc_macro_cfg_process, r=jseyf…
Browse files Browse the repository at this point in the history
…ried

Apply attr proc macros before cfg processing

Fixes #39336.
r? @jseyfried
  • Loading branch information
bors committed Sep 28, 2017
2 parents 3c96d40 0f97b6b commit 46ef620
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 14 deletions.
39 changes: 25 additions & 14 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 308,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
err.emit();
}

let item = item
let item = self.fully_configure(item)
.map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs });
let item_with_markers =
add_derived_markers(&mut self.cx, item.span(), &traits, item.clone());
Expand Down Expand Up @@ -400,6 400,27 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
result
}

fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
let mut cfg = StripUnconfigured {
should_test: self.cx.ecfg.should_test,
sess: self.cx.parse_sess,
features: self.cx.ecfg.features,
};
// Since the item itself has already been configured by the InvocationCollector,
// we know that fold result vector will contain exactly one element
match item {
Annotatable::Item(item) => {
Annotatable::Item(cfg.fold_item(item).pop().unwrap())
}
Annotatable::TraitItem(item) => {
Annotatable::TraitItem(item.map(|item| cfg.fold_trait_item(item).pop().unwrap()))
}
Annotatable::ImplItem(item) => {
Annotatable::ImplItem(item.map(|item| cfg.fold_impl_item(item).pop().unwrap()))
}
}
}

fn expand_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
let result = match invoc.kind {
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
Expand Down Expand Up @@ -740,15 761,6 @@ struct InvocationCollector<'a, 'b: 'a> {
monotonic: bool,
}

macro_rules! fully_configure {
($this:ident, $node:ident, $noop_fold:ident) => {
match $noop_fold($node, &mut $this.cfg).pop() {
Some(node) => node,
None => return SmallVector::new(),
}
}
}

impl<'a, 'b> InvocationCollector<'a, 'b> {
fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion {
let mark = Mark::fresh(self.cx.current_expansion.mark);
Expand Down Expand Up @@ -900,7 912,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {

let (attr, traits, mut item) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
let item = Annotatable::Item(fully_configure!(self, item, noop_fold_item));
let item = Annotatable::Item(item);
return self.collect_attr(attr, traits, item, ExpansionKind::Items).make_items();
}

Expand Down Expand Up @@ -974,8 986,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {

let (attr, traits, item) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
let item =
Annotatable::TraitItem(P(fully_configure!(self, item, noop_fold_trait_item)));
let item = Annotatable::TraitItem(P(item));
return self.collect_attr(attr, traits, item, ExpansionKind::TraitItems)
.make_trait_items()
}
Expand All @@ -995,7 1006,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {

let (attr, traits, item) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
let item = Annotatable::ImplItem(P(fully_configure!(self, item, noop_fold_impl_item)));
let item = Annotatable::ImplItem(P(item));
return self.collect_attr(attr, traits, item, ExpansionKind::ImplItems)
.make_impl_items();
}
Expand Down
39 changes: 39 additions & 0 deletions src/test/run-pass-fulldeps/proc-macro/attr-cfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 1,39 @@
// Copyright 2016 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.

// aux-build:attr-cfg.rs
// ignore-stage1
// revisions: foo bar

#![feature(proc_macro)]

extern crate attr_cfg;
use attr_cfg::attr_cfg;

#[attr_cfg]
fn outer() -> u8 {
#[cfg(foo)]
fn inner() -> u8 { 1 }

#[cfg(bar)]
fn inner() -> u8 { 2 }

inner()
}

#[cfg(foo)]
fn main() {
assert_eq!(outer(), 1);
}

#[cfg(bar)]
fn main() {
assert_eq!(outer(), 2);
}
32 changes: 32 additions & 0 deletions src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-cfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 1,32 @@
// Copyright 2016 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.

// no-prefer-dynamic
#![feature(proc_macro)]
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro_attribute]
pub fn attr_cfg(args: TokenStream, input: TokenStream) -> TokenStream {
let input_str = input.to_string();

assert_eq!(input_str, "fn outer() -> u8 {
#[cfg(foo)]
fn inner() -> u8 { 1 }
#[cfg(bar)]
fn inner() -> u8 { 2 }
inner()
}");

input
}
23 changes: 23 additions & 0 deletions src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-attr-cfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 1,23 @@
// Copyright 2016 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.

// no-prefer-dynamic
#![feature(proc_macro)]
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro_derive(Foo, attributes(foo))]
pub fn derive(input: TokenStream) -> TokenStream {
assert!(!input.to_string().contains("#[cfg(any())]"));
"".parse().unwrap()
}
27 changes: 27 additions & 0 deletions src/test/run-pass-fulldeps/proc-macro/derive-attr-cfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 1,27 @@
// Copyright 2016 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.

// aux-build:derive-attr-cfg.rs
// ignore-stage1

#![feature(proc_macro)]

extern crate derive_attr_cfg;
use derive_attr_cfg::Foo;

#[derive(Foo)]
#[foo]
struct S {
#[cfg(any())]
x: i32
}

fn main() {
}

0 comments on commit 46ef620

Please sign in to comment.