Implement built-in attribute macro #[cfg_eval]

This commit is contained in:
Vadim Petrochenkov 2021-03-06 21:33:02 +03:00
parent 069e612e73
commit 5dad6c2575
11 changed files with 259 additions and 0 deletions

View file

@ -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]
}

View file

@ -24,6 +24,7 @@
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,

View file

@ -344,6 +344,7 @@
cfg_attr,
cfg_attr_multi,
cfg_doctest,
cfg_eval,
cfg_panic,
cfg_sanitize,
cfg_target_feature,

View file

@ -1452,6 +1452,18 @@ macro_rules! trace_macros {
/* 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")]

View file

@ -81,3 +81,12 @@
)]
#[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;

View file

@ -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)]

View file

@ -67,6 +67,15 @@
#[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

View file

@ -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
}

View file

@ -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

View file

@ -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);
}

View file

@ -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),
},
]