Skip to content

Commit 55c173c

Browse files
committed
Auto merge of #57367 - petrochenkov:unrestab, r=Centril
Stabilize `unrestricted_attribute_tokens` In accordance with a plan described in https://internals.rust-lang.org/t/unrestricted-attribute-tokens-feature-status/8561/3. Delimited non-macro non-builtin attributes now support the same syntax as macro attributes: ``` PATH PATH `(` TOKEN_STREAM `)` PATH `[` TOKEN_STREAM `]` PATH `{` TOKEN_STREAM `}` ``` Such attributes mostly serve as inert proc macro helpers or tool attributes. To some extent these attributes are de-facto stable due to a hole in feature gate checking (feature gating is done too late - after macro expansion.) So if macro *removes* such helper attributes during expansion (and it must remove them, unless it's a derive macro), then the code will work on stable. Key-value non-macro non-builtin attributes are now restricted to bare minimum required to support what we support on stable - unsuffixed literals (#34981). ``` PATH `=` LITERAL ``` (Key-value macro attributes are not supported at all right now.) Crater run in #57321 found no regressions for this change. There are multiple possible ways to extend key-value attributes (#57321 (comment)), but I'd expect an RFC for that and it's not a pressing enough issue to block stabilization of delimited attributes. Built-in attributes are still restricted to the "classic" meta-item syntax, nothing changes here. #57321 goes further and adds some additional restrictions (more consistent input checking) to built-in attributes. Closes #55208
2 parents 00aae71 + eccc199 commit 55c173c

23 files changed

+108
-87
lines changed

src/libcore/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@
123123
#![feature(abi_unadjusted)]
124124
#![feature(adx_target_feature)]
125125
#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)]
126-
#![feature(unrestricted_attribute_tokens)]
127126
#![feature(external_doc)]
128127

129128
#[prelude_import]

src/libsyntax/feature_gate.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ use crate::early_buffered_lints::BufferedEarlyLintId;
2121
use crate::source_map::Spanned;
2222
use crate::edition::{ALL_EDITIONS, Edition};
2323
use crate::visit::{self, FnKind, Visitor};
24-
use crate::parse::ParseSess;
24+
use crate::parse::{token, ParseSess};
2525
use crate::symbol::Symbol;
26+
use crate::tokenstream::TokenTree;
2627

2728
use errors::{DiagnosticBuilder, Handler};
2829
use rustc_data_structures::fx::FxHashMap;
@@ -431,9 +432,6 @@ declare_features! (
431432
// Added for testing E0705; perma-unstable.
432433
(active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)),
433434

434-
// support for arbitrary delimited token streams in non-macro attributes
435-
(active, unrestricted_attribute_tokens, "1.30.0", Some(55208), None),
436-
437435
// Allows unsized rvalues at arguments and parameters.
438436
(active, unsized_locals, "1.30.0", Some(48055), None),
439437

@@ -700,6 +698,8 @@ declare_features! (
700698
(accepted, cfg_target_vendor, "1.33.0", Some(29718), None),
701699
// `extern crate self as foo;` puts local crate root into extern prelude under name `foo`.
702700
(accepted, extern_crate_self, "1.34.0", Some(56409), None),
701+
// support for arbitrary delimited token streams in non-macro attributes
702+
(accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None),
703703
);
704704

705705
// If you change this, please modify `src/doc/unstable-book` as well. You must
@@ -1660,13 +1660,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
16601660

16611661
match BUILTIN_ATTRIBUTES.iter().find(|(name, ..)| attr.path == name) {
16621662
Some(&(name, _, template, _)) => self.check_builtin_attribute(attr, name, template),
1663-
None => if !self.context.features.unrestricted_attribute_tokens {
1664-
// Unfortunately, `parse_meta` cannot be called speculatively
1665-
// because it can report errors by itself, so we have to call it
1666-
// only if the feature is disabled.
1667-
if let Err(mut err) = attr.parse_meta(self.context.parse_sess) {
1668-
err.help("try enabling `#![feature(unrestricted_attribute_tokens)]`").emit()
1669-
}
1663+
None => if let Some(TokenTree::Token(_, token::Eq)) = attr.tokens.trees().next() {
1664+
// All key-value attributes are restricted to meta-item syntax.
1665+
attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok();
16701666
}
16711667
}
16721668
}

src/libsyntax/parse/attr.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,21 @@ impl<'a> Parser<'a> {
158158
self.parse_token_tree().into()
159159
} else if self.eat(&token::Eq) {
160160
let eq = TokenTree::Token(self.prev_span, token::Eq);
161-
let tree = match self.token {
162-
token::CloseDelim(_) | token::Eof => self.unexpected()?,
163-
_ => self.parse_token_tree(),
161+
let mut is_interpolated_expr = false;
162+
if let token::Interpolated(nt) = &self.token {
163+
if let token::NtExpr(..) = **nt {
164+
is_interpolated_expr = true;
165+
}
166+
}
167+
let tokens = if is_interpolated_expr {
168+
// We need to accept arbitrary interpolated expressions to continue
169+
// supporting things like `doc = $expr` that work on stable.
170+
// Non-literal interpolated expressions are rejected after expansion.
171+
self.parse_token_tree().into()
172+
} else {
173+
self.parse_unsuffixed_lit()?.tokens()
164174
};
165-
TokenStream::new(vec![eq.into(), tree.into()])
175+
TokenStream::from_streams(vec![eq.into(), tokens])
166176
} else {
167177
TokenStream::empty()
168178
};

src/libsyntax/tokenstream.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ impl TokenStream {
254254
}
255255
}
256256

257-
fn from_streams(mut streams: Vec<TokenStream>) -> TokenStream {
257+
pub(crate) fn from_streams(mut streams: Vec<TokenStream>) -> TokenStream {
258258
match streams.len() {
259259
0 => TokenStream::empty(),
260260
1 => streams.pop().unwrap(),

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// aux-build:derive-b.rs
22

3-
#![feature(unrestricted_attribute_tokens)]
4-
53
extern crate derive_b;
64

75
#[derive(Debug, PartialEq, derive_b::B, Eq, Copy, Clone)]

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
// compile-pass
1+
#![feature(custom_attribute)]
22

3-
#![feature(custom_attribute, unrestricted_attribute_tokens)]
4-
5-
#[my_attr = !] // OK under feature gate
3+
#[my_attr = !] //~ ERROR unexpected token: `!`
64
fn main() {}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: unexpected token: `!`
2+
--> $DIR/attr-eq-token-tree.rs:3:11
3+
|
4+
LL | #[my_attr = !] //~ ERROR unexpected token: `!`
5+
| ^
6+
7+
error: aborting due to previous error
8+

src/test/ui/feature-gates/feature-gate-unrestricted-attribute-tokens.rs

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/test/ui/feature-gates/feature-gate-unrestricted-attribute-tokens.stderr

Lines changed: 0 additions & 20 deletions
This file was deleted.

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
#![feature(unrestricted_attribute_tokens)]
2-
3-
#[doc = $not_there] //~ ERROR expected `]`, found `not_there`
1+
#[doc = $not_there] //~ ERROR unexpected token: `$`
42
fn main() { }

0 commit comments

Comments
 (0)