Skip to content

Commit 3c15405

Browse files
committed
Add feature gate + tests
1 parent 4897a05 commit 3c15405

File tree

5 files changed

+106
-10
lines changed

5 files changed

+106
-10
lines changed

src/libsyntax/ext/tt/macro_rules.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,8 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
237237
s.iter().map(|m| {
238238
if let MatchedNonterminal(ref nt) = *m {
239239
if let NtTT(ref tt) = **nt {
240-
let tt = quoted::parse(tt.clone().into(), true, sess).pop().unwrap();
240+
let tt = quoted::parse(tt.clone().into(), true, sess, features, &def.attrs)
241+
.pop().unwrap();
241242
valid &= check_lhs_nt_follows(sess, features, &def.attrs, &tt);
242243
return tt;
243244
}
@@ -253,7 +254,8 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
253254
s.iter().map(|m| {
254255
if let MatchedNonterminal(ref nt) = *m {
255256
if let NtTT(ref tt) = **nt {
256-
return quoted::parse(tt.clone().into(), false, sess).pop().unwrap();
257+
return quoted::parse(tt.clone().into(), false, sess, features, &def.attrs)
258+
.pop().unwrap();
257259
}
258260
}
259261
sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")

src/libsyntax/ext/tt/quoted.rs

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use ast;
11+
use {ast, attr};
1212
use ext::tt::macro_parser;
13+
use feature_gate::{self, emit_feature_err, Features, GateIssue};
1314
use parse::{token, ParseSess};
1415
use print::pprust;
1516
use symbol::keywords;
1617
use syntax_pos::{BytePos, Span, DUMMY_SP};
1718
use tokenstream;
1819

20+
use std::cell::RefCell;
1921
use std::iter::Peekable;
2022
use std::rc::Rc;
2123

@@ -179,6 +181,8 @@ pub fn parse(
179181
input: tokenstream::TokenStream,
180182
expect_matchers: bool,
181183
sess: &ParseSess,
184+
features: &RefCell<Features>,
185+
attrs: &[ast::Attribute],
182186
) -> Vec<TokenTree> {
183187
// Will contain the final collection of `self::TokenTree`
184188
let mut result = Vec::new();
@@ -187,10 +191,9 @@ pub fn parse(
187191
// additional trees if need be.
188192
let mut trees = input.trees().peekable();
189193
while let Some(tree) = trees.next() {
190-
let tree = parse_tree(tree, &mut trees, expect_matchers, sess);
191-
192194
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
193195
// parse out the matcher (i.e. in `$id:ident` this would parse the `:` and `ident`).
196+
let tree = parse_tree(tree, &mut trees, expect_matchers, sess, features, attrs);
194197
match tree {
195198
TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
196199
let span = match trees.next() {
@@ -244,6 +247,8 @@ fn parse_tree<I>(
244247
trees: &mut Peekable<I>,
245248
expect_matchers: bool,
246249
sess: &ParseSess,
250+
features: &RefCell<Features>,
251+
attrs: &[ast::Attribute],
247252
) -> TokenTree
248253
where
249254
I: Iterator<Item = tokenstream::TokenTree>,
@@ -262,9 +267,9 @@ where
262267
sess.span_diagnostic.span_err(span, &msg);
263268
}
264269
// Parse the contents of the sequence itself
265-
let sequence = parse(delimited.tts.into(), expect_matchers, sess);
270+
let sequence = parse(delimited.tts.into(), expect_matchers, sess, features, attrs);
266271
// Get the Kleene operator and optional separator
267-
let (separator, op) = parse_sep_and_kleene_op(trees, span, sess);
272+
let (separator, op) = parse_sep_and_kleene_op(trees, span, sess, features, attrs);
268273
// Count the number of captured "names" (i.e. named metavars)
269274
let name_captures = macro_parser::count_names(&sequence);
270275
TokenTree::Sequence(
@@ -317,7 +322,7 @@ where
317322
span,
318323
Rc::new(Delimited {
319324
delim: delimited.delim,
320-
tts: parse(delimited.tts.into(), expect_matchers, sess),
325+
tts: parse(delimited.tts.into(), expect_matchers, sess, features, attrs),
321326
}),
322327
),
323328
}
@@ -373,6 +378,8 @@ fn parse_sep_and_kleene_op<I>(
373378
input: &mut Peekable<I>,
374379
span: Span,
375380
sess: &ParseSess,
381+
features: &RefCell<Features>,
382+
attrs: &[ast::Attribute],
376383
) -> (Option<token::Token>, KleeneOp)
377384
where
378385
I: Iterator<Item = tokenstream::TokenTree>,
@@ -401,6 +408,21 @@ where
401408
// (N.B. We need to advance the input iterator.)
402409
match parse_kleene_op(input, span) {
403410
// #2 is a KleeneOp (this is the only valid option) :)
411+
Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => {
412+
if !features.borrow().macro_at_most_once_rep
413+
&& !attr::contains_name(attrs, "allow_internal_unstable")
414+
{
415+
let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
416+
emit_feature_err(
417+
sess,
418+
"macro_at_most_once_rep",
419+
span,
420+
GateIssue::Language,
421+
explain,
422+
);
423+
}
424+
return (Some(token::Question), op);
425+
}
404426
Ok(Ok(op)) => return (Some(token::Question), op),
405427

406428
// #2 is a random token (this is an error) :(
@@ -410,6 +432,19 @@ where
410432
Err(span) => span,
411433
}
412434
} else {
435+
if !features.borrow().macro_at_most_once_rep
436+
&& !attr::contains_name(attrs, "allow_internal_unstable")
437+
{
438+
let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
439+
emit_feature_err(
440+
sess,
441+
"macro_at_most_once_rep",
442+
span,
443+
GateIssue::Language,
444+
explain,
445+
);
446+
}
447+
413448
// #2 is a random tree and #1 is KleeneOp::ZeroOrOne
414449
return (None, op);
415450
}
@@ -418,6 +453,21 @@ where
418453
// #1 is a separator followed by #2, a KleeneOp
419454
Ok(Err((tok, span))) => match parse_kleene_op(input, span) {
420455
// #2 is a KleeneOp :D
456+
Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => {
457+
if !features.borrow().macro_at_most_once_rep
458+
&& !attr::contains_name(attrs, "allow_internal_unstable")
459+
{
460+
let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
461+
emit_feature_err(
462+
sess,
463+
"macro_at_most_once_rep",
464+
span,
465+
GateIssue::Language,
466+
explain,
467+
);
468+
}
469+
return (Some(tok), op);
470+
}
421471
Ok(Ok(op)) => return (Some(tok), op),
422472

423473
// #2 is a random token :(
@@ -431,7 +481,13 @@ where
431481
Err(span) => span,
432482
};
433483

434-
sess.span_diagnostic
435-
.span_err(span, "expected one of: `*`, `+`, or `?`");
484+
if !features.borrow().macro_at_most_once_rep
485+
&& !attr::contains_name(attrs, "allow_internal_unstable")
486+
{
487+
sess.span_diagnostic
488+
.span_err(span, "expected one of: `*`, `+`, or `?`");
489+
} else {
490+
sess.span_diagnostic.span_err(span, "expected `*` or `+`");
491+
}
436492
(None, KleeneOp::ZeroOrMore)
437493
}

src/libsyntax/feature_gate.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,11 @@ declare_features! (
452452

453453
// Allows `#[repr(transparent)]` attribute on newtype structs
454454
(active, repr_transparent, "1.25.0", Some(43036)),
455+
456+
// Use `?` as the Kleene "at most one" operator
457+
// FIXME(mark-i-m): make sure we use the correct issue number when there is
458+
// a tracking issue...
459+
(active, macro_at_most_once_rep, "1.25.0", None),
455460
);
456461

457462
declare_features! (
@@ -1250,6 +1255,9 @@ pub const EXPLAIN_PLACEMENT_IN: &'static str =
12501255
pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
12511256
"Unsized tuple coercion is not stable enough for use and is subject to change";
12521257

1258+
pub const EXPLAIN_MACRO_AT_MOST_ONCE_REP: &'static str =
1259+
"Using the `?` macro Kleene operator for \"at most one\" repetition is unstable";
1260+
12531261
struct PostExpansionVisitor<'a> {
12541262
context: &'a Context<'a>,
12551263
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that the MSP430 interrupt ABI cannot be used when msp430_interrupt
12+
// feature gate is not used.
13+
14+
macro_rules! m { ($(a)?) => {} }
15+
//~^ ERROR Using the `?` macro Kleene operator for "at most one" repetition is unstable
16+
17+
fn main() {
18+
m!();
19+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0658]: Using the `?` macro Kleene operator for "at most one" repetition is unstable
2+
--> $DIR/feature-gate-macro_at_most_once_rep.rs:14:19
3+
|
4+
14 | macro_rules! m { ($(a)?) => {} }
5+
| ^^^^^
6+
|
7+
= help: add #![feature(macro_at_most_once_rep)] to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+
11+

0 commit comments

Comments
 (0)