diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 8f2e571c21340..5412decd3b744 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -886,8 +886,20 @@ fn is_legal_fragment_specifier(sess: &ParseSess, frag_name: &str, frag_span: Span) -> bool { match frag_name { - "item" | "block" | "stmt" | "expr" | "pat" | "lifetime" | + "item" | "block" | "stmt" | "expr" | "pat" | "path" | "ty" | "ident" | "meta" | "tt" | "" => true, + "lifetime" => { + if !features.borrow().macro_lifetime_matcher + && !attr::contains_name(attrs, "allow_internal_unstable") { + let explain = feature_gate::EXPLAIN_LIFETIME_MATCHER; + emit_feature_err(sess, + "macro_lifetime_matcher", + frag_span, + GateIssue::Language, + explain); + } + true + }, "vis" => { if !features.borrow().macro_vis_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7ae360678cd50..471251b063009 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -447,6 +447,9 @@ declare_features! ( // Termination trait in main (RFC 1937) (active, termination_trait, "1.24.0", Some(43301)), + + // Allows use of the :lifetime macro fragment specifier + (active, macro_lifetime_matcher, "1.24.0", Some(46895)), ); declare_features! ( @@ -520,7 +523,7 @@ declare_features! ( (accepted, loop_break_value, "1.19.0", Some(37339)), // Permits numeric fields in struct expressions and patterns. (accepted, relaxed_adts, "1.19.0", Some(35626)), - // Coerces non capturing closures to function pointers + // Coerces non capturing closures to function pointers (accepted, closure_to_fn_coercion, "1.19.0", Some(39817)), // Allows attributes on struct literal fields. (accepted, struct_field_attributes, "1.20.0", Some(38814)), @@ -1226,6 +1229,9 @@ pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str = pub const EXPLAIN_VIS_MATCHER: &'static str = ":vis fragment specifier is experimental and subject to change"; +pub const EXPLAIN_LIFETIME_MATCHER: &'static str = + ":lifetime fragment specifier is experimental and subject to change"; + pub const EXPLAIN_PLACEMENT_IN: &'static str = "placement-in expression syntax is experimental and subject to change."; diff --git a/src/test/run-pass/macro-lifetime-used-with-bound.rs b/src/test/run-pass/macro-lifetime-used-with-bound.rs index b9e1fde6b1f3e..b0c9280b6ce44 100644 --- a/src/test/run-pass/macro-lifetime-used-with-bound.rs +++ b/src/test/run-pass/macro-lifetime-used-with-bound.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(macro_lifetime_matcher)] + macro_rules! foo { ($l:lifetime, $l2:lifetime) => { fn f<$l: $l2, $l2>(arg: &$l str, arg2: &$l2 str) -> &$l str { diff --git a/src/test/run-pass/macro-lifetime-used-with-labels.rs b/src/test/run-pass/macro-lifetime-used-with-labels.rs index d003d7dcfb620..8a2d76e17df68 100644 --- a/src/test/run-pass/macro-lifetime-used-with-labels.rs +++ b/src/test/run-pass/macro-lifetime-used-with-labels.rs @@ -9,6 +9,7 @@ // except according to those terms. #![allow(unreachable_code)] +#![feature(macro_lifetime_matcher)] macro_rules! x { ($a:lifetime) => { diff --git a/src/test/run-pass/macro-lifetime-used-with-static.rs b/src/test/run-pass/macro-lifetime-used-with-static.rs index 5c1f8683e00f6..468ee2e943657 100644 --- a/src/test/run-pass/macro-lifetime-used-with-static.rs +++ b/src/test/run-pass/macro-lifetime-used-with-static.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(macro_lifetime_matcher)] + macro_rules! foo { ($l:lifetime) => { fn f(arg: &$l str) -> &$l str { diff --git a/src/test/run-pass/macro-lifetime.rs b/src/test/run-pass/macro-lifetime.rs index ff5798ff78d62..db521ca7f103f 100644 --- a/src/test/run-pass/macro-lifetime.rs +++ b/src/test/run-pass/macro-lifetime.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(macro_lifetime_matcher)] + macro_rules! foo { ($l:lifetime) => { fn f<$l>(arg: &$l str) -> &$l str { diff --git a/src/test/ui/feature-gate-macro-lifetime-matcher.rs b/src/test/ui/feature-gate-macro-lifetime-matcher.rs new file mode 100644 index 0000000000000..0d107d283cdff --- /dev/null +++ b/src/test/ui/feature-gate-macro-lifetime-matcher.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the :lifetime macro fragment cannot be used when macro_lifetime_matcher +// feature gate is not used. + +macro_rules! m { ($lt:lifetime) => {} } +//~^ ERROR :lifetime fragment specifier is experimental and subject to change + +fn main() { + m!('a); +} diff --git a/src/test/ui/feature-gate-macro-lifetime-matcher.stderr b/src/test/ui/feature-gate-macro-lifetime-matcher.stderr new file mode 100644 index 0000000000000..e78f7684cf2be --- /dev/null +++ b/src/test/ui/feature-gate-macro-lifetime-matcher.stderr @@ -0,0 +1,10 @@ +error: :lifetime fragment specifier is experimental and subject to change (see issue #46895) + --> $DIR/feature-gate-macro-lifetime-matcher.rs:14:19 + | +14 | macro_rules! m { ($lt:lifetime) => {} } + | ^^^^^^^^^^^^ + | + = help: add #![feature(macro_lifetime_matcher)] to the crate attributes to enable + +error: aborting due to previous error +