Skip to content

Commit f498e4e

Browse files
committed
Auto merge of #51587 - mark-i-m:at_most_once_rep_2018, r=alexcrichton
2018 edition `?` Kleene operator This is my first attempt at implementing the migration lint + 2018 behavior as discussed in #48075 r? @nikomatsakis
2 parents 6a3db03 + 10ee0f6 commit f498e4e

32 files changed

+769
-303
lines changed

src/doc/unstable-book/src/language-features/macro-at-most-once-rep.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
# `macro_at_most_once_rep`
22

3-
The tracking issue for this feature is: TODO(mark-i-m)
3+
NOTE: This feature is only available in the 2018 Edition.
4+
5+
The tracking issue for this feature is: #48075
46

57
With this feature gate enabled, one can use `?` as a Kleene operator meaning "0
68
or 1 repetitions" in a macro definition. Previously only `+` and `*` were allowed.
79

810
For example:
911

10-
```rust
12+
```rust,ignore
1113
#![feature(macro_at_most_once_rep)]
1214
1315
macro_rules! foo {

src/librustc/lint/builtin.rs

+10
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,15 @@ declare_lint! {
331331
via the module system"
332332
}
333333

334+
/// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`.
335+
pub mod parser {
336+
declare_lint! {
337+
pub QUESTION_MARK_MACRO_SEP,
338+
Allow,
339+
"detects the use of `?` as a macro separator"
340+
}
341+
}
342+
334343
/// Does nothing as a lint pass, but registers some `Lint`s
335344
/// which are used by other parts of the compiler.
336345
#[derive(Copy, Clone)]
@@ -389,6 +398,7 @@ impl LintPass for HardwiredLints {
389398
WHERE_CLAUSES_OBJECT_SAFETY,
390399
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
391400
MACRO_USE_EXTERN_CRATE,
401+
parser::QUESTION_MARK_MACRO_SEP,
392402
)
393403
}
394404
}

src/librustc/lint/mod.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ use hir::def_id::{CrateNum, LOCAL_CRATE};
3838
use hir::intravisit;
3939
use hir;
4040
use lint::builtin::BuiltinLintDiagnostics;
41+
use lint::builtin::parser::QUESTION_MARK_MACRO_SEP;
4142
use session::{Session, DiagnosticMessageId};
4243
use std::{hash, ptr};
4344
use syntax::ast;
4445
use syntax::codemap::{MultiSpan, ExpnFormat};
46+
use syntax::early_buffered_lints::BufferedEarlyLintId;
4547
use syntax::edition::Edition;
4648
use syntax::symbol::Symbol;
4749
use syntax::visit as ast_visit;
@@ -86,6 +88,13 @@ pub struct Lint {
8688
}
8789

8890
impl Lint {
91+
/// Returns the `rust::lint::Lint` for a `syntax::early_buffered_lints::BufferedEarlyLintId`.
92+
pub fn from_parser_lint_id(lint_id: BufferedEarlyLintId) -> &'static Self {
93+
match lint_id {
94+
BufferedEarlyLintId::QuestionMarkMacroSep => QUESTION_MARK_MACRO_SEP,
95+
}
96+
}
97+
8998
/// Get the lint's name, with ASCII letters converted to lowercase.
9099
pub fn name_lower(&self) -> String {
91100
self.name.to_ascii_lowercase()
@@ -118,7 +127,7 @@ macro_rules! declare_lint {
118127
};
119128
);
120129
($vis: vis $NAME: ident, $Level: ident, $desc: expr,
121-
$lint_edition: expr => $edition_level: ident $(,)?
130+
$lint_edition: expr => $edition_level: ident
122131
) => (
123132
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
124133
name: stringify!($NAME),
@@ -133,7 +142,8 @@ macro_rules! declare_lint {
133142
/// Declare a static `LintArray` and return it as an expression.
134143
#[macro_export]
135144
macro_rules! lint_array {
136-
($( $lint:expr ),* $(,)?) => {{
145+
($( $lint:expr ),* ,) => { lint_array!( $($lint),* ) };
146+
($( $lint:expr ),*) => {{
137147
vec![$($lint),*]
138148
}}
139149
}

src/librustc/macros.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ macro_rules! __impl_stable_hash_field {
7171

7272
#[macro_export]
7373
macro_rules! impl_stable_hash_for {
74-
(enum $enum_name:path { $( $variant:ident $( ( $($field:ident $(-> $delegate:tt)?),* ) )* ),* $(,)? }) => {
74+
// FIXME(mark-i-m): Some of these should be `?` rather than `*`. See the git blame and change
75+
// them back when `?` is supported again.
76+
(enum $enum_name:path { $( $variant:ident $( ( $($field:ident $(-> $delegate:tt)*),* ) )* ),* $(,)* }) => {
7577
impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $enum_name {
7678
#[inline]
7779
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
@@ -83,14 +85,15 @@ macro_rules! impl_stable_hash_for {
8385
match *self {
8486
$(
8587
$variant $( ( $(ref $field),* ) )* => {
86-
$($( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)?) );*)*
88+
$($( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)*) );*)*
8789
}
8890
)*
8991
}
9092
}
9193
}
9294
};
93-
(struct $struct_name:path { $($field:ident $(-> $delegate:tt)?),* $(,)? }) => {
95+
// FIXME(mark-i-m): same here.
96+
(struct $struct_name:path { $($field:ident $(-> $delegate:tt)*),* $(,)* }) => {
9497
impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name {
9598
#[inline]
9699
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
@@ -100,11 +103,12 @@ macro_rules! impl_stable_hash_for {
100103
$(ref $field),*
101104
} = *self;
102105

103-
$( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)?) );*
106+
$( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)*) );*
104107
}
105108
}
106109
};
107-
(tuple_struct $struct_name:path { $($field:ident $(-> $delegate:tt)?),* $(,)? }) => {
110+
// FIXME(mark-i-m): same here.
111+
(tuple_struct $struct_name:path { $($field:ident $(-> $delegate:tt)*),* $(,)* }) => {
108112
impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name {
109113
#[inline]
110114
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
@@ -114,7 +118,7 @@ macro_rules! impl_stable_hash_for {
114118
$(ref $field),*
115119
) = *self;
116120

117-
$( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)?) );*
121+
$( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)*) );*
118122
}
119123
}
120124
};

src/librustc_driver/driver.rs

+10
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use std::path::{Path, PathBuf};
5252
use rustc_data_structures::sync::{self, Lrc, Lock};
5353
use std::sync::mpsc;
5454
use syntax::{self, ast, attr, diagnostics, visit};
55+
use syntax::early_buffered_lints::BufferedEarlyLint;
5556
use syntax::ext::base::ExtCtxt;
5657
use syntax::fold::Folder;
5758
use syntax::parse::{self, PResult};
@@ -1066,6 +1067,15 @@ where
10661067
)
10671068
});
10681069

1070+
// Add all buffered lints from the `ParseSess` to the `Session`.
1071+
sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
1072+
info!("{} parse sess buffered_lints", buffered_lints.len());
1073+
for BufferedEarlyLint{id, span, msg, lint_id} in buffered_lints.drain(..) {
1074+
let lint = lint::Lint::from_parser_lint_id(lint_id);
1075+
sess.buffer_lint(lint, id, span, &msg);
1076+
}
1077+
});
1078+
10691079
// Done with macro expansion!
10701080

10711081
after_expand(&krate)?;

src/librustc_lint/builtin.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ declare_lint! {
617617
pub ANONYMOUS_PARAMETERS,
618618
Allow,
619619
"detects anonymous parameters",
620-
Edition::Edition2018 => Warn,
620+
Edition::Edition2018 => Warn
621621
}
622622

623623
/// Checks for use of anonymous parameters (RFC 1685)
@@ -1706,7 +1706,7 @@ impl LintPass for SoftLints {
17061706
UNIONS_WITH_DROP_FIELDS,
17071707
UNREACHABLE_PUB,
17081708
TYPE_ALIAS_BOUNDS,
1709-
TRIVIAL_BOUNDS,
1709+
TRIVIAL_BOUNDS
17101710
)
17111711
}
17121712
}

src/librustc_lint/lib.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@ extern crate syntax_pos;
4444

4545
use rustc::lint;
4646
use rustc::lint::{LateContext, LateLintPass, LintPass, LintArray};
47-
use rustc::lint::builtin::{BARE_TRAIT_OBJECTS, ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
48-
ELIDED_LIFETIMES_IN_PATHS};
49-
use rustc::lint::builtin::MACRO_USE_EXTERN_CRATE;
47+
use rustc::lint::builtin::{
48+
BARE_TRAIT_OBJECTS,
49+
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
50+
MACRO_USE_EXTERN_CRATE,
51+
ELIDED_LIFETIMES_IN_PATHS,
52+
parser::QUESTION_MARK_MACRO_SEP
53+
};
5054
use rustc::session;
5155
use rustc::util;
5256
use rustc::hir;
@@ -321,6 +325,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
321325
reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
322326
edition: None,
323327
},
328+
FutureIncompatibleInfo {
329+
id: LintId::of(QUESTION_MARK_MACRO_SEP),
330+
reference: "issue #48075 <https://github.com/rust-lang/rust/issues/48075>",
331+
edition: Some(Edition::Edition2018),
332+
}
324333
]);
325334

326335
// Register renamed and removed lints

src/libsyntax/early_buffered_lints.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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+
//! Allows the buffering of lints for later.
12+
//!
13+
//! Since we cannot have a dependency on `librustc`, we implement some types here that are somewhat
14+
//! redundant. Later, these types can be converted to types for use by the rest of the compiler.
15+
16+
use syntax::ast::NodeId;
17+
use syntax_pos::MultiSpan;
18+
19+
/// Since we cannot import `LintId`s from `rustc::lint`, we define some Ids here which can later be
20+
/// passed to `rustc::lint::Lint::from_parser_lint_id` to get a `rustc::lint::Lint`.
21+
pub enum BufferedEarlyLintId {
22+
/// Usage of `?` as a macro separator is deprecated.
23+
QuestionMarkMacroSep,
24+
}
25+
26+
/// Stores buffered lint info which can later be passed to `librustc`.
27+
pub struct BufferedEarlyLint {
28+
/// The span of code that we are linting on.
29+
pub span: MultiSpan,
30+
31+
/// The lint message.
32+
pub msg: String,
33+
34+
/// The `NodeId` of the AST node that generated the lint.
35+
pub id: NodeId,
36+
37+
/// A lint Id that can be passed to `rustc::lint::Lint::from_parser_lint_id`.
38+
pub lint_id: BufferedEarlyLintId,
39+
}

src/libsyntax/ext/expand.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ macro_rules! ast_fragments {
4444
(
4545
$($Kind:ident($AstTy:ty) {
4646
$kind_name:expr;
47-
$(one fn $fold_ast:ident; fn $visit_ast:ident;)?
48-
$(many fn $fold_ast_elt:ident; fn $visit_ast_elt:ident;)?
47+
// FIXME: HACK: this should be `$(one ...)?` and `$(many ...)?` but `?` macro
48+
// repetition was removed from 2015 edition in #51587 because of ambiguities.
49+
$(one fn $fold_ast:ident; fn $visit_ast:ident;)*
50+
$(many fn $fold_ast_elt:ident; fn $visit_ast_elt:ident;)*
4951
fn $make_ast:ident;
5052
})*
5153
) => {
@@ -100,22 +102,22 @@ macro_rules! ast_fragments {
100102
AstFragment::OptExpr(expr) =>
101103
AstFragment::OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))),
102104
$($(AstFragment::$Kind(ast) =>
103-
AstFragment::$Kind(folder.$fold_ast(ast)),)?)*
105+
AstFragment::$Kind(folder.$fold_ast(ast)),)*)*
104106
$($(AstFragment::$Kind(ast) =>
105107
AstFragment::$Kind(ast.into_iter()
106108
.flat_map(|ast| folder.$fold_ast_elt(ast))
107-
.collect()),)?)*
109+
.collect()),)*)*
108110
}
109111
}
110112

111113
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
112114
match *self {
113115
AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
114116
AstFragment::OptExpr(None) => {}
115-
$($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)*
117+
$($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)*)*
116118
$($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] {
117119
visitor.$visit_ast_elt(ast_elt);
118-
})?)*
120+
})*)*
119121
}
120122
}
121123
}
@@ -126,10 +128,10 @@ macro_rules! ast_fragments {
126128
}
127129
$($(fn $fold_ast(&mut self, ast: $AstTy) -> $AstTy {
128130
self.expand_fragment(AstFragment::$Kind(ast)).$make_ast()
129-
})?)*
131+
})*)*
130132
$($(fn $fold_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy {
131133
self.expand_fragment(AstFragment::$Kind(SmallVector::one(ast_elt))).$make_ast()
132-
})?)*
134+
})*)*
133135
}
134136

135137
impl<'a> MacResult for ::ext::tt::macro_rules::ParserAnyMacro<'a> {

src/libsyntax/ext/tt/macro_rules.rs

+21-4
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,17 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition:
240240
s.iter().map(|m| {
241241
if let MatchedNonterminal(ref nt) = *m {
242242
if let NtTT(ref tt) = **nt {
243-
let tt = quoted::parse(tt.clone().into(), true, sess, features, &def.attrs)
244-
.pop().unwrap();
243+
let tt = quoted::parse(
244+
tt.clone().into(),
245+
true,
246+
sess,
247+
features,
248+
&def.attrs,
249+
edition,
250+
def.id,
251+
)
252+
.pop()
253+
.unwrap();
245254
valid &= check_lhs_nt_follows(sess, features, &def.attrs, &tt);
246255
return tt;
247256
}
@@ -257,8 +266,16 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition:
257266
s.iter().map(|m| {
258267
if let MatchedNonterminal(ref nt) = *m {
259268
if let NtTT(ref tt) = **nt {
260-
return quoted::parse(tt.clone().into(), false, sess, features, &def.attrs)
261-
.pop().unwrap();
269+
return quoted::parse(
270+
tt.clone().into(),
271+
false,
272+
sess,
273+
features,
274+
&def.attrs,
275+
edition,
276+
def.id,
277+
).pop()
278+
.unwrap();
262279
}
263280
}
264281
sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")

0 commit comments

Comments
 (0)