From d2f56378da7f722145d54f7c9c54deed43e2a12b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Sat, 11 Aug 2018 16:40:08 +0300 Subject: [PATCH 1/3] 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<I:Iterator> 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 + From e7ee6fb2a25c9e3dbb6c7db07f4e339111d265ec Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Sat, 11 Aug 2018 16:58:28 +0300 Subject: [PATCH 2/3] Do not consider built-in attributes as candidates when resolving non-attribute macro invocations This is needed to avoid regressions on stable channel --- src/librustc_resolve/macros.rs | 5 +++- src/test/ui/issue-11692-2.rs | 2 +- src/test/ui/issue-11692-2.stderr | 2 +- src/test/ui/macro-path-prelude-fail-3.rs | 4 +-- src/test/ui/macro-path-prelude-fail-3.stderr | 10 +++---- src/test/ui/macro-path-prelude-shadowing.rs | 4 ++- .../ui/macro-path-prelude-shadowing.stderr | 29 +++---------------- 7 files changed, 20 insertions(+), 36 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 2054b7a351f7d..f111a44efe05b 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -669,7 +669,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } } WhereToResolve::BuiltinAttrs => { - if is_builtin_attr_name(ident.name) { + // FIXME: Only built-in attributes are not considered as candidates for + // non-attributes to fight off regressions on stable channel (#53205). + // We need to come up with some more principled approach instead. + if is_attr && is_builtin_attr_name(ident.name) { let binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin), ty::Visibility::Public, ident.span, Mark::root()) .to_name_binding(self.arenas); diff --git a/src/test/ui/issue-11692-2.rs b/src/test/ui/issue-11692-2.rs index 50525e03acf50..acac2d151fe9a 100644 --- a/src/test/ui/issue-11692-2.rs +++ b/src/test/ui/issue-11692-2.rs @@ -10,5 +10,5 @@ fn main() { concat!(test!()); - //~^ ERROR expected a macro, found built-in attribute + //~^ ERROR cannot find macro `test!` in this scope } diff --git a/src/test/ui/issue-11692-2.stderr b/src/test/ui/issue-11692-2.stderr index 0c130943fd873..51d6041e92220 100644 --- a/src/test/ui/issue-11692-2.stderr +++ b/src/test/ui/issue-11692-2.stderr @@ -1,4 +1,4 @@ -error: expected a macro, found built-in attribute +error: cannot find macro `test!` in this scope --> $DIR/issue-11692-2.rs:12:13 | LL | concat!(test!()); diff --git a/src/test/ui/macro-path-prelude-fail-3.rs b/src/test/ui/macro-path-prelude-fail-3.rs index bdbc7bd660fcd..d325b0460015c 100644 --- a/src/test/ui/macro-path-prelude-fail-3.rs +++ b/src/test/ui/macro-path-prelude-fail-3.rs @@ -10,9 +10,9 @@ #![feature(use_extern_macros)] -#[derive(inline)] //~ ERROR expected a macro, found built-in attribute +#[derive(inline)] //~ ERROR cannot find derive macro `inline` in this scope struct S; fn main() { - inline!(); //~ ERROR expected a macro, found built-in attribute + inline!(); //~ ERROR cannot find macro `inline!` in this scope } diff --git a/src/test/ui/macro-path-prelude-fail-3.stderr b/src/test/ui/macro-path-prelude-fail-3.stderr index 396bba2408f32..c9af4b6642751 100644 --- a/src/test/ui/macro-path-prelude-fail-3.stderr +++ b/src/test/ui/macro-path-prelude-fail-3.stderr @@ -1,14 +1,14 @@ -error: expected a macro, found built-in attribute +error: cannot find derive macro `inline` in this scope --> $DIR/macro-path-prelude-fail-3.rs:13:10 | -LL | #[derive(inline)] //~ ERROR expected a macro, found built-in attribute +LL | #[derive(inline)] //~ ERROR cannot find derive macro `inline` in this scope | ^^^^^^ -error: expected a macro, found built-in attribute +error: cannot find macro `inline!` in this scope --> $DIR/macro-path-prelude-fail-3.rs:17:5 | -LL | inline!(); //~ ERROR expected a macro, found built-in attribute - | ^^^^^^ +LL | inline!(); //~ ERROR cannot find macro `inline!` in this scope + | ^^^^^^ help: you could try the macro: `line` error: aborting due to 2 previous errors diff --git a/src/test/ui/macro-path-prelude-shadowing.rs b/src/test/ui/macro-path-prelude-shadowing.rs index 1aff7777ef7b1..6831cd81d7dae 100644 --- a/src/test/ui/macro-path-prelude-shadowing.rs +++ b/src/test/ui/macro-path-prelude-shadowing.rs @@ -21,7 +21,9 @@ add_macro_expanded_things_to_macro_prelude!(); mod m1 { fn check() { - inline!(); //~ ERROR `inline` is ambiguous + inline!(); // OK. Theoretically ambiguous, but we do not consider built-in attributes + // as candidates for non-attribute macro invocations to avoid regressions + // on stable channel } } diff --git a/src/test/ui/macro-path-prelude-shadowing.stderr b/src/test/ui/macro-path-prelude-shadowing.stderr index 0e1b9a985a3c3..c0892f97376e3 100644 --- a/src/test/ui/macro-path-prelude-shadowing.stderr +++ b/src/test/ui/macro-path-prelude-shadowing.stderr @@ -1,42 +1,21 @@ -error[E0659]: `inline` is ambiguous - --> $DIR/macro-path-prelude-shadowing.rs:24:9 - | -LL | inline!(); //~ ERROR `inline` is ambiguous - | ^^^^^^ - | -note: `inline` could refer to the name imported here - --> $DIR/macro-path-prelude-shadowing.rs:16:5 - | -LL | #[macro_use] - | ^^^^^^^^^^^^ -... -LL | add_macro_expanded_things_to_macro_prelude!(); - | ---------------------------------------------- in this macro invocation -note: `inline` could also refer to the name defined here - --> $DIR/macro-path-prelude-shadowing.rs:24:9 - | -LL | inline!(); //~ ERROR `inline` is ambiguous - | ^^^^^^ - = note: macro-expanded macro imports do not shadow - error[E0659]: `std` is ambiguous - --> $DIR/macro-path-prelude-shadowing.rs:37:9 + --> $DIR/macro-path-prelude-shadowing.rs:39:9 | LL | std::panic!(); //~ ERROR `std` is ambiguous | ^^^^^^^^^^ | note: `std` could refer to the name imported here - --> $DIR/macro-path-prelude-shadowing.rs:35:9 + --> $DIR/macro-path-prelude-shadowing.rs:37:9 | LL | use m2::*; // glob-import user-defined `std` | ^^^^^ note: `std` could also refer to the name defined here - --> $DIR/macro-path-prelude-shadowing.rs:37:9 + --> $DIR/macro-path-prelude-shadowing.rs:39:9 | LL | std::panic!(); //~ ERROR `std` is ambiguous | ^^^ = note: consider adding an explicit import of `std` to disambiguate -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0659`. From dd0a766e06fc553a0321fb04eb51910bfd2c7097 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Sat, 11 Aug 2018 14:33:43 +0300 Subject: [PATCH 3/3] Prohibit using macro-expanded `macro_export` macros through module-relative paths --- src/librustc_resolve/build_reduced_graph.rs | 1 - src/librustc_resolve/lib.rs | 16 ++++++--- src/librustc_resolve/macros.rs | 2 -- src/librustc_resolve/resolve_imports.rs | 20 +++++++++-- .../proc-macro/proc-macro-attributes.rs | 2 +- .../local-modularized-tricky-fail-3.rs | 32 +++++++++++++++++ .../local-modularized-tricky-fail-3.stderr | 36 +++++++++++++++++++ 7 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/imports/local-modularized-tricky-fail-3.rs create mode 100644 src/test/ui/imports/local-modularized-tricky-fail-3.stderr diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 0be1bf3011e78..bf87b00c14969 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -789,7 +789,6 @@ impl<'a, 'b, 'cl> BuildReducedGraphVisitor<'a, 'b, 'cl> { fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> { let mark = id.placeholder_to_mark(); self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark); - self.resolver.unresolved_invocations_macro_export.insert(mark); let invocation = self.resolver.invocations[&mark]; invocation.module.set(self.resolver.current_module); invocation.legacy_scope.set(self.legacy_scope); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8ff4483492906..e31e2cc1dff59 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1385,6 +1385,8 @@ pub struct Resolver<'a, 'b: 'a> { use_injections: Vec<UseError<'a>>, /// `use` injections for proc macros wrongly imported with #[macro_use] proc_mac_errors: Vec<macros::ProcMacError>, + /// crate-local macro expanded `macro_export` referred to by a module-relative path + macro_expanded_macro_export_errors: BTreeSet<(Span, Span)>, gated_errors: FxHashSet<Span>, disallowed_shadowing: Vec<&'a LegacyBinding<'a>>, @@ -1432,9 +1434,6 @@ pub struct Resolver<'a, 'b: 'a> { /// Only supposed to be used by rustdoc, otherwise should be false. pub ignore_extern_prelude_feature: bool, - - /// Macro invocations in the whole crate that can expand into a `#[macro_export] macro_rules`. - unresolved_invocations_macro_export: FxHashSet<Mark>, } /// Nothing really interesting here, it just provides memory for the rest of the crate. @@ -1706,6 +1705,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { proc_mac_errors: Vec::new(), gated_errors: FxHashSet(), disallowed_shadowing: Vec::new(), + macro_expanded_macro_export_errors: BTreeSet::new(), arenas, dummy_binding: arenas.alloc_name_binding(NameBinding { @@ -1737,7 +1737,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { current_type_ascription: Vec::new(), injected_crate: None, ignore_extern_prelude_feature: false, - unresolved_invocations_macro_export: FxHashSet(), } } @@ -4126,6 +4125,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { ns: Namespace, module: Module<'a>, found_traits: &mut Vec<TraitCandidate>) { + assert!(ns == TypeNS || ns == ValueNS); let mut traits = module.traits.borrow_mut(); if traits.is_none() { let mut collected_traits = Vec::new(); @@ -4371,6 +4371,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { self.report_proc_macro_import(krate); let mut reported_spans = FxHashSet(); + for &(span_use, span_def) in &self.macro_expanded_macro_export_errors { + let msg = "macro-expanded `macro_export` macros from the current crate \ + cannot be referred to by absolute paths"; + self.session.struct_span_err(span_use, msg) + .span_note(span_def, "the macro is defined here") + .emit(); + } + for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors { if !reported_spans.insert(span) { continue } let participle = |binding: &NameBinding| { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index f111a44efe05b..fe9d3c7eb9982 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -196,9 +196,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> { self.current_module = invocation.module.get(); self.current_module.unresolved_invocations.borrow_mut().remove(&mark); - self.unresolved_invocations_macro_export.remove(&mark); self.current_module.unresolved_invocations.borrow_mut().extend(derives); - self.unresolved_invocations_macro_export.extend(derives); for &derive in derives { self.invocations.insert(derive, invocation); } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index a3a9b938bbd6f..715292bc11622 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -146,6 +146,14 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { .try_borrow_mut() .map_err(|_| Determined)?; // This happens when there is a cycle of imports + if let Some(binding) = resolution.binding { + if !restricted_shadowing && binding.expansion != Mark::root() { + if let NameBindingKind::Def(_, true) = binding.kind { + self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); + } + } + } + if record_used { if let Some(binding) = resolution.binding { if let Some(shadowed_glob) = resolution.shadowed_glob { @@ -211,9 +219,15 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { // if it cannot be shadowed by some new item/import expanded from a macro. // This happens either if there are no unexpanded macros, or expanded names cannot // shadow globs (that happens in macro namespace or with restricted shadowing). - let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty() || - (ns == MacroNS && ptr::eq(module, self.graph_root) && - !self.unresolved_invocations_macro_export.is_empty()); + // + // Additionally, any macro in any module can plant names in the root module if it creates + // `macro_export` macros, so the root module effectively has unresolved invocations if any + // module has unresolved invocations. + // However, it causes resolution/expansion to stuck too often (#53144), so, to make + // progress, we have to ignore those potential unresolved invocations from other modules + // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted + // shadowing is enabled, see `macro_expanded_macro_export_errors`). + let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty(); if let Some(binding) = resolution.binding { if !unexpanded_macros || ns == MacroNS || restricted_shadowing { return check_usable(self, binding); diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs index 153e4dd05717a..8d53699c0640e 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs @@ -21,7 +21,7 @@ extern crate derive_b; #[C] //~ ERROR: The attribute `C` is currently unknown to the compiler #[B(D)] #[B(E = "foo")] -#[B arbitrary tokens] //~ expected one of `(` or `=`, found `arbitrary` +#[B arbitrary tokens] //~ ERROR arbitrary tokens in non-macro attributes are unstable struct B; fn main() {} diff --git a/src/test/ui/imports/local-modularized-tricky-fail-3.rs b/src/test/ui/imports/local-modularized-tricky-fail-3.rs new file mode 100644 index 0000000000000..ab1f312e161e8 --- /dev/null +++ b/src/test/ui/imports/local-modularized-tricky-fail-3.rs @@ -0,0 +1,32 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Crate-local macro expanded `macro_export` macros cannot be accessed with module-relative paths. + +#![feature(use_extern_macros)] + +macro_rules! define_exported { () => { + #[macro_export] + macro_rules! exported { + () => () + } +}} + +define_exported!(); + +mod m { + use exported; + //~^ ERROR macro-expanded `macro_export` macros from the current crate cannot +} + +fn main() { + ::exported!(); + //~^ ERROR macro-expanded `macro_export` macros from the current crate cannot +} diff --git a/src/test/ui/imports/local-modularized-tricky-fail-3.stderr b/src/test/ui/imports/local-modularized-tricky-fail-3.stderr new file mode 100644 index 0000000000000..6da52842d83d7 --- /dev/null +++ b/src/test/ui/imports/local-modularized-tricky-fail-3.stderr @@ -0,0 +1,36 @@ +error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths + --> $DIR/local-modularized-tricky-fail-3.rs:25:9 + | +LL | use exported; + | ^^^^^^^^ + | +note: the macro is defined here + --> $DIR/local-modularized-tricky-fail-3.rs:17:5 + | +LL | / macro_rules! exported { +LL | | () => () +LL | | } + | |_____^ +... +LL | define_exported!(); + | ------------------- in this macro invocation + +error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths + --> $DIR/local-modularized-tricky-fail-3.rs:30:5 + | +LL | ::exported!(); + | ^^^^^^^^^^ + | +note: the macro is defined here + --> $DIR/local-modularized-tricky-fail-3.rs:17:5 + | +LL | / macro_rules! exported { +LL | | () => () +LL | | } + | |_____^ +... +LL | define_exported!(); + | ------------------- in this macro invocation + +error: aborting due to 2 previous errors +