Skip to content

Commit fc323ba

Browse files
committed
Auto merge of #53293 - petrochenkov:gramattr2, r=alexcrichton
syntax: Enforce attribute grammar in the parser Also fix feature-gating for `unrestricted_attribute_tokens` that was introduced in #53270, but was actually broken. cc #50911
2 parents 6c712b1 + 097c40c commit fc323ba

20 files changed

+128
-55
lines changed

src/libsyntax/attr/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ impl NestedMetaItemKind {
607607
}
608608

609609
impl Lit {
610-
fn tokens(&self) -> TokenStream {
610+
crate fn tokens(&self) -> TokenStream {
611611
TokenTree::Token(self.span, self.node.token()).into()
612612
}
613613
}
@@ -794,7 +794,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
794794
);
795795

796796
let start_span = parser.span;
797-
let (path, tokens) = panictry!(parser.parse_path_and_tokens());
797+
let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted());
798798
let end_span = parser.span;
799799
if parser.token != token::Eof {
800800
parse_sess.span_diagnostic

src/libsyntax/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl<'a> StripUnconfigured<'a> {
9090
let cfg = parser.parse_meta_item()?;
9191
parser.expect(&token::Comma)?;
9292
let lo = parser.span.lo();
93-
let (path, tokens) = parser.parse_path_and_tokens()?;
93+
let (path, tokens) = parser.parse_meta_item_unrestricted()?;
9494
parser.expect(&token::CloseDelim(token::Paren))?;
9595
Ok((cfg, path, tokens, parser.prev_span.with_lo(lo)))
9696
}) {

src/libsyntax/feature_gate.rs

+20-18
Original file line numberDiff line numberDiff line change
@@ -1526,27 +1526,29 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
15261526
}
15271527
}
15281528

1529-
match attr.parse_meta(self.context.parse_sess) {
1530-
Ok(meta) => {
1531-
// allow attr_literals in #[repr(align(x))] and #[repr(packed(n))]
1532-
let mut allow_attr_literal = false;
1533-
if attr.path == "repr" {
1534-
if let Some(content) = meta.meta_item_list() {
1535-
allow_attr_literal = content.iter().any(
1536-
|c| c.check_name("align") || c.check_name("packed"));
1529+
if !self.context.features.unrestricted_attribute_tokens {
1530+
// Unfortunately, `parse_meta` cannot be called speculatively because it can report
1531+
// errors by itself, so we have to call it only if the feature is disabled.
1532+
match attr.parse_meta(self.context.parse_sess) {
1533+
Ok(meta) => {
1534+
// allow attr_literals in #[repr(align(x))] and #[repr(packed(n))]
1535+
let mut allow_attr_literal = false;
1536+
if attr.path == "repr" {
1537+
if let Some(content) = meta.meta_item_list() {
1538+
allow_attr_literal = content.iter().any(
1539+
|c| c.check_name("align") || c.check_name("packed"));
1540+
}
15371541
}
1538-
}
15391542

1540-
if !allow_attr_literal && contains_novel_literal(&meta) {
1541-
gate_feature_post!(&self, attr_literals, attr.span,
1542-
"non-string literals in attributes, or string \
1543-
literals in top-level positions, are experimental");
1543+
if !allow_attr_literal && contains_novel_literal(&meta) {
1544+
gate_feature_post!(&self, attr_literals, attr.span,
1545+
"non-string literals in attributes, or string \
1546+
literals in top-level positions, are experimental");
1547+
}
1548+
}
1549+
Err(mut err) => {
1550+
err.help("try enabling `#![feature(unrestricted_attribute_tokens)]`").emit()
15441551
}
1545-
}
1546-
Err(mut err) => {
1547-
err.cancel();
1548-
gate_feature_post!(&self, unrestricted_attribute_tokens, attr.span,
1549-
"arbitrary tokens in non-macro attributes are unstable");
15501552
}
15511553
}
15521554
}

src/libsyntax/parse/attr.rs

+29-5
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ use attr;
1212
use ast;
1313
use codemap::respan;
1414
use parse::{SeqSep, PResult};
15-
use parse::token::{self, Nonterminal};
15+
use parse::token::{self, Nonterminal, DelimToken};
1616
use parse::parser::{Parser, TokenType, PathStyle};
17-
use tokenstream::TokenStream;
17+
use tokenstream::{TokenStream, TokenTree};
1818

1919
#[derive(Debug)]
2020
enum InnerAttributeParsePolicy<'a> {
@@ -116,7 +116,7 @@ impl<'a> Parser<'a> {
116116
};
117117

118118
self.expect(&token::OpenDelim(token::Bracket))?;
119-
let (path, tokens) = self.parse_path_and_tokens()?;
119+
let (path, tokens) = self.parse_meta_item_unrestricted()?;
120120
self.expect(&token::CloseDelim(token::Bracket))?;
121121
let hi = self.prev_span;
122122

@@ -138,7 +138,16 @@ impl<'a> Parser<'a> {
138138
})
139139
}
140140

141-
crate fn parse_path_and_tokens(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
141+
/// Parse an inner part of attribute - path and following tokens.
142+
/// The tokens must be either a delimited token stream, or empty token stream,
143+
/// or the "legacy" key-value form.
144+
/// PATH `(` TOKEN_STREAM `)`
145+
/// PATH `[` TOKEN_STREAM `]`
146+
/// PATH `{` TOKEN_STREAM `}`
147+
/// PATH
148+
/// PATH `=` TOKEN_TREE
149+
/// The delimiters or `=` are still put into the resulting token stream.
150+
crate fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
142151
let meta = match self.token {
143152
token::Interpolated(ref nt) => match nt.0 {
144153
Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
@@ -150,7 +159,22 @@ impl<'a> Parser<'a> {
150159
self.bump();
151160
(meta.ident, meta.node.tokens(meta.span))
152161
} else {
153-
(self.parse_path(PathStyle::Mod)?, self.parse_tokens())
162+
let path = self.parse_path(PathStyle::Mod)?;
163+
let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) ||
164+
self.check(&token::OpenDelim(DelimToken::Bracket)) ||
165+
self.check(&token::OpenDelim(DelimToken::Brace)) {
166+
self.parse_token_tree().into()
167+
} else if self.eat(&token::Eq) {
168+
let eq = TokenTree::Token(self.prev_span, token::Eq);
169+
let tree = match self.token {
170+
token::CloseDelim(_) | token::Eof => self.unexpected()?,
171+
_ => self.parse_token_tree(),
172+
};
173+
TokenStream::concat(vec![eq.into(), tree.into()])
174+
} else {
175+
TokenStream::empty()
176+
};
177+
(path, tokens)
154178
})
155179
}
156180

src/libsyntax/parse/parser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ impl<'a> Parser<'a> {
825825
///
826826
/// This method will automatically add `tok` to `expected_tokens` if `tok` is not
827827
/// encountered.
828-
fn check(&mut self, tok: &token::Token) -> bool {
828+
crate fn check(&mut self, tok: &token::Token) -> bool {
829829
let is_present = self.token == *tok;
830830
if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); }
831831
is_present

src/test/compile-fail-fulldeps/issue-48941.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@
1717
#![feature(plugin)]
1818
#![plugin(macro_crate_test)]
1919

20-
#[noop_attribute"x"] //~ ERROR expected one of
21-
fn night() { }
22-
23-
#[noop_attribute("hi"), rank = 2] //~ ERROR unexpected token
20+
#[noop_attribute("hi", rank = a)] //~ ERROR expected unsuffixed literal or identifier, found a
2421
fn knight() { }
2522

2623
#[noop_attribute("/user", data= = "<user")] //~ ERROR literal or identifier

src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ extern crate derive_b;
2121
#[C] //~ ERROR: The attribute `C` is currently unknown to the compiler
2222
#[B(D)]
2323
#[B(E = "foo")]
24-
#[B arbitrary tokens] //~ ERROR arbitrary tokens in non-macro attributes are unstable
24+
#[B(arbitrary tokens)] //~ ERROR expected one of `(`, `)`, `,`, `::`, or `=`, found `tokens`
2525
struct B;
2626

2727
fn main() {}

src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs

-6
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,6 @@ mod _test2_inner {
4141
#[a = y] //~ ERROR: must only be followed by a delimiter token
4242
fn _test3() {}
4343

44-
#[a = ] //~ ERROR: must only be followed by a delimiter token
45-
fn _test4() {}
46-
47-
#[a () = ] //~ ERROR: must only be followed by a delimiter token
48-
fn _test5() {}
49-
5044
fn attrs() {
5145
// Statement, item
5246
#[a] // OK
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2018 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+
#[path =] //~ ERROR unexpected token: `]`
12+
mod m {}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2018 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+
#[path() token] //~ ERROR expected `]`, found `token`
12+
mod m {}

src/test/parse-fail/attr-bad-meta.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// asterisk is bogus
12-
#[path*] //~ ERROR arbitrary tokens in non-macro attributes are unstable
11+
#![feature(unrestricted_attribute_tokens)]
12+
13+
#[path*] //~ ERROR expected one of `(`, `::`, `=`, `[`, `]`, or `{`, found `*`
1314
mod m {}

src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use proc_macro::TokenStream;
1919
#[proc_macro_derive(B, attributes(B, C))]
2020
pub fn derive(input: TokenStream) -> TokenStream {
2121
let input = input.to_string();
22-
assert!(input.contains("#[B arbitrary tokens]"));
22+
assert!(input.contains("#[B [ arbitrary tokens ]]"));
2323
assert!(input.contains("struct B {"));
2424
assert!(input.contains("#[C]"));
2525
"".parse().unwrap()

src/test/run-pass-fulldeps/proc-macro/derive-b.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
extern crate derive_b;
1717

1818
#[derive(Debug, PartialEq, derive_b::B, Eq, Copy, Clone)]
19-
#[cfg_attr(all(), B arbitrary tokens)]
19+
#[cfg_attr(all(), B[arbitrary tokens])]
2020
struct B {
2121
#[C]
2222
a: u64

src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ extern crate attribute_spans_preserved as foo;
1717
use foo::foo;
1818

1919
#[ foo ( let y: u32 = "z"; ) ] //~ ERROR: mismatched types
20-
#[ bar let x: u32 = "y"; ] //~ ERROR: mismatched types
20+
#[ bar { let x: u32 = "y"; } ] //~ ERROR: mismatched types
2121
fn main() {
2222
}

src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ LL | #[ foo ( let y: u32 = "z"; ) ] //~ ERROR: mismatched types
88
found type `&'static str`
99

1010
error[E0308]: mismatched types
11-
--> $DIR/attribute-spans-preserved.rs:20:21
11+
--> $DIR/attribute-spans-preserved.rs:20:23
1212
|
13-
LL | #[ bar let x: u32 = "y"; ] //~ ERROR: mismatched types
14-
| ^^^ expected u32, found reference
13+
LL | #[ bar { let x: u32 = "y"; } ] //~ ERROR: mismatched types
14+
| ^^^ expected u32, found reference
1515
|
1616
= note: expected type `u32`
1717
found type `&'static str`
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
fn main ( ) { let y : u32 = "z" ; let x : u32 = "y" ; }
1+
fn main ( ) { let y : u32 = "z" ; { let x : u32 = "y" ; } }

src/test/ui/attr-eq-token-tree.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2018 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+
// compile-pass
12+
13+
#![feature(custom_attribute, unrestricted_attribute_tokens)]
14+
15+
#[my_attr = !] // OK under feature gate
16+
fn main() {}

src/test/ui/macros/macro-attribute.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#[doc = $not_there] //~ ERROR arbitrary tokens in non-macro attributes are unstable
11+
#![feature(unrestricted_attribute_tokens)]
12+
13+
#[doc = $not_there] //~ ERROR expected `]`, found `not_there`
1214
fn main() { }
+4-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
error[E0658]: arbitrary tokens in non-macro attributes are unstable (see issue #44690)
2-
--> $DIR/macro-attribute.rs:11:1
1+
error: expected `]`, found `not_there`
2+
--> $DIR/macro-attribute.rs:13:10
33
|
4-
LL | #[doc = $not_there] //~ ERROR arbitrary tokens in non-macro attributes are unstable
5-
| ^^^^^^^^^^^^^^^^^^^
6-
|
7-
= help: add #![feature(unrestricted_attribute_tokens)] to the crate attributes to enable
4+
LL | #[doc = $not_there] //~ ERROR expected `]`, found `not_there`
5+
| ^^^^^^^^^ expected `]`
86

97
error: aborting due to previous error
108

11-
For more information about this error, try `rustc --explain E0658`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2018 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+
// compile-pass
12+
13+
#![feature(custom_attribute, unrestricted_attribute_tokens)]
14+
15+
#[my_attr(a b c d)]
16+
fn main() {}

0 commit comments

Comments
 (0)