about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2021-03-06 21:33:02 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2021-03-06 23:03:19 +0300
commit5dad6c25751f577c53bd36d09f033e1c245d0806 (patch)
tree5a5269785f864cdd6f1742f9cfcd5e0444e6427e
parent069e612e73f3fabb1184d9df009ea064118fffd8 (diff)
downloadrust-5dad6c25751f577c53bd36d09f033e1c245d0806.tar.gz
rust-5dad6c25751f577c53bd36d09f033e1c245d0806.zip
Implement built-in attribute macro `#[cfg_eval]`
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs29
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/core/src/macros/mod.rs12
-rw-r--r--library/core/src/prelude/v1.rs9
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/prelude/v1.rs9
-rw-r--r--src/test/ui/proc-macro/cfg-eval-fail.rs9
-rw-r--r--src/test/ui/proc-macro/cfg-eval-fail.stderr20
-rw-r--r--src/test/ui/proc-macro/cfg-eval.rs32
-rw-r--r--src/test/ui/proc-macro/cfg-eval.stdout135
11 files changed, 259 insertions, 0 deletions
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
new file mode 100644
index 00000000000..805f9d0634c
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -0,0 +1,29 @@
+use crate::util::check_builtin_macro_attribute;
+
+use rustc_ast::{self as ast, AstLike};
+use rustc_expand::base::{Annotatable, ExtCtxt};
+use rustc_expand::config::StripUnconfigured;
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+
+pub fn expand(
+    ecx: &mut ExtCtxt<'_>,
+    _span: Span,
+    meta_item: &ast::MetaItem,
+    item: Annotatable,
+) -> Vec<Annotatable> {
+    check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
+
+    let mut visitor =
+        StripUnconfigured { sess: ecx.sess, features: ecx.ecfg.features, modified: false };
+    let mut item = visitor.fully_configure(item);
+    if visitor.modified {
+        // Erase the tokens if cfg-stripping modified the item
+        // This will cause us to synthesize fake tokens
+        // when `nt_to_tokenstream` is called on this item.
+        if let Some(tokens) = item.tokens_mut() {
+            *tokens = None;
+        }
+    }
+    vec![item]
+}
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 9a3c914337c..1017b23e567 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -24,6 +24,7 @@ mod asm;
 mod assert;
 mod cfg;
 mod cfg_accessible;
+mod cfg_eval;
 mod compile_error;
 mod concat;
 mod concat_idents;
@@ -89,6 +90,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
     register_attr! {
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
+        cfg_eval: cfg_eval::expand,
         derive: derive::Expander,
         global_allocator: global_allocator::expand,
         test: test::expand_test,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9663760cba1..507eb1e1cbe 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -344,6 +344,7 @@ symbols! {
         cfg_attr,
         cfg_attr_multi,
         cfg_doctest,
+        cfg_eval,
         cfg_panic,
         cfg_sanitize,
         cfg_target_feature,
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 3e70ba81d49..28fed9b8a14 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1452,6 +1452,18 @@ pub(crate) mod builtin {
         /* compiler built-in */
     }
 
+    /// Expands all `#[cfg]` and `#[cfg_attr]` attributes in the code fragment it's applied to.
+    #[cfg(not(bootstrap))]
+    #[unstable(
+        feature = "cfg_eval",
+        issue = "82679",
+        reason = "`cfg_eval` is a recently implemented feature"
+    )]
+    #[rustc_builtin_macro]
+    pub macro cfg_eval($($tt:tt)*) {
+        /* compiler built-in */
+    }
+
     /// Unstable implementation detail of the `rustc` compiler, do not use.
     #[rustc_builtin_macro]
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index a1fbd8dec75..5e8a8d252a2 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -81,3 +81,12 @@ pub use crate::macros::builtin::derive;
 )]
 #[doc(no_inline)]
 pub use crate::macros::builtin::cfg_accessible;
+
+#[cfg(not(bootstrap))]
+#[unstable(
+    feature = "cfg_eval",
+    issue = "82679",
+    reason = "`cfg_eval` is a recently implemented feature"
+)]
+#[doc(no_inline)]
+pub use crate::macros::builtin::cfg_eval;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 72b86338d2c..acdf7550fe7 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -234,6 +234,7 @@
 #![feature(box_syntax)]
 #![feature(c_variadic)]
 #![feature(cfg_accessible)]
+#![cfg_attr(not(bootstrap), feature(cfg_eval))]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_thread_local)]
 #![feature(char_error_internals)]
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index ef9aec54a4c..7181dc6e710 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -67,6 +67,15 @@ pub use core::prelude::v1::derive;
 #[doc(hidden)]
 pub use core::prelude::v1::cfg_accessible;
 
+#[cfg(not(bootstrap))]
+#[unstable(
+    feature = "cfg_eval",
+    issue = "82679",
+    reason = "`cfg_eval` is a recently implemented feature"
+)]
+#[doc(hidden)]
+pub use core::prelude::v1::cfg_eval;
+
 // The file so far is equivalent to src/libcore/prelude/v1.rs,
 // and below to src/liballoc/prelude.rs.
 // Those files are duplicated rather than using glob imports
diff --git a/src/test/ui/proc-macro/cfg-eval-fail.rs b/src/test/ui/proc-macro/cfg-eval-fail.rs
new file mode 100644
index 00000000000..379491f3126
--- /dev/null
+++ b/src/test/ui/proc-macro/cfg-eval-fail.rs
@@ -0,0 +1,9 @@
+#![feature(cfg_eval)]
+#![feature(stmt_expr_attributes)]
+
+fn main() {
+    let _ = #[cfg_eval] #[cfg(FALSE)] 0;
+    //~^ ERROR removing an expression is not supported in this position
+    //~| ERROR removing an expression is not supported in this position
+    //~| ERROR removing an expression is not supported in this position
+}
diff --git a/src/test/ui/proc-macro/cfg-eval-fail.stderr b/src/test/ui/proc-macro/cfg-eval-fail.stderr
new file mode 100644
index 00000000000..010ac006b0b
--- /dev/null
+++ b/src/test/ui/proc-macro/cfg-eval-fail.stderr
@@ -0,0 +1,20 @@
+error: removing an expression is not supported in this position
+  --> $DIR/cfg-eval-fail.rs:5:25
+   |
+LL |     let _ = #[cfg_eval] #[cfg(FALSE)] 0;
+   |                         ^^^^^^^^^^^^^
+
+error: removing an expression is not supported in this position
+  --> $DIR/cfg-eval-fail.rs:5:25
+   |
+LL |     let _ = #[cfg_eval] #[cfg(FALSE)] 0;
+   |                         ^^^^^^^^^^^^^
+
+error: removing an expression is not supported in this position
+  --> $DIR/cfg-eval-fail.rs:5:25
+   |
+LL |     let _ = #[cfg_eval] #[cfg(FALSE)] 0;
+   |                         ^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/proc-macro/cfg-eval.rs b/src/test/ui/proc-macro/cfg-eval.rs
new file mode 100644
index 00000000000..ea397df5452
--- /dev/null
+++ b/src/test/ui/proc-macro/cfg-eval.rs
@@ -0,0 +1,32 @@
+// check-pass
+// compile-flags: -Z span-debug
+// aux-build:test-macros.rs
+
+#![feature(cfg_eval)]
+#![feature(proc_macro_hygiene)]
+#![feature(stmt_expr_attributes)]
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+#[cfg_eval]
+#[print_attr]
+struct S1 {
+    #[cfg(FALSE)]
+    field_false: u8,
+    #[cfg(all(/*true*/))]
+    #[cfg_attr(FALSE, unknown_attr)]
+    #[cfg_attr(all(/*true*/), allow())]
+    field_true: u8,
+}
+
+#[cfg_eval]
+#[cfg(FALSE)]
+struct S2 {}
+
+fn main() {
+    let _ = #[cfg_eval] #[print_attr](#[cfg(FALSE)] 0, #[cfg(all(/*true*/))] 1);
+}
diff --git a/src/test/ui/proc-macro/cfg-eval.stdout b/src/test/ui/proc-macro/cfg-eval.stdout
new file mode 100644
index 00000000000..b98e8961bfe
--- /dev/null
+++ b/src/test/ui/proc-macro/cfg-eval.stdout
@@ -0,0 +1,135 @@
+PRINT-ATTR INPUT (DISPLAY): struct S1 { #[cfg(all())] #[allow()] field_true : u8, }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "struct",
+        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+    },
+    Ident {
+        ident: "S1",
+        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Punct {
+                ch: '#',
+                spacing: Alone,
+                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "cfg",
+                        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "all",
+                                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                            },
+                            Group {
+                                delimiter: Parenthesis,
+                                stream: TokenStream [],
+                                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                            },
+                        ],
+                        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                    },
+                ],
+                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+            },
+            Punct {
+                ch: '#',
+                spacing: Alone,
+                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "allow",
+                        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [],
+                        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                    },
+                ],
+                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+            },
+            Ident {
+                ident: "field_true",
+                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+            },
+            Ident {
+                ident: "u8",
+                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+            },
+        ],
+        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+    },
+]
+PRINT-ATTR INPUT (DISPLAY): (#[cfg(all())] 1,)
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Punct {
+                ch: '#',
+                spacing: Alone,
+                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "cfg",
+                        span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "all",
+                                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                            },
+                            Group {
+                                delimiter: Parenthesis,
+                                stream: TokenStream [],
+                                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                            },
+                        ],
+                        span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                    },
+                ],
+                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+            },
+            Literal {
+                kind: Integer,
+                symbol: "1",
+                suffix: None,
+                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+            },
+        ],
+        span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+    },
+]