From d2f56378da7f722145d54f7c9c54deed43e2a12b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Aug 2018 16:40:08 +0300 Subject: [PATCH] Feature gate arbitrary tokens in non-macro attributes with a separate gate Feature gate `rustc_` and `derive_` with their own gates again instead of `custom_attribute` --- src/librustc_resolve/macros.rs | 33 ++++++++++--- src/libsyntax/feature_gate.rs | 46 ++++++++++--------- src/test/compile-fail/gated-attr-literals.rs | 32 ++++++------- src/test/compile-fail/macro-attribute.rs | 2 +- src/test/parse-fail/attr-bad-meta.rs | 2 +- .../run-pass-fulldeps/proc-macro/derive-b.rs | 2 +- src/test/ui/feature-gate-rustc-attrs-1.rs | 18 ++++++++ src/test/ui/feature-gate-rustc-attrs-1.stderr | 19 ++++++++ src/test/ui/feature-gate-rustc-attrs.rs | 2 - src/test/ui/feature-gate-rustc-attrs.stderr | 20 +------- ...ture-gate-unrestricted-attribute-tokens.rs | 17 +++++++ ...-gate-unrestricted-attribute-tokens.stderr | 20 ++++++++ 12 files changed, 144 insertions(+), 69 deletions(-) create mode 100644 src/test/ui/feature-gate-rustc-attrs-1.rs create mode 100644 src/test/ui/feature-gate-rustc-attrs-1.stderr create mode 100644 src/test/ui/feature-gate-unrestricted-attribute-tokens.rs create mode 100644 src/test/ui/feature-gate-unrestricted-attribute-tokens.stderr diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index d680b2d9f7d74..2054b7a351f7d 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -28,6 +28,7 @@ use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; use syntax::ext::hygiene::{self, Mark}; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{self, feature_err, emit_feature_err, is_builtin_attr_name, GateIssue}; +use syntax::feature_gate::EXPLAIN_DERIVE_UNDERSCORE; use syntax::fold::{self, Folder}; use syntax::parse::parser::PathStyle; use syntax::parse::token::{self, Token}; @@ -338,19 +339,37 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> { match attr_kind { NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::Custom if is_attr_invoc => { + let features = self.session.features_untracked(); if attr_kind == NonMacroAttrKind::Tool && - !self.session.features_untracked().tool_attributes { + !features.tool_attributes { feature_err(&self.session.parse_sess, "tool_attributes", invoc.span(), GateIssue::Language, "tool attributes are unstable").emit(); } - if attr_kind == NonMacroAttrKind::Custom && - !self.session.features_untracked().custom_attribute { - let msg = format!("The attribute `{}` is currently unknown to the compiler \ - and may have meaning added to it in the future", path); - feature_err(&self.session.parse_sess, "custom_attribute", invoc.span(), - GateIssue::Language, &msg).emit(); + if attr_kind == NonMacroAttrKind::Custom { + assert!(path.segments.len() == 1); + let name = path.segments[0].ident.name.as_str(); + if name.starts_with("rustc_") { + if !features.rustc_attrs { + let msg = "unless otherwise specified, attributes with the prefix \ + `rustc_` are reserved for internal compiler diagnostics"; + feature_err(&self.session.parse_sess, "rustc_attrs", invoc.span(), + GateIssue::Language, &msg).emit(); + } + } else if name.starts_with("derive_") { + if !features.custom_derive { + feature_err(&self.session.parse_sess, "custom_derive", invoc.span(), + GateIssue::Language, EXPLAIN_DERIVE_UNDERSCORE).emit(); + } + } else if !features.custom_attribute { + let msg = format!("The attribute `{}` is currently unknown to the \ + compiler and may have meaning added to it in the \ + future", path); + feature_err(&self.session.parse_sess, "custom_attribute", invoc.span(), + GateIssue::Language, &msg).emit(); + } } + return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr { mark_used: attr_kind == NonMacroAttrKind::Tool, }))); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 976708ae78816..b779b2eb689e8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -90,7 +90,7 @@ macro_rules! declare_features { self.macros_in_extern || self.proc_macro_path_invoc || self.proc_macro_mod || self.proc_macro_expr || self.proc_macro_non_items || self.proc_macro_gen || - self.stmt_expr_attributes + self.stmt_expr_attributes || self.unrestricted_attribute_tokens } } }; @@ -504,6 +504,9 @@ declare_features! ( // impl Iterator for &mut Iterator // impl Debug for Foo<'_> (active, impl_header_lifetime_elision, "1.30.0", Some(15872), Some(Edition::Edition2018)), + + // Support for arbitrary delimited token streams in non-macro attributes. + (active, unrestricted_attribute_tokens, "1.30.0", Some(44690), None), ); declare_features! ( @@ -721,8 +724,7 @@ pub fn is_builtin_attr_name(name: ast::Name) -> bool { } pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { - BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.path == builtin_name) || - attr.name().as_str().starts_with("rustc_") + BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.path == builtin_name) } // Attributes that have a special meaning to rustc or rustdoc @@ -1521,25 +1523,27 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - // allow attr_literals in #[repr(align(x))] and #[repr(packed(n))] - let mut allow_attr_literal = false; - if attr.path == "repr" { - if let Some(content) = attr.meta_item_list() { - allow_attr_literal = content.iter().any( - |c| c.check_name("align") || c.check_name("packed")); - } - } - - if self.context.features.use_extern_macros() && attr::is_known(attr) { - return - } + match attr.parse_meta(self.context.parse_sess) { + Ok(meta) => { + // allow attr_literals in #[repr(align(x))] and #[repr(packed(n))] + let mut allow_attr_literal = false; + if attr.path == "repr" { + if let Some(content) = meta.meta_item_list() { + allow_attr_literal = content.iter().any( + |c| c.check_name("align") || c.check_name("packed")); + } + } - if !allow_attr_literal { - let meta = panictry!(attr.parse_meta(self.context.parse_sess)); - if contains_novel_literal(&meta) { - gate_feature_post!(&self, attr_literals, attr.span, - "non-string literals in attributes, or string \ - literals in top-level positions, are experimental"); + if !allow_attr_literal && contains_novel_literal(&meta) { + gate_feature_post!(&self, attr_literals, attr.span, + "non-string literals in attributes, or string \ + literals in top-level positions, are experimental"); + } + } + Err(mut err) => { + err.cancel(); + gate_feature_post!(&self, unrestricted_attribute_tokens, attr.span, + "arbitrary tokens in non-macro attributes are unstable"); } } } diff --git a/src/test/compile-fail/gated-attr-literals.rs b/src/test/compile-fail/gated-attr-literals.rs index b500bfc3c2139..8d36745116b65 100644 --- a/src/test/compile-fail/gated-attr-literals.rs +++ b/src/test/compile-fail/gated-attr-literals.rs @@ -11,37 +11,33 @@ // Check that literals in attributes don't parse without the feature gate. // gate-test-attr_literals -// gate-test-custom_attribute -#![feature(rustc_attrs)] -#![allow(dead_code)] -#![allow(unused_variables)] +#![feature(custom_attribute)] -#[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown -#[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr] // OK +#[fake_attr(100)] //~^ ERROR non-string literals in attributes -#[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(1, 2, 3)] //~^ ERROR non-string literals in attributes -#[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr("hello")] //~^ ERROR string literals in top-level positions, are experimental -#[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown -#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(name = "hello")] // OK +#[fake_attr(1, "hi", key = 12, true, false)] //~^ ERROR non-string literals in attributes, or string literals in top-level positions -#[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(key = "hello", val = 10)] //~^ ERROR non-string literals in attributes -#[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(key("hello"), val(10))] //~^ ERROR non-string literals in attributes, or string literals in top-level positions -#[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(enabled = true, disabled = false)] //~^ ERROR non-string literals in attributes -#[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(true)] //~^ ERROR non-string literals in attributes -#[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(pi = 3.14159)] //~^ ERROR non-string literals in attributes -#[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(b"hi")] //~^ ERROR string literals in top-level positions, are experimental -#[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown +#[fake_doc(r"doc")] //~^ ERROR string literals in top-level positions, are experimental struct Q { } -#[rustc_error] fn main() { } diff --git a/src/test/compile-fail/macro-attribute.rs b/src/test/compile-fail/macro-attribute.rs index 52f867fe913b8..a77b172487600 100644 --- a/src/test/compile-fail/macro-attribute.rs +++ b/src/test/compile-fail/macro-attribute.rs @@ -8,5 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[doc = $not_there] //~ error: unexpected token: `$` +#[doc = $not_there] //~ ERROR arbitrary tokens in non-macro attributes are unstable fn main() { } diff --git a/src/test/parse-fail/attr-bad-meta.rs b/src/test/parse-fail/attr-bad-meta.rs index d57a813311b5a..41db88121cb52 100644 --- a/src/test/parse-fail/attr-bad-meta.rs +++ b/src/test/parse-fail/attr-bad-meta.rs @@ -9,5 +9,5 @@ // except according to those terms. // asterisk is bogus -#[path*] //~ ERROR expected one of `(` or `=` +#[path*] //~ ERROR arbitrary tokens in non-macro attributes are unstable mod m {} diff --git a/src/test/run-pass-fulldeps/proc-macro/derive-b.rs b/src/test/run-pass-fulldeps/proc-macro/derive-b.rs index 4a7c8f3e8343b..918d2c17123e8 100644 --- a/src/test/run-pass-fulldeps/proc-macro/derive-b.rs +++ b/src/test/run-pass-fulldeps/proc-macro/derive-b.rs @@ -11,7 +11,7 @@ // aux-build:derive-b.rs // ignore-stage1 -#![feature(proc_macro_path_invoc)] +#![feature(proc_macro_path_invoc, unrestricted_attribute_tokens)] extern crate derive_b; diff --git a/src/test/ui/feature-gate-rustc-attrs-1.rs b/src/test/ui/feature-gate-rustc-attrs-1.rs new file mode 100644 index 0000000000000..7295de80db56d --- /dev/null +++ b/src/test/ui/feature-gate-rustc-attrs-1.rs @@ -0,0 +1,18 @@ +// Copyright 2015 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. + +// ignore-tidy-linelength + +// Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate. + +#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable +#[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable + +fn main() {} diff --git a/src/test/ui/feature-gate-rustc-attrs-1.stderr b/src/test/ui/feature-gate-rustc-attrs-1.stderr new file mode 100644 index 0000000000000..54a580ce9f942 --- /dev/null +++ b/src/test/ui/feature-gate-rustc-attrs-1.stderr @@ -0,0 +1,19 @@ +error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable (see issue #29642) + --> $DIR/feature-gate-rustc-attrs-1.rs:15:1 + | +LL | #[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable + | ^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(rustc_attrs)] to the crate attributes to enable + +error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable (see issue #29642) + --> $DIR/feature-gate-rustc-attrs-1.rs:16:1 + | +LL | #[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable + | ^^^^^^^^^^^^^^ + | + = help: add #![feature(rustc_attrs)] to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-rustc-attrs.rs b/src/test/ui/feature-gate-rustc-attrs.rs index 8cfd3e020c69a..99bc51b69c6cb 100644 --- a/src/test/ui/feature-gate-rustc-attrs.rs +++ b/src/test/ui/feature-gate-rustc-attrs.rs @@ -12,8 +12,6 @@ // Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate. -#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable -#[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable #[rustc_foo] //~^ ERROR unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics diff --git a/src/test/ui/feature-gate-rustc-attrs.stderr b/src/test/ui/feature-gate-rustc-attrs.stderr index fda95a5b97a57..52a4d3664ce23 100644 --- a/src/test/ui/feature-gate-rustc-attrs.stderr +++ b/src/test/ui/feature-gate-rustc-attrs.stderr @@ -1,27 +1,11 @@ -error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable (see issue #29642) - --> $DIR/feature-gate-rustc-attrs.rs:15:1 - | -LL | #[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable - | ^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(rustc_attrs)] to the crate attributes to enable - -error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable (see issue #29642) - --> $DIR/feature-gate-rustc-attrs.rs:16:1 - | -LL | #[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable - | ^^^^^^^^^^^^^^ - | - = help: add #![feature(rustc_attrs)] to the crate attributes to enable - error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642) - --> $DIR/feature-gate-rustc-attrs.rs:17:1 + --> $DIR/feature-gate-rustc-attrs.rs:15:1 | LL | #[rustc_foo] | ^^^^^^^^^^^^ | = help: add #![feature(rustc_attrs)] to the crate attributes to enable -error: aborting due to 3 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-unrestricted-attribute-tokens.rs b/src/test/ui/feature-gate-unrestricted-attribute-tokens.rs new file mode 100644 index 0000000000000..daebbe658a23b --- /dev/null +++ b/src/test/ui/feature-gate-unrestricted-attribute-tokens.rs @@ -0,0 +1,17 @@ +// Copyright 2018 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. + +#![feature(custom_attribute)] + +#[my_attr(a b c d)] +//~^ ERROR expected one of `(`, `)`, `,`, `::`, or `=`, found `b` +//~| ERROR expected one of `(`, `)`, `,`, `::`, or `=`, found `c` +//~| ERROR expected one of `(`, `)`, `,`, `::`, or `=`, found `d` +fn main() {} diff --git a/src/test/ui/feature-gate-unrestricted-attribute-tokens.stderr b/src/test/ui/feature-gate-unrestricted-attribute-tokens.stderr new file mode 100644 index 0000000000000..cc5694b1598d3 --- /dev/null +++ b/src/test/ui/feature-gate-unrestricted-attribute-tokens.stderr @@ -0,0 +1,20 @@ +error: expected one of `(`, `)`, `,`, `::`, or `=`, found `b` + --> $DIR/feature-gate-unrestricted-attribute-tokens.rs:13:13 + | +LL | #[my_attr(a b c d)] + | ^ expected one of `(`, `)`, `,`, `::`, or `=` here + +error: expected one of `(`, `)`, `,`, `::`, or `=`, found `c` + --> $DIR/feature-gate-unrestricted-attribute-tokens.rs:13:15 + | +LL | #[my_attr(a b c d)] + | ^ expected one of `(`, `)`, `,`, `::`, or `=` here + +error: expected one of `(`, `)`, `,`, `::`, or `=`, found `d` + --> $DIR/feature-gate-unrestricted-attribute-tokens.rs:13:17 + | +LL | #[my_attr(a b c d)] + | ^ expected one of `(`, `)`, `,`, `::`, or `=` here + +error: aborting due to 3 previous errors +