mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-12 23:13:15 +00:00
Rollup merge of #22383 - pnkfelix:pass-features-along-during-expansion, r=huonw
Pass features along during expansion Use the set of passed features to detect uses of feature-gated macros without the corresponding feature enabled. Fix #22234. ---- Also, the framework this add (passing along a reference to the features in the expansion context) is a necessary precursor for landing a properly feature-gated desugaring-based overloaded-`box` and placement-`in` (#22181). ---- This is fixing a bug, but since there might be code out there that is unknowingly taking advantage of that bug, I feel obligated to mark this as a: [breaking-change]
This commit is contained in:
commit
020e4e4ad9
@ -471,9 +471,10 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||
new_path.extend(env::split_paths(&_old_path));
|
||||
env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
|
||||
}
|
||||
let features = sess.features.borrow();
|
||||
let cfg = syntax::ext::expand::ExpansionConfig {
|
||||
crate_name: crate_name.to_string(),
|
||||
enable_quotes: sess.features.borrow().quote,
|
||||
features: Some(&features),
|
||||
recursion_limit: sess.recursion_limit.get(),
|
||||
};
|
||||
let ret = syntax::ext::expand::expand_crate(&sess.parse_sess,
|
||||
|
@ -18,6 +18,7 @@ use codemap;
|
||||
use codemap::Span;
|
||||
use ext::base;
|
||||
use ext::base::*;
|
||||
use feature_gate;
|
||||
use parse::token::InternedString;
|
||||
use parse::token;
|
||||
use ptr::P;
|
||||
@ -48,6 +49,12 @@ static OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
|
||||
|
||||
pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
||||
-> Box<base::MacResult+'cx> {
|
||||
if !cx.ecfg.enable_asm() {
|
||||
feature_gate::emit_feature_err(
|
||||
&cx.parse_sess.span_diagnostic, "asm", sp, feature_gate::EXPLAIN_ASM);
|
||||
return DummyResult::expr(sp);
|
||||
}
|
||||
|
||||
let mut p = cx.new_parser_from_tts(tts);
|
||||
let mut asm = InternedString::new("");
|
||||
let mut asm_str_style = None;
|
||||
|
@ -439,7 +439,8 @@ impl BlockInfo {
|
||||
|
||||
/// The base map of methods for expanding syntax extension
|
||||
/// AST nodes into full ASTs
|
||||
fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv {
|
||||
fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
|
||||
-> SyntaxEnv {
|
||||
// utility function to simplify creating NormalTT syntax extensions
|
||||
fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
|
||||
NormalTT(box f, None)
|
||||
@ -470,7 +471,7 @@ fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv {
|
||||
syntax_expanders.insert(intern("deriving"),
|
||||
Decorator(box ext::deriving::expand_deprecated_deriving));
|
||||
|
||||
if ecfg.enable_quotes {
|
||||
if ecfg.enable_quotes() {
|
||||
// Quasi-quoting expanders
|
||||
syntax_expanders.insert(intern("quote_tokens"),
|
||||
builtin_normal_expander(
|
||||
@ -541,7 +542,7 @@ pub struct ExtCtxt<'a> {
|
||||
pub parse_sess: &'a parse::ParseSess,
|
||||
pub cfg: ast::CrateConfig,
|
||||
pub backtrace: ExpnId,
|
||||
pub ecfg: expand::ExpansionConfig,
|
||||
pub ecfg: expand::ExpansionConfig<'a>,
|
||||
pub use_std: bool,
|
||||
|
||||
pub mod_path: Vec<ast::Ident> ,
|
||||
@ -554,7 +555,7 @@ pub struct ExtCtxt<'a> {
|
||||
|
||||
impl<'a> ExtCtxt<'a> {
|
||||
pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
|
||||
ecfg: expand::ExpansionConfig) -> ExtCtxt<'a> {
|
||||
ecfg: expand::ExpansionConfig<'a>) -> ExtCtxt<'a> {
|
||||
let env = initial_syntax_expander_table(&ecfg);
|
||||
ExtCtxt {
|
||||
parse_sess: parse_sess,
|
||||
|
@ -12,12 +12,21 @@ use ast;
|
||||
use codemap::Span;
|
||||
use ext::base::*;
|
||||
use ext::base;
|
||||
use feature_gate;
|
||||
use parse::token;
|
||||
use parse::token::{str_to_ident};
|
||||
use ptr::P;
|
||||
|
||||
pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
||||
-> Box<base::MacResult+'cx> {
|
||||
if !cx.ecfg.enable_concat_idents() {
|
||||
feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
|
||||
"concat_idents",
|
||||
sp,
|
||||
feature_gate::EXPLAIN_CONCAT_IDENTS);
|
||||
return base::DummyResult::expr(sp);
|
||||
}
|
||||
|
||||
let mut res_str = String::new();
|
||||
for (i, e) in tts.iter().enumerate() {
|
||||
if i & 1 == 1 {
|
||||
|
@ -22,6 +22,7 @@ use attr::AttrMetaMethods;
|
||||
use codemap;
|
||||
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
|
||||
use ext::base::*;
|
||||
use feature_gate::{Features};
|
||||
use fold;
|
||||
use fold::*;
|
||||
use parse;
|
||||
@ -1408,28 +1409,63 @@ fn new_span(cx: &ExtCtxt, sp: Span) -> Span {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ExpansionConfig {
|
||||
pub struct ExpansionConfig<'feat> {
|
||||
pub crate_name: String,
|
||||
pub enable_quotes: bool,
|
||||
pub features: Option<&'feat Features>,
|
||||
pub recursion_limit: usize,
|
||||
}
|
||||
|
||||
impl ExpansionConfig {
|
||||
pub fn default(crate_name: String) -> ExpansionConfig {
|
||||
impl<'feat> ExpansionConfig<'feat> {
|
||||
pub fn default(crate_name: String) -> ExpansionConfig<'static> {
|
||||
ExpansionConfig {
|
||||
crate_name: crate_name,
|
||||
enable_quotes: false,
|
||||
features: None,
|
||||
recursion_limit: 64,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_quotes(&self) -> bool {
|
||||
match self.features {
|
||||
Some(&Features { allow_quote: true, .. }) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_asm(&self) -> bool {
|
||||
match self.features {
|
||||
Some(&Features { allow_asm: true, .. }) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_log_syntax(&self) -> bool {
|
||||
match self.features {
|
||||
Some(&Features { allow_log_syntax: true, .. }) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_concat_idents(&self) -> bool {
|
||||
match self.features {
|
||||
Some(&Features { allow_concat_idents: true, .. }) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_trace_macros(&self) -> bool {
|
||||
match self.features {
|
||||
Some(&Features { allow_trace_macros: true, .. }) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expand_crate(parse_sess: &parse::ParseSess,
|
||||
cfg: ExpansionConfig,
|
||||
// these are the macros being imported to this crate:
|
||||
imported_macros: Vec<ast::MacroDef>,
|
||||
user_exts: Vec<NamedSyntaxExtension>,
|
||||
c: Crate) -> Crate {
|
||||
pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess,
|
||||
cfg: ExpansionConfig<'feat>,
|
||||
// these are the macros being imported to this crate:
|
||||
imported_macros: Vec<ast::MacroDef>,
|
||||
user_exts: Vec<NamedSyntaxExtension>,
|
||||
c: Crate) -> Crate {
|
||||
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
|
||||
cx.use_std = std_inject::use_std(&c);
|
||||
|
||||
@ -1598,7 +1634,7 @@ mod test {
|
||||
// these following tests are quite fragile, in that they don't test what
|
||||
// *kind* of failure occurs.
|
||||
|
||||
fn test_ecfg() -> ExpansionConfig {
|
||||
fn test_ecfg() -> ExpansionConfig<'static> {
|
||||
ExpansionConfig::default("test".to_string())
|
||||
}
|
||||
|
||||
|
@ -11,12 +11,20 @@
|
||||
use ast;
|
||||
use codemap;
|
||||
use ext::base;
|
||||
use feature_gate;
|
||||
use print;
|
||||
|
||||
pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt,
|
||||
sp: codemap::Span,
|
||||
tts: &[ast::TokenTree])
|
||||
-> Box<base::MacResult+'cx> {
|
||||
if !cx.ecfg.enable_log_syntax() {
|
||||
feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
|
||||
"log_syntax",
|
||||
sp,
|
||||
feature_gate::EXPLAIN_LOG_SYNTAX);
|
||||
return base::DummyResult::any(sp);
|
||||
}
|
||||
|
||||
cx.print_backtrace();
|
||||
|
||||
|
@ -12,6 +12,7 @@ use ast;
|
||||
use codemap::Span;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::base;
|
||||
use feature_gate;
|
||||
use parse::token::keywords;
|
||||
|
||||
|
||||
@ -19,6 +20,15 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt,
|
||||
sp: Span,
|
||||
tt: &[ast::TokenTree])
|
||||
-> Box<base::MacResult+'static> {
|
||||
if !cx.ecfg.enable_trace_macros() {
|
||||
feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
|
||||
"trace_macros",
|
||||
sp,
|
||||
feature_gate::EXPLAIN_TRACE_MACROS);
|
||||
return base::DummyResult::any(sp);
|
||||
}
|
||||
|
||||
|
||||
match tt {
|
||||
[ast::TtToken(_, ref tok)] if tok.is_keyword(keywords::True) => {
|
||||
cx.set_trace_macros(true);
|
||||
|
@ -295,7 +295,11 @@ pub struct Features {
|
||||
pub unboxed_closures: bool,
|
||||
pub rustc_diagnostic_macros: bool,
|
||||
pub visible_private_types: bool,
|
||||
pub quote: bool,
|
||||
pub allow_quote: bool,
|
||||
pub allow_asm: bool,
|
||||
pub allow_log_syntax: bool,
|
||||
pub allow_concat_idents: bool,
|
||||
pub allow_trace_macros: bool,
|
||||
pub old_orphan_check: bool,
|
||||
pub simd_ffi: bool,
|
||||
pub unmarked_api: bool,
|
||||
@ -311,7 +315,11 @@ impl Features {
|
||||
unboxed_closures: false,
|
||||
rustc_diagnostic_macros: false,
|
||||
visible_private_types: false,
|
||||
quote: false,
|
||||
allow_quote: false,
|
||||
allow_asm: false,
|
||||
allow_log_syntax: false,
|
||||
allow_concat_idents: false,
|
||||
allow_trace_macros: false,
|
||||
old_orphan_check: false,
|
||||
simd_ffi: false,
|
||||
unmarked_api: false,
|
||||
@ -360,6 +368,18 @@ pub fn emit_feature_warn(diag: &SpanHandler, feature: &str, span: Span, explain:
|
||||
}
|
||||
}
|
||||
|
||||
pub const EXPLAIN_ASM: &'static str =
|
||||
"inline assembly is not stable enough for use and is subject to change";
|
||||
|
||||
pub const EXPLAIN_LOG_SYNTAX: &'static str =
|
||||
"`log_syntax!` is not stable enough for use and is subject to change";
|
||||
|
||||
pub const EXPLAIN_CONCAT_IDENTS: &'static str =
|
||||
"`concat_idents` is not stable enough for use and is subject to change";
|
||||
|
||||
pub const EXPLAIN_TRACE_MACROS: &'static str =
|
||||
"`trace_macros` is not stable enough for use and is subject to change";
|
||||
|
||||
struct MacroVisitor<'a> {
|
||||
context: &'a Context<'a>
|
||||
}
|
||||
@ -369,24 +389,28 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
|
||||
let ast::MacInvocTT(ref path, _, _) = mac.node;
|
||||
let id = path.segments.last().unwrap().identifier;
|
||||
|
||||
// Issue 22234: If you add a new case here, make sure to also
|
||||
// add code to catch the macro during or after expansion.
|
||||
//
|
||||
// We still keep this MacroVisitor (rather than *solely*
|
||||
// relying on catching cases during or after expansion) to
|
||||
// catch uses of these macros within conditionally-compiled
|
||||
// code, e.g. `#[cfg]`-guarded functions.
|
||||
|
||||
if id == token::str_to_ident("asm") {
|
||||
self.context.gate_feature("asm", path.span, "inline assembly is not \
|
||||
stable enough for use and is subject to change");
|
||||
self.context.gate_feature("asm", path.span, EXPLAIN_ASM);
|
||||
}
|
||||
|
||||
else if id == token::str_to_ident("log_syntax") {
|
||||
self.context.gate_feature("log_syntax", path.span, "`log_syntax!` is not \
|
||||
stable enough for use and is subject to change");
|
||||
self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX);
|
||||
}
|
||||
|
||||
else if id == token::str_to_ident("trace_macros") {
|
||||
self.context.gate_feature("trace_macros", path.span, "`trace_macros` is not \
|
||||
stable enough for use and is subject to change");
|
||||
self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS);
|
||||
}
|
||||
|
||||
else if id == token::str_to_ident("concat_idents") {
|
||||
self.context.gate_feature("concat_idents", path.span, "`concat_idents` is not \
|
||||
stable enough for use and is subject to change");
|
||||
self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -710,11 +734,18 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
|
||||
|
||||
check(&mut cx, krate);
|
||||
|
||||
// FIXME (pnkfelix): Before adding the 99th entry below, change it
|
||||
// to a single-pass (instead of N calls to `.has_feature`).
|
||||
|
||||
Features {
|
||||
unboxed_closures: cx.has_feature("unboxed_closures"),
|
||||
rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
|
||||
visible_private_types: cx.has_feature("visible_private_types"),
|
||||
quote: cx.has_feature("quote"),
|
||||
allow_quote: cx.has_feature("quote"),
|
||||
allow_asm: cx.has_feature("asm"),
|
||||
allow_log_syntax: cx.has_feature("log_syntax"),
|
||||
allow_concat_idents: cx.has_feature("concat_idents"),
|
||||
allow_trace_macros: cx.has_feature("trace_macros"),
|
||||
old_orphan_check: cx.has_feature("old_orphan_check"),
|
||||
simd_ffi: cx.has_feature("simd_ffi"),
|
||||
unmarked_api: cx.has_feature("unmarked_api"),
|
||||
|
15
src/test/compile-fail/asm-gated2.rs
Normal file
15
src/test/compile-fail/asm-gated2.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
println!("{}", asm!("")); //~ ERROR inline assembly is not stable
|
||||
}
|
||||
}
|
19
src/test/compile-fail/concat_idents-gate.rs
Normal file
19
src/test/compile-fail/concat_idents-gate.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
const XY_1: i32 = 10;
|
||||
|
||||
fn main() {
|
||||
const XY_2: i32 = 20;
|
||||
let a = concat_idents!(X, Y_1); //~ ERROR `concat_idents` is not stable
|
||||
let b = concat_idents!(X, Y_2); //~ ERROR `concat_idents` is not stable
|
||||
assert_eq!(a, 10);
|
||||
assert_eq!(b, 20);
|
||||
}
|
17
src/test/compile-fail/concat_idents-gate2.rs
Normal file
17
src/test/compile-fail/concat_idents-gate2.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
const XY_1: i32 = 10;
|
||||
|
||||
fn main() {
|
||||
const XY_2: i32 = 20;
|
||||
assert_eq!(10, concat_idents!(X, Y_1)); //~ ERROR `concat_idents` is not stable
|
||||
assert_eq!(20, concat_idents!(X, Y_2)); //~ ERROR `concat_idents` is not stable
|
||||
}
|
13
src/test/compile-fail/log-syntax-gate2.rs
Normal file
13
src/test/compile-fail/log-syntax-gate2.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
fn main() {
|
||||
println!("{}", log_syntax!()); //~ ERROR `log_syntax!` is not stable
|
||||
}
|
30
src/test/compile-fail/trace_macros-gate.rs
Normal file
30
src/test/compile-fail/trace_macros-gate.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// Test that the trace_macros feature gate is on.
|
||||
|
||||
fn main() {
|
||||
trace_macros!(); //~ ERROR `trace_macros` is not stable
|
||||
trace_macros!(1); //~ ERROR `trace_macros` is not stable
|
||||
trace_macros!(ident); //~ ERROR `trace_macros` is not stable
|
||||
trace_macros!(for); //~ ERROR `trace_macros` is not stable
|
||||
trace_macros!(true,); //~ ERROR `trace_macros` is not stable
|
||||
trace_macros!(false 1); //~ ERROR `trace_macros` is not stable
|
||||
|
||||
// Errors are signalled early for the above, before expansion.
|
||||
// See trace_macros-gate2 and trace_macros-gate3. for examples
|
||||
// of the below being caught.
|
||||
|
||||
macro_rules! expando {
|
||||
($x: ident) => { trace_macros!($x) }
|
||||
}
|
||||
|
||||
expando!(true);
|
||||
}
|
20
src/test/compile-fail/trace_macros-gate2.rs
Normal file
20
src/test/compile-fail/trace_macros-gate2.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// Test that the trace_macros feature gate is on.
|
||||
|
||||
fn main() {
|
||||
// (Infrastructure does not attempt to detect uses in macro definitions.)
|
||||
macro_rules! expando {
|
||||
($x: ident) => { trace_macros!($x) }
|
||||
}
|
||||
|
||||
expando!(true); //~ ERROR `trace_macros` is not stable
|
||||
}
|
20
src/test/compile-fail/trace_macros-gate3.rs
Normal file
20
src/test/compile-fail/trace_macros-gate3.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// Test that the trace_macros feature gate is on.
|
||||
|
||||
pub fn main() {
|
||||
println!("arg: {}", trace_macros!()); //~ ERROR `trace_macros` is not stable
|
||||
println!("arg: {}", trace_macros!(1)); //~ ERROR `trace_macros` is not stable
|
||||
println!("arg: {}", trace_macros!(ident)); //~ ERROR `trace_macros` is not stable
|
||||
println!("arg: {}", trace_macros!(for)); //~ ERROR `trace_macros` is not stable
|
||||
println!("arg: {}", trace_macros!(true,)); //~ ERROR `trace_macros` is not stable
|
||||
println!("arg: {}", trace_macros!(false 1)); //~ ERROR `trace_macros` is not stable
|
||||
}
|
Loading…
Reference in New Issue
Block a user