Auto merge of #66070 - petrochenkov:regattr, r=matthewjasper
Support registering inert attributes and attribute tools using crate-level attributes
And remove `#[feature(custom_attribute)]`.
(`rustc_plugin::Registry::register_attribute` is not removed yet, I'll do it in a follow up PR.)
```rust
#![register_attr(my_attr)]
#![register_tool(my_tool)]
#[my_attr] // OK
#[my_tool::anything] // OK
fn main() {}
```
---
Some tools (`rustfmt` and `clippy`) used in tool attributes are hardcoded in the compiler.
We need some way to introduce them without hardcoding as well.
This PR introduces a way to do it with a crate level attribute.
The previous attempt to introduce them through command line (https://github.com/rust-lang/rust/pull/57921) met some resistance.
This probably needs to go through an RFC before stabilization.
However, I'd prefer to land *this* PR without an RFC to able to remove `#[feature(custom_attribute)]` and `Registry::register_attribute` while also providing a replacement.
---
`register_attr` is a direct replacement for `#![feature(custom_attribute)]` (https://github.com/rust-lang/rust/issues/29642), except it doesn't rely on implicit fallback from unresolved attributes to custom attributes (which was always hacky and is the primary reason for the removal of `custom_attribute`) and requires registering the attribute explicitly.
It's not clear whether it should go through stabilization or not.
It's quite possible that all the uses should migrate to `#![register_tool]` (https://github.com/rust-lang/rust/issues/66079) instead.
---
Details:
- The naming is `register_attr`/`register_tool` rather than some `register_attributes` (plural, no abbreviation) for consistency with already existing attributes like `cfg_attr`, or `feature`, etc.
---
Previous attempt: https://github.com/rust-lang/rust/pull/57921
cc https://github.com/rust-lang/rust/issues/44690
Tracking issues: #66079 (`register_tool`), #66080 (`register_attr`)
Closes https://github.com/rust-lang/rust/issues/29642
This commit is contained in:
commit
3fc30d884a
33 changed files with 411 additions and 118 deletions
|
|
@ -40,10 +40,10 @@ pub enum NonMacroAttrKind {
|
||||||
Tool,
|
Tool,
|
||||||
/// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`).
|
/// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`).
|
||||||
DeriveHelper,
|
DeriveHelper,
|
||||||
|
/// Single-segment custom attribute registered with `#[register_attr]`.
|
||||||
|
Registered,
|
||||||
/// Single-segment custom attribute registered by a legacy plugin (`register_attribute`).
|
/// Single-segment custom attribute registered by a legacy plugin (`register_attribute`).
|
||||||
LegacyPluginHelper,
|
LegacyPluginHelper,
|
||||||
/// Single-segment custom attribute not registered in any way (`#[my_attr]`).
|
|
||||||
Custom,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, HashStable)]
|
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, HashStable)]
|
||||||
|
|
@ -329,8 +329,24 @@ impl NonMacroAttrKind {
|
||||||
NonMacroAttrKind::Builtin => "built-in attribute",
|
NonMacroAttrKind::Builtin => "built-in attribute",
|
||||||
NonMacroAttrKind::Tool => "tool attribute",
|
NonMacroAttrKind::Tool => "tool attribute",
|
||||||
NonMacroAttrKind::DeriveHelper => "derive helper attribute",
|
NonMacroAttrKind::DeriveHelper => "derive helper attribute",
|
||||||
|
NonMacroAttrKind::Registered => "explicitly registered attribute",
|
||||||
NonMacroAttrKind::LegacyPluginHelper => "legacy plugin helper attribute",
|
NonMacroAttrKind::LegacyPluginHelper => "legacy plugin helper attribute",
|
||||||
NonMacroAttrKind::Custom => "custom attribute",
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn article(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
NonMacroAttrKind::Registered => "an",
|
||||||
|
_ => "a",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Users of some attributes cannot mark them as used, so they are considered always used.
|
||||||
|
pub fn is_used(self) -> bool {
|
||||||
|
match self {
|
||||||
|
NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper => true,
|
||||||
|
NonMacroAttrKind::Builtin | NonMacroAttrKind::Registered |
|
||||||
|
NonMacroAttrKind::LegacyPluginHelper => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -389,6 +405,7 @@ impl<Id> Res<Id> {
|
||||||
pub fn article(&self) -> &'static str {
|
pub fn article(&self) -> &'static str {
|
||||||
match *self {
|
match *self {
|
||||||
Res::Def(kind, _) => kind.article(),
|
Res::Def(kind, _) => kind.article(),
|
||||||
|
Res::NonMacroAttr(kind) => kind.article(),
|
||||||
Res::Err => "an",
|
Res::Err => "an",
|
||||||
_ => "a",
|
_ => "a",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,6 @@ impl<'a> Registry<'a> {
|
||||||
|
|
||||||
/// Register an attribute with an attribute type.
|
/// Register an attribute with an attribute type.
|
||||||
///
|
///
|
||||||
/// Registered attributes will bypass the `custom_attribute` feature gate.
|
|
||||||
/// `Whitelisted` attributes will additionally not trigger the `unused_attribute`
|
/// `Whitelisted` attributes will additionally not trigger the `unused_attribute`
|
||||||
/// lint. `CrateLevel` attributes will not be allowed on anything other than a crate.
|
/// lint. `CrateLevel` attributes will not be allowed on anything other than a crate.
|
||||||
pub fn register_attribute(&mut self, name: Symbol, ty: AttributeType) {
|
pub fn register_attribute(&mut self, name: Symbol, ty: AttributeType) {
|
||||||
|
|
|
||||||
|
|
@ -141,8 +141,7 @@ impl<'a> Resolver<'a> {
|
||||||
crate fn get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
|
crate fn get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
|
||||||
match res {
|
match res {
|
||||||
Res::Def(DefKind::Macro(..), def_id) => self.get_macro_by_def_id(def_id),
|
Res::Def(DefKind::Macro(..), def_id) => self.get_macro_by_def_id(def_id),
|
||||||
Res::NonMacroAttr(attr_kind) =>
|
Res::NonMacroAttr(attr_kind) => Some(self.non_macro_attr(attr_kind.is_used())),
|
||||||
Some(self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ use syntax_pos::hygiene::MacroKind;
|
||||||
use syntax_pos::{BytePos, Span, MultiSpan};
|
use syntax_pos::{BytePos, Span, MultiSpan};
|
||||||
|
|
||||||
use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
|
use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
|
||||||
use crate::{path_names_to_string, KNOWN_TOOLS};
|
use crate::path_names_to_string;
|
||||||
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
|
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
|
||||||
use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment};
|
use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment};
|
||||||
|
|
||||||
|
|
@ -400,6 +400,14 @@ impl<'a> Resolver<'a> {
|
||||||
Scope::Module(module) => {
|
Scope::Module(module) => {
|
||||||
this.add_module_candidates(module, &mut suggestions, filter_fn);
|
this.add_module_candidates(module, &mut suggestions, filter_fn);
|
||||||
}
|
}
|
||||||
|
Scope::RegisteredAttrs => {
|
||||||
|
let res = Res::NonMacroAttr(NonMacroAttrKind::Registered);
|
||||||
|
if filter_fn(res) {
|
||||||
|
suggestions.extend(this.registered_attrs.iter().map(|ident| {
|
||||||
|
TypoSuggestion::from_res(ident.name, res)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
Scope::MacroUsePrelude => {
|
Scope::MacroUsePrelude => {
|
||||||
suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| {
|
suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| {
|
||||||
let res = binding.res();
|
let res = binding.res();
|
||||||
|
|
@ -439,8 +447,8 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
Scope::ToolPrelude => {
|
Scope::ToolPrelude => {
|
||||||
let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
|
let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
|
||||||
suggestions.extend(KNOWN_TOOLS.iter().map(|name| {
|
suggestions.extend(this.registered_tools.iter().map(|ident| {
|
||||||
TypoSuggestion::from_res(*name, res)
|
TypoSuggestion::from_res(ident.name, res)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Scope::StdLibPrelude => {
|
Scope::StdLibPrelude => {
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,6 @@ mod check_unused;
|
||||||
mod build_reduced_graph;
|
mod build_reduced_graph;
|
||||||
mod resolve_imports;
|
mod resolve_imports;
|
||||||
|
|
||||||
const KNOWN_TOOLS: &[Name] = &[sym::clippy, sym::rustfmt];
|
|
||||||
|
|
||||||
enum Weak {
|
enum Weak {
|
||||||
Yes,
|
Yes,
|
||||||
No,
|
No,
|
||||||
|
|
@ -102,6 +100,7 @@ enum Scope<'a> {
|
||||||
MacroRules(LegacyScope<'a>),
|
MacroRules(LegacyScope<'a>),
|
||||||
CrateRoot,
|
CrateRoot,
|
||||||
Module(Module<'a>),
|
Module(Module<'a>),
|
||||||
|
RegisteredAttrs,
|
||||||
MacroUsePrelude,
|
MacroUsePrelude,
|
||||||
BuiltinAttrs,
|
BuiltinAttrs,
|
||||||
LegacyPluginHelpers,
|
LegacyPluginHelpers,
|
||||||
|
|
@ -621,7 +620,6 @@ enum AmbiguityKind {
|
||||||
Import,
|
Import,
|
||||||
BuiltinAttr,
|
BuiltinAttr,
|
||||||
DeriveHelper,
|
DeriveHelper,
|
||||||
LegacyHelperVsPrelude,
|
|
||||||
LegacyVsModern,
|
LegacyVsModern,
|
||||||
GlobVsOuter,
|
GlobVsOuter,
|
||||||
GlobVsGlob,
|
GlobVsGlob,
|
||||||
|
|
@ -638,8 +636,6 @@ impl AmbiguityKind {
|
||||||
"built-in attribute vs any other name",
|
"built-in attribute vs any other name",
|
||||||
AmbiguityKind::DeriveHelper =>
|
AmbiguityKind::DeriveHelper =>
|
||||||
"derive helper attribute vs any other name",
|
"derive helper attribute vs any other name",
|
||||||
AmbiguityKind::LegacyHelperVsPrelude =>
|
|
||||||
"legacy plugin helper attribute vs name from prelude",
|
|
||||||
AmbiguityKind::LegacyVsModern =>
|
AmbiguityKind::LegacyVsModern =>
|
||||||
"`macro_rules` vs non-`macro_rules` from other module",
|
"`macro_rules` vs non-`macro_rules` from other module",
|
||||||
AmbiguityKind::GlobVsOuter =>
|
AmbiguityKind::GlobVsOuter =>
|
||||||
|
|
@ -916,6 +912,8 @@ pub struct Resolver<'a> {
|
||||||
crate_loader: CrateLoader<'a>,
|
crate_loader: CrateLoader<'a>,
|
||||||
macro_names: FxHashSet<Ident>,
|
macro_names: FxHashSet<Ident>,
|
||||||
builtin_macros: FxHashMap<Name, SyntaxExtension>,
|
builtin_macros: FxHashMap<Name, SyntaxExtension>,
|
||||||
|
registered_attrs: FxHashSet<Ident>,
|
||||||
|
registered_tools: FxHashSet<Ident>,
|
||||||
macro_use_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
|
macro_use_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
|
||||||
all_macros: FxHashMap<Name, Res>,
|
all_macros: FxHashMap<Name, Res>,
|
||||||
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
|
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
|
||||||
|
|
@ -1138,6 +1136,9 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (registered_attrs, registered_tools) =
|
||||||
|
macros::registered_attrs_and_tools(session, &krate.attrs);
|
||||||
|
|
||||||
let mut invocation_parent_scopes = FxHashMap::default();
|
let mut invocation_parent_scopes = FxHashMap::default();
|
||||||
invocation_parent_scopes.insert(ExpnId::root(), ParentScope::module(graph_root));
|
invocation_parent_scopes.insert(ExpnId::root(), ParentScope::module(graph_root));
|
||||||
|
|
||||||
|
|
@ -1207,6 +1208,8 @@ impl<'a> Resolver<'a> {
|
||||||
crate_loader: CrateLoader::new(session, metadata_loader, crate_name),
|
crate_loader: CrateLoader::new(session, metadata_loader, crate_name),
|
||||||
macro_names: FxHashSet::default(),
|
macro_names: FxHashSet::default(),
|
||||||
builtin_macros: Default::default(),
|
builtin_macros: Default::default(),
|
||||||
|
registered_attrs,
|
||||||
|
registered_tools,
|
||||||
macro_use_prelude: FxHashMap::default(),
|
macro_use_prelude: FxHashMap::default(),
|
||||||
all_macros: FxHashMap::default(),
|
all_macros: FxHashMap::default(),
|
||||||
macro_map: FxHashMap::default(),
|
macro_map: FxHashMap::default(),
|
||||||
|
|
@ -1484,6 +1487,7 @@ impl<'a> Resolver<'a> {
|
||||||
Scope::MacroRules(..) => true,
|
Scope::MacroRules(..) => true,
|
||||||
Scope::CrateRoot => true,
|
Scope::CrateRoot => true,
|
||||||
Scope::Module(..) => true,
|
Scope::Module(..) => true,
|
||||||
|
Scope::RegisteredAttrs => use_prelude,
|
||||||
Scope::MacroUsePrelude => use_prelude || rust_2015,
|
Scope::MacroUsePrelude => use_prelude || rust_2015,
|
||||||
Scope::BuiltinAttrs => true,
|
Scope::BuiltinAttrs => true,
|
||||||
Scope::LegacyPluginHelpers => use_prelude || rust_2015,
|
Scope::LegacyPluginHelpers => use_prelude || rust_2015,
|
||||||
|
|
@ -1528,11 +1532,12 @@ impl<'a> Resolver<'a> {
|
||||||
match ns {
|
match ns {
|
||||||
TypeNS => Scope::ExternPrelude,
|
TypeNS => Scope::ExternPrelude,
|
||||||
ValueNS => Scope::StdLibPrelude,
|
ValueNS => Scope::StdLibPrelude,
|
||||||
MacroNS => Scope::MacroUsePrelude,
|
MacroNS => Scope::RegisteredAttrs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Scope::RegisteredAttrs => Scope::MacroUsePrelude,
|
||||||
Scope::MacroUsePrelude => Scope::StdLibPrelude,
|
Scope::MacroUsePrelude => Scope::StdLibPrelude,
|
||||||
Scope::BuiltinAttrs => Scope::LegacyPluginHelpers,
|
Scope::BuiltinAttrs => Scope::LegacyPluginHelpers,
|
||||||
Scope::LegacyPluginHelpers => break, // nowhere else to search
|
Scope::LegacyPluginHelpers => break, // nowhere else to search
|
||||||
|
|
@ -1688,11 +1693,11 @@ impl<'a> Resolver<'a> {
|
||||||
if let Some(binding) = self.extern_prelude_get(ident, !record_used) {
|
if let Some(binding) = self.extern_prelude_get(ident, !record_used) {
|
||||||
return Some(LexicalScopeBinding::Item(binding));
|
return Some(LexicalScopeBinding::Item(binding));
|
||||||
}
|
}
|
||||||
}
|
if let Some(ident) = self.registered_tools.get(&ident) {
|
||||||
if ns == TypeNS && KNOWN_TOOLS.contains(&ident.name) {
|
let binding = (Res::ToolMod, ty::Visibility::Public,
|
||||||
let binding = (Res::ToolMod, ty::Visibility::Public,
|
ident.span, ExpnId::root()).to_name_binding(self.arenas);
|
||||||
DUMMY_SP, ExpnId::root()).to_name_binding(self.arenas);
|
return Some(LexicalScopeBinding::Item(binding));
|
||||||
return Some(LexicalScopeBinding::Item(binding));
|
}
|
||||||
}
|
}
|
||||||
if let Some(prelude) = self.prelude {
|
if let Some(prelude) = self.prelude {
|
||||||
if let Ok(binding) = self.resolve_ident_in_module_unadjusted(
|
if let Ok(binding) = self.resolve_ident_in_module_unadjusted(
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,17 @@
|
||||||
|
|
||||||
use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy};
|
use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy};
|
||||||
use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak};
|
use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak};
|
||||||
use crate::{ModuleKind, NameBinding, PathResult, Segment, ToNameBinding};
|
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
|
||||||
use crate::{ModuleOrUniformRoot, KNOWN_TOOLS};
|
|
||||||
use crate::Namespace::*;
|
use crate::Namespace::*;
|
||||||
use crate::resolve_imports::ImportResolver;
|
use crate::resolve_imports::ImportResolver;
|
||||||
use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
|
use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
|
||||||
use rustc::hir::def_id;
|
use rustc::hir::def_id;
|
||||||
use rustc::middle::stability;
|
use rustc::middle::stability;
|
||||||
|
use rustc::session::Session;
|
||||||
|
use rustc::util::nodemap::FxHashSet;
|
||||||
use rustc::{ty, lint, span_bug};
|
use rustc::{ty, lint, span_bug};
|
||||||
use syntax::ast::{self, NodeId, Ident};
|
use syntax::ast::{self, NodeId, Ident};
|
||||||
use syntax::attr::StabilityLevel;
|
use syntax::attr::{self, StabilityLevel};
|
||||||
use syntax::edition::Edition;
|
use syntax::edition::Edition;
|
||||||
use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
|
use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
|
||||||
use syntax::feature_gate::GateIssue;
|
use syntax::feature_gate::GateIssue;
|
||||||
|
|
@ -93,6 +94,46 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The code common between processing `#![register_tool]` and `#![register_attr]`.
|
||||||
|
fn registered_idents(
|
||||||
|
sess: &Session,
|
||||||
|
attrs: &[ast::Attribute],
|
||||||
|
attr_name: Symbol,
|
||||||
|
descr: &str,
|
||||||
|
) -> FxHashSet<Ident> {
|
||||||
|
let mut registered = FxHashSet::default();
|
||||||
|
for attr in attr::filter_by_name(attrs, attr_name) {
|
||||||
|
for nested_meta in attr.meta_item_list().unwrap_or_default() {
|
||||||
|
match nested_meta.ident() {
|
||||||
|
Some(ident) => if let Some(old_ident) = registered.replace(ident) {
|
||||||
|
let msg = format!("{} `{}` was already registered", descr, ident);
|
||||||
|
sess.struct_span_err(ident.span, &msg)
|
||||||
|
.span_label(old_ident.span, "already registered here").emit();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let msg = format!("`{}` only accepts identifiers", attr_name);
|
||||||
|
let span = nested_meta.span();
|
||||||
|
sess.struct_span_err(span, &msg).span_label(span, "not an identifier").emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registered
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn registered_attrs_and_tools(
|
||||||
|
sess: &Session,
|
||||||
|
attrs: &[ast::Attribute],
|
||||||
|
) -> (FxHashSet<Ident>, FxHashSet<Ident>) {
|
||||||
|
let registered_attrs = registered_idents(sess, attrs, sym::register_attr, "attribute");
|
||||||
|
let mut registered_tools = registered_idents(sess, attrs, sym::register_tool, "tool");
|
||||||
|
// We implicitly add `rustfmt` and `clippy` to known tools,
|
||||||
|
// but it's not an error to register them explicitly.
|
||||||
|
let predefined_tools = [sym::clippy, sym::rustfmt];
|
||||||
|
registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span));
|
||||||
|
(registered_attrs, registered_tools)
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> base::Resolver for Resolver<'a> {
|
impl<'a> base::Resolver for Resolver<'a> {
|
||||||
fn next_node_id(&mut self) -> NodeId {
|
fn next_node_id(&mut self) -> NodeId {
|
||||||
self.next_node_id()
|
self.next_node_id()
|
||||||
|
|
@ -416,10 +457,9 @@ impl<'a> Resolver<'a> {
|
||||||
struct Flags: u8 {
|
struct Flags: u8 {
|
||||||
const MACRO_RULES = 1 << 0;
|
const MACRO_RULES = 1 << 0;
|
||||||
const MODULE = 1 << 1;
|
const MODULE = 1 << 1;
|
||||||
const PRELUDE = 1 << 2;
|
const MISC_SUGGEST_CRATE = 1 << 2;
|
||||||
const MISC_SUGGEST_CRATE = 1 << 3;
|
const MISC_SUGGEST_SELF = 1 << 3;
|
||||||
const MISC_SUGGEST_SELF = 1 << 4;
|
const MISC_FROM_PRELUDE = 1 << 4;
|
||||||
const MISC_FROM_PRELUDE = 1 << 5;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -453,6 +493,10 @@ impl<'a> Resolver<'a> {
|
||||||
// Go through all the scopes and try to resolve the name.
|
// Go through all the scopes and try to resolve the name.
|
||||||
let break_result = self.visit_scopes(scope_set, parent_scope, orig_ident,
|
let break_result = self.visit_scopes(scope_set, parent_scope, orig_ident,
|
||||||
|this, scope, use_prelude, ident| {
|
|this, scope, use_prelude, ident| {
|
||||||
|
let ok = |res, span, arenas| Ok((
|
||||||
|
(res, ty::Visibility::Public, span, ExpnId::root()).to_name_binding(arenas),
|
||||||
|
Flags::empty(),
|
||||||
|
));
|
||||||
let result = match scope {
|
let result = match scope {
|
||||||
Scope::DeriveHelpers => {
|
Scope::DeriveHelpers => {
|
||||||
let mut result = Err(Determinacy::Determined);
|
let mut result = Err(Determinacy::Determined);
|
||||||
|
|
@ -461,10 +505,8 @@ impl<'a> Resolver<'a> {
|
||||||
match this.resolve_macro_path(derive, Some(MacroKind::Derive),
|
match this.resolve_macro_path(derive, Some(MacroKind::Derive),
|
||||||
parent_scope, true, force) {
|
parent_scope, true, force) {
|
||||||
Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) {
|
Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) {
|
||||||
let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
|
let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
|
||||||
ty::Visibility::Public, derive.span, ExpnId::root())
|
result = ok(res, derive.span, this.arenas);
|
||||||
.to_name_binding(this.arenas);
|
|
||||||
result = Ok((binding, Flags::empty()));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(_) | Err(Determinacy::Determined) => {}
|
Ok(_) | Err(Determinacy::Determined) => {}
|
||||||
|
|
@ -531,41 +573,39 @@ impl<'a> Resolver<'a> {
|
||||||
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
|
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Scope::RegisteredAttrs => match this.registered_attrs.get(&ident).cloned() {
|
||||||
|
Some(ident) => ok(
|
||||||
|
Res::NonMacroAttr(NonMacroAttrKind::Registered), ident.span, this.arenas
|
||||||
|
),
|
||||||
|
None => Err(Determinacy::Determined)
|
||||||
|
}
|
||||||
Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() {
|
Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() {
|
||||||
Some(binding) => Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
|
Some(binding) => Ok((binding, Flags::MISC_FROM_PRELUDE)),
|
||||||
None => Err(Determinacy::determined(
|
None => Err(Determinacy::determined(
|
||||||
this.graph_root.unexpanded_invocations.borrow().is_empty()
|
this.graph_root.unexpanded_invocations.borrow().is_empty()
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Scope::BuiltinAttrs => if is_builtin_attr_name(ident.name) {
|
Scope::BuiltinAttrs => if is_builtin_attr_name(ident.name) {
|
||||||
let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin),
|
ok(Res::NonMacroAttr(NonMacroAttrKind::Builtin), DUMMY_SP, this.arenas)
|
||||||
ty::Visibility::Public, DUMMY_SP, ExpnId::root())
|
|
||||||
.to_name_binding(this.arenas);
|
|
||||||
Ok((binding, Flags::PRELUDE))
|
|
||||||
} else {
|
} else {
|
||||||
Err(Determinacy::Determined)
|
Err(Determinacy::Determined)
|
||||||
}
|
}
|
||||||
Scope::LegacyPluginHelpers => if this.session.plugin_attributes.borrow().iter()
|
Scope::LegacyPluginHelpers => if this.session.plugin_attributes.borrow().iter()
|
||||||
.any(|(name, _)| ident.name == *name) {
|
.any(|(name, _)| ident.name == *name) {
|
||||||
let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
|
let res = Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper);
|
||||||
ty::Visibility::Public, DUMMY_SP, ExpnId::root())
|
ok(res, DUMMY_SP, this.arenas)
|
||||||
.to_name_binding(this.arenas);
|
|
||||||
Ok((binding, Flags::PRELUDE))
|
|
||||||
} else {
|
} else {
|
||||||
Err(Determinacy::Determined)
|
Err(Determinacy::Determined)
|
||||||
}
|
}
|
||||||
Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) {
|
Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) {
|
||||||
Some(binding) => Ok((binding, Flags::PRELUDE)),
|
Some(binding) => Ok((binding, Flags::empty())),
|
||||||
None => Err(Determinacy::determined(
|
None => Err(Determinacy::determined(
|
||||||
this.graph_root.unexpanded_invocations.borrow().is_empty()
|
this.graph_root.unexpanded_invocations.borrow().is_empty()
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
Scope::ToolPrelude => if KNOWN_TOOLS.contains(&ident.name) {
|
Scope::ToolPrelude => match this.registered_tools.get(&ident).cloned() {
|
||||||
let binding = (Res::ToolMod, ty::Visibility::Public, DUMMY_SP, ExpnId::root())
|
Some(ident) => ok(Res::ToolMod, ident.span, this.arenas),
|
||||||
.to_name_binding(this.arenas);
|
None => Err(Determinacy::Determined)
|
||||||
Ok((binding, Flags::PRELUDE))
|
|
||||||
} else {
|
|
||||||
Err(Determinacy::Determined)
|
|
||||||
}
|
}
|
||||||
Scope::StdLibPrelude => {
|
Scope::StdLibPrelude => {
|
||||||
let mut result = Err(Determinacy::Determined);
|
let mut result = Err(Determinacy::Determined);
|
||||||
|
|
@ -579,7 +619,7 @@ impl<'a> Resolver<'a> {
|
||||||
path_span,
|
path_span,
|
||||||
) {
|
) {
|
||||||
if use_prelude || this.is_builtin_macro(binding.res()) {
|
if use_prelude || this.is_builtin_macro(binding.res()) {
|
||||||
result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE));
|
result = Ok((binding, Flags::MISC_FROM_PRELUDE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -587,11 +627,7 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
Scope::BuiltinTypes => match this.primitive_type_table.primitive_types
|
Scope::BuiltinTypes => match this.primitive_type_table.primitive_types
|
||||||
.get(&ident.name).cloned() {
|
.get(&ident.name).cloned() {
|
||||||
Some(prim_ty) => {
|
Some(prim_ty) => ok(Res::PrimTy(prim_ty), DUMMY_SP, this.arenas),
|
||||||
let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public,
|
|
||||||
DUMMY_SP, ExpnId::root()).to_name_binding(this.arenas);
|
|
||||||
Ok((binding, Flags::PRELUDE))
|
|
||||||
}
|
|
||||||
None => Err(Determinacy::Determined)
|
None => Err(Determinacy::Determined)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -608,8 +644,6 @@ impl<'a> Resolver<'a> {
|
||||||
if res != innermost_res {
|
if res != innermost_res {
|
||||||
let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
|
let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
|
||||||
let derive_helper = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
|
let derive_helper = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
|
||||||
let legacy_helper =
|
|
||||||
Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper);
|
|
||||||
|
|
||||||
let ambiguity_error_kind = if is_import {
|
let ambiguity_error_kind = if is_import {
|
||||||
Some(AmbiguityKind::Import)
|
Some(AmbiguityKind::Import)
|
||||||
|
|
@ -617,11 +651,6 @@ impl<'a> Resolver<'a> {
|
||||||
Some(AmbiguityKind::BuiltinAttr)
|
Some(AmbiguityKind::BuiltinAttr)
|
||||||
} else if innermost_res == derive_helper || res == derive_helper {
|
} else if innermost_res == derive_helper || res == derive_helper {
|
||||||
Some(AmbiguityKind::DeriveHelper)
|
Some(AmbiguityKind::DeriveHelper)
|
||||||
} else if innermost_res == legacy_helper &&
|
|
||||||
flags.contains(Flags::PRELUDE) ||
|
|
||||||
res == legacy_helper &&
|
|
||||||
innermost_flags.contains(Flags::PRELUDE) {
|
|
||||||
Some(AmbiguityKind::LegacyHelperVsPrelude)
|
|
||||||
} else if innermost_flags.contains(Flags::MACRO_RULES) &&
|
} else if innermost_flags.contains(Flags::MACRO_RULES) &&
|
||||||
flags.contains(Flags::MODULE) &&
|
flags.contains(Flags::MODULE) &&
|
||||||
!this.disambiguate_legacy_vs_modern(innermost_binding,
|
!this.disambiguate_legacy_vs_modern(innermost_binding,
|
||||||
|
|
@ -681,20 +710,7 @@ impl<'a> Resolver<'a> {
|
||||||
return Ok(binding);
|
return Ok(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
let determinacy = Determinacy::determined(determinacy == Determinacy::Determined || force);
|
Err(Determinacy::determined(determinacy == Determinacy::Determined || force))
|
||||||
if determinacy == Determinacy::Determined && macro_kind == Some(MacroKind::Attr) &&
|
|
||||||
self.session.features_untracked().custom_attribute {
|
|
||||||
// For single-segment attributes interpret determinate "no resolution" as a custom
|
|
||||||
// attribute. (Lexical resolution implies the first segment and attr kind should imply
|
|
||||||
// the last segment, so we are certainly working with a single-segment attribute here.)
|
|
||||||
assert!(ns == MacroNS);
|
|
||||||
let binding = (Res::NonMacroAttr(NonMacroAttrKind::Custom),
|
|
||||||
ty::Visibility::Public, orig_ident.span, ExpnId::root())
|
|
||||||
.to_name_binding(self.arenas);
|
|
||||||
Ok(binding)
|
|
||||||
} else {
|
|
||||||
Err(determinacy)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn finalize_macro_resolutions(&mut self) {
|
crate fn finalize_macro_resolutions(&mut self) {
|
||||||
|
|
@ -705,16 +721,7 @@ impl<'a> Resolver<'a> {
|
||||||
// Make sure compilation does not succeed if preferred macro resolution
|
// Make sure compilation does not succeed if preferred macro resolution
|
||||||
// has changed after the macro had been expanded. In theory all such
|
// has changed after the macro had been expanded. In theory all such
|
||||||
// situations should be reported as ambiguity errors, so this is a bug.
|
// situations should be reported as ambiguity errors, so this is a bug.
|
||||||
if initial_res == Res::NonMacroAttr(NonMacroAttrKind::Custom) {
|
span_bug!(span, "inconsistent resolution for a macro");
|
||||||
// Yeah, legacy custom attributes are implemented using forced resolution
|
|
||||||
// (which is a best effort error recovery tool, basically), so we can't
|
|
||||||
// promise their resolution won't change later.
|
|
||||||
let msg = format!("inconsistent resolution for a macro: first {}, then {}",
|
|
||||||
initial_res.descr(), res.descr());
|
|
||||||
this.session.span_err(span, &msg);
|
|
||||||
} else {
|
|
||||||
span_bug!(span, "inconsistent resolution for a macro");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// It's possible that the macro was unresolved (indeterminate) and silently
|
// It's possible that the macro was unresolved (indeterminate) and silently
|
||||||
|
|
@ -826,7 +833,8 @@ impl<'a> Resolver<'a> {
|
||||||
res: Option<Res>, span: Span) {
|
res: Option<Res>, span: Span) {
|
||||||
if let Some(Res::NonMacroAttr(kind)) = res {
|
if let Some(Res::NonMacroAttr(kind)) = res {
|
||||||
if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) {
|
if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) {
|
||||||
let msg = format!("cannot use a {} through an import", kind.descr());
|
let msg =
|
||||||
|
format!("cannot use {} {} through an import", kind.article(), kind.descr());
|
||||||
let mut err = self.session.struct_span_err(span, &msg);
|
let mut err = self.session.struct_span_err(span, &msg);
|
||||||
if let Some(binding) = binding {
|
if let Some(binding) = binding {
|
||||||
err.span_note(binding.span, &format!("the {} imported here", kind.descr()));
|
err.span_note(binding.span, &format!("the {} imported here", kind.descr()));
|
||||||
|
|
|
||||||
|
|
@ -265,9 +265,6 @@ declare_features! (
|
||||||
/// Allows the use of SIMD types in functions declared in `extern` blocks.
|
/// Allows the use of SIMD types in functions declared in `extern` blocks.
|
||||||
(active, simd_ffi, "1.0.0", Some(27731), None),
|
(active, simd_ffi, "1.0.0", Some(27731), None),
|
||||||
|
|
||||||
/// Allows using custom attributes (RFC 572).
|
|
||||||
(active, custom_attribute, "1.0.0", Some(29642), None),
|
|
||||||
|
|
||||||
/// Allows using non lexical lifetimes (RFC 2094).
|
/// Allows using non lexical lifetimes (RFC 2094).
|
||||||
(active, nll, "1.0.0", Some(43234), None),
|
(active, nll, "1.0.0", Some(43234), None),
|
||||||
|
|
||||||
|
|
@ -526,6 +523,12 @@ declare_features! (
|
||||||
/// Allows using the `efiapi` ABI.
|
/// Allows using the `efiapi` ABI.
|
||||||
(active, abi_efiapi, "1.40.0", Some(65815), None),
|
(active, abi_efiapi, "1.40.0", Some(65815), None),
|
||||||
|
|
||||||
|
/// Allows using the `#[register_attr]` attribute.
|
||||||
|
(active, register_attr, "1.41.0", Some(66080), None),
|
||||||
|
|
||||||
|
/// Allows using the `#[register_attr]` attribute.
|
||||||
|
(active, register_tool, "1.41.0", Some(66079), None),
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// feature-group-end: actual feature gates
|
// feature-group-end: actual feature gates
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -329,6 +329,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
|
|
||||||
gated!(ffi_returns_twice, Whitelisted, template!(Word), experimental!(ffi_returns_twice)),
|
gated!(ffi_returns_twice, Whitelisted, template!(Word), experimental!(ffi_returns_twice)),
|
||||||
gated!(track_caller, Whitelisted, template!(Word), experimental!(track_caller)),
|
gated!(track_caller, Whitelisted, template!(Word), experimental!(track_caller)),
|
||||||
|
gated!(
|
||||||
|
register_attr, CrateLevel, template!(List: "attr1, attr2, ..."),
|
||||||
|
experimental!(register_attr),
|
||||||
|
),
|
||||||
|
gated!(
|
||||||
|
register_tool, CrateLevel, template!(List: "tool1, tool2, ..."),
|
||||||
|
experimental!(register_tool),
|
||||||
|
),
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Internal attributes: Stability, deprecation, and unsafe:
|
// Internal attributes: Stability, deprecation, and unsafe:
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,9 @@ declare_features! (
|
||||||
Some("merged into `#![feature(slice_patterns)]`")),
|
Some("merged into `#![feature(slice_patterns)]`")),
|
||||||
(removed, macro_reexport, "1.0.0", Some(29638), None,
|
(removed, macro_reexport, "1.0.0", Some(29638), None,
|
||||||
Some("subsumed by `pub use`")),
|
Some("subsumed by `pub use`")),
|
||||||
|
/// Allows using custom attributes (RFC 572).
|
||||||
|
(removed, custom_attribute, "1.0.0", Some(29642), None,
|
||||||
|
Some("removed in favor of `#![register_tool]` and `#![register_attr]`")),
|
||||||
(removed, pushpop_unsafe, "1.2.0", None, None, None),
|
(removed, pushpop_unsafe, "1.2.0", None, None, None),
|
||||||
(removed, needs_allocator, "1.4.0", Some(27389), None,
|
(removed, needs_allocator, "1.4.0", Some(27389), None,
|
||||||
Some("subsumed by `#![feature(allocator_internals)]`")),
|
Some("subsumed by `#![feature(allocator_internals)]`")),
|
||||||
|
|
|
||||||
|
|
@ -546,6 +546,8 @@ symbols! {
|
||||||
recursion_limit,
|
recursion_limit,
|
||||||
reexport_test_harness_main,
|
reexport_test_harness_main,
|
||||||
reflect,
|
reflect,
|
||||||
|
register_attr,
|
||||||
|
register_tool,
|
||||||
relaxed_adts,
|
relaxed_adts,
|
||||||
repr,
|
repr,
|
||||||
repr128,
|
repr128,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,15 @@
|
||||||
// ignore-stage1
|
// ignore-stage1
|
||||||
// compile-flags: -D crate-not-okay
|
// compile-flags: -D crate-not-okay
|
||||||
|
|
||||||
#![feature(plugin, custom_attribute, custom_inner_attributes, rustc_attrs)]
|
#![feature(plugin, register_attr, custom_inner_attributes, rustc_attrs)]
|
||||||
|
|
||||||
|
#![register_attr(
|
||||||
|
rustc_crate_okay,
|
||||||
|
rustc_crate_blue,
|
||||||
|
rustc_crate_red,
|
||||||
|
rustc_crate_grey,
|
||||||
|
rustc_crate_green,
|
||||||
|
)]
|
||||||
|
|
||||||
#![plugin(lint_for_crate_rpass)]
|
#![plugin(lint_for_crate_rpass)]
|
||||||
#![rustc_crate_okay]
|
#![rustc_crate_okay]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
|
warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
|
||||||
--> $DIR/issue-15778-pass.rs:8:1
|
--> $DIR/issue-15778-pass.rs:16:1
|
||||||
|
|
|
|
||||||
LL | #![plugin(lint_for_crate_rpass)]
|
LL | #![plugin(lint_for_crate_rpass)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
||||||
|
|
|
||||||
13
src/test/ui/attributes/register-attr-tool-fail.rs
Normal file
13
src/test/ui/attributes/register-attr-tool-fail.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#![feature(register_attr)]
|
||||||
|
#![feature(register_tool)]
|
||||||
|
|
||||||
|
#![register_attr] //~ ERROR malformed `register_attr` attribute input
|
||||||
|
#![register_tool] //~ ERROR malformed `register_tool` attribute input
|
||||||
|
|
||||||
|
#![register_attr(a::b)] //~ ERROR `register_attr` only accepts identifiers
|
||||||
|
#![register_tool(a::b)] //~ ERROR `register_tool` only accepts identifiers
|
||||||
|
|
||||||
|
#![register_attr(attr, attr)] //~ ERROR attribute `attr` was already registered
|
||||||
|
#![register_tool(tool, tool)] //~ ERROR tool `tool` was already registered
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
42
src/test/ui/attributes/register-attr-tool-fail.stderr
Normal file
42
src/test/ui/attributes/register-attr-tool-fail.stderr
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
error: `register_attr` only accepts identifiers
|
||||||
|
--> $DIR/register-attr-tool-fail.rs:7:18
|
||||||
|
|
|
||||||
|
LL | #![register_attr(a::b)]
|
||||||
|
| ^^^^ not an identifier
|
||||||
|
|
||||||
|
error: attribute `attr` was already registered
|
||||||
|
--> $DIR/register-attr-tool-fail.rs:10:24
|
||||||
|
|
|
||||||
|
LL | #![register_attr(attr, attr)]
|
||||||
|
| ---- ^^^^
|
||||||
|
| |
|
||||||
|
| already registered here
|
||||||
|
|
||||||
|
error: `register_tool` only accepts identifiers
|
||||||
|
--> $DIR/register-attr-tool-fail.rs:8:18
|
||||||
|
|
|
||||||
|
LL | #![register_tool(a::b)]
|
||||||
|
| ^^^^ not an identifier
|
||||||
|
|
||||||
|
error: tool `tool` was already registered
|
||||||
|
--> $DIR/register-attr-tool-fail.rs:11:24
|
||||||
|
|
|
||||||
|
LL | #![register_tool(tool, tool)]
|
||||||
|
| ---- ^^^^
|
||||||
|
| |
|
||||||
|
| already registered here
|
||||||
|
|
||||||
|
error: malformed `register_attr` attribute input
|
||||||
|
--> $DIR/register-attr-tool-fail.rs:4:1
|
||||||
|
|
|
||||||
|
LL | #![register_attr]
|
||||||
|
| ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[register_attr(attr1, attr2, ...)]`
|
||||||
|
|
||||||
|
error: malformed `register_tool` attribute input
|
||||||
|
--> $DIR/register-attr-tool-fail.rs:5:1
|
||||||
|
|
|
||||||
|
LL | #![register_tool]
|
||||||
|
| ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[register_tool(tool1, tool2, ...)]`
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
14
src/test/ui/attributes/register-attr-tool-import.rs
Normal file
14
src/test/ui/attributes/register-attr-tool-import.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
#![feature(register_attr)]
|
||||||
|
#![feature(register_tool)]
|
||||||
|
|
||||||
|
#![register_attr(attr)]
|
||||||
|
#![register_tool(tool)]
|
||||||
|
|
||||||
|
use attr as renamed_attr; // OK
|
||||||
|
use tool as renamed_tool; // OK
|
||||||
|
|
||||||
|
#[renamed_attr] //~ ERROR cannot use an explicitly registered attribute through an import
|
||||||
|
#[renamed_tool::attr] //~ ERROR cannot use a tool module through an import
|
||||||
|
fn main() {}
|
||||||
26
src/test/ui/attributes/register-attr-tool-import.stderr
Normal file
26
src/test/ui/attributes/register-attr-tool-import.stderr
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
error: cannot use an explicitly registered attribute through an import
|
||||||
|
--> $DIR/register-attr-tool-import.rs:12:3
|
||||||
|
|
|
||||||
|
LL | #[renamed_attr]
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the explicitly registered attribute imported here
|
||||||
|
--> $DIR/register-attr-tool-import.rs:9:5
|
||||||
|
|
|
||||||
|
LL | use attr as renamed_attr; // OK
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: cannot use a tool module through an import
|
||||||
|
--> $DIR/register-attr-tool-import.rs:13:3
|
||||||
|
|
|
||||||
|
LL | #[renamed_tool::attr]
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the tool module imported here
|
||||||
|
--> $DIR/register-attr-tool-import.rs:10:5
|
||||||
|
|
|
||||||
|
LL | use tool as renamed_tool; // OK
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
14
src/test/ui/attributes/register-attr-tool-prelude.rs
Normal file
14
src/test/ui/attributes/register-attr-tool-prelude.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#![feature(register_attr)]
|
||||||
|
#![feature(register_tool)]
|
||||||
|
|
||||||
|
#![register_attr(attr)]
|
||||||
|
#![register_tool(tool)]
|
||||||
|
|
||||||
|
#[no_implicit_prelude]
|
||||||
|
mod m {
|
||||||
|
#[attr] //~ ERROR cannot find attribute `attr` in this scope
|
||||||
|
#[tool::attr] //~ ERROR failed to resolve: use of undeclared type or module `tool`
|
||||||
|
fn check() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
15
src/test/ui/attributes/register-attr-tool-prelude.stderr
Normal file
15
src/test/ui/attributes/register-attr-tool-prelude.stderr
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0433]: failed to resolve: use of undeclared type or module `tool`
|
||||||
|
--> $DIR/register-attr-tool-prelude.rs:10:7
|
||||||
|
|
|
||||||
|
LL | #[tool::attr]
|
||||||
|
| ^^^^ use of undeclared type or module `tool`
|
||||||
|
|
||||||
|
error: cannot find attribute `attr` in this scope
|
||||||
|
--> $DIR/register-attr-tool-prelude.rs:9:7
|
||||||
|
|
|
||||||
|
LL | #[attr]
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0433`.
|
||||||
10
src/test/ui/attributes/register-attr-tool-unused.rs
Normal file
10
src/test/ui/attributes/register-attr-tool-unused.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#![deny(unused)]
|
||||||
|
|
||||||
|
#![feature(register_attr)]
|
||||||
|
#![feature(register_tool)]
|
||||||
|
|
||||||
|
#[register_attr(attr)] //~ ERROR crate-level attribute should be an inner attribute
|
||||||
|
//~| ERROR unused attribute
|
||||||
|
#[register_tool(tool)] //~ ERROR crate-level attribute should be an inner attribute
|
||||||
|
//~| ERROR unused attribute
|
||||||
|
fn main() {}
|
||||||
33
src/test/ui/attributes/register-attr-tool-unused.stderr
Normal file
33
src/test/ui/attributes/register-attr-tool-unused.stderr
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
error: unused attribute
|
||||||
|
--> $DIR/register-attr-tool-unused.rs:6:1
|
||||||
|
|
|
||||||
|
LL | #[register_attr(attr)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lint level defined here
|
||||||
|
--> $DIR/register-attr-tool-unused.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(unused)]
|
||||||
|
| ^^^^^^
|
||||||
|
= note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]`
|
||||||
|
|
||||||
|
error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
|
||||||
|
--> $DIR/register-attr-tool-unused.rs:6:1
|
||||||
|
|
|
||||||
|
LL | #[register_attr(attr)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unused attribute
|
||||||
|
--> $DIR/register-attr-tool-unused.rs:8:1
|
||||||
|
|
|
||||||
|
LL | #[register_tool(tool)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
|
||||||
|
--> $DIR/register-attr-tool-unused.rs:8:1
|
||||||
|
|
|
||||||
|
LL | #[register_tool(tool)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
19
src/test/ui/attributes/register-attr-tool.rs
Normal file
19
src/test/ui/attributes/register-attr-tool.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
// check-pass
|
||||||
|
// compile-flags: --cfg foo
|
||||||
|
|
||||||
|
#![feature(register_attr)]
|
||||||
|
#![feature(register_tool)]
|
||||||
|
|
||||||
|
#![register_attr(attr)]
|
||||||
|
#![register_tool(tool)]
|
||||||
|
#![register_tool(rustfmt, clippy)] // OK
|
||||||
|
#![cfg_attr(foo, register_attr(conditional_attr))]
|
||||||
|
#![cfg_attr(foo, register_tool(conditional_tool))]
|
||||||
|
|
||||||
|
#[attr]
|
||||||
|
#[tool::attr]
|
||||||
|
#[rustfmt::attr]
|
||||||
|
#[clippy::attr]
|
||||||
|
#[conditional_attr]
|
||||||
|
#[conditional_tool::attr]
|
||||||
|
fn main() {}
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
// This test ensures that attributes on formals in generic parameter
|
// This test ensures that attributes on formals in generic parameter
|
||||||
// lists are included when we are checking for unstable attributes.
|
// lists are included when we are checking for unstable attributes.
|
||||||
|
|
||||||
// gate-test-custom_attribute
|
|
||||||
|
|
||||||
struct StLt<#[lt_struct] 'a>(&'a u32);
|
struct StLt<#[lt_struct] 'a>(&'a u32);
|
||||||
//~^ ERROR cannot find attribute `lt_struct` in this scope
|
//~^ ERROR cannot find attribute `lt_struct` in this scope
|
||||||
struct StTy<#[ty_struct] I>(I);
|
struct StTy<#[ty_struct] I>(I);
|
||||||
|
|
|
||||||
|
|
@ -1,101 +1,101 @@
|
||||||
error: cannot find attribute `lt_hof` in this scope
|
error: cannot find attribute `lt_hof` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:53:21
|
--> $DIR/feature-gate-custom_attribute2.rs:51:21
|
||||||
|
|
|
|
||||||
LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
|
LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `ty_meth` in this scope
|
error: cannot find attribute `ty_meth` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:48:15
|
--> $DIR/feature-gate-custom_attribute2.rs:46:15
|
||||||
|
|
|
|
||||||
LL | fn m_ty<#[ty_meth] P>(_: P) { }
|
LL | fn m_ty<#[ty_meth] P>(_: P) { }
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `lt_meth` in this scope
|
error: cannot find attribute `lt_meth` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:46:15
|
--> $DIR/feature-gate-custom_attribute2.rs:44:15
|
||||||
|
|
|
|
||||||
LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
|
LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `ty_fn` in this scope
|
error: cannot find attribute `ty_fn` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:42:11
|
--> $DIR/feature-gate-custom_attribute2.rs:40:11
|
||||||
|
|
|
|
||||||
LL | fn f_ty<#[ty_fn] O>(_: O) { }
|
LL | fn f_ty<#[ty_fn] O>(_: O) { }
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `lt_fn` in this scope
|
error: cannot find attribute `lt_fn` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:40:11
|
--> $DIR/feature-gate-custom_attribute2.rs:38:11
|
||||||
|
|
|
|
||||||
LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
|
LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `ty_impl_for` in this scope
|
error: cannot find attribute `ty_impl_for` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:35:8
|
--> $DIR/feature-gate-custom_attribute2.rs:33:8
|
||||||
|
|
|
|
||||||
LL | impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
|
LL | impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `lt_impl_for` in this scope
|
error: cannot find attribute `lt_impl_for` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:31:8
|
--> $DIR/feature-gate-custom_attribute2.rs:29:8
|
||||||
|
|
|
|
||||||
LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
|
LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `ty_inherent` in this scope
|
error: cannot find attribute `ty_inherent` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:28:8
|
--> $DIR/feature-gate-custom_attribute2.rs:26:8
|
||||||
|
|
|
|
||||||
LL | impl<#[ty_inherent] M> StTy<M> { }
|
LL | impl<#[ty_inherent] M> StTy<M> { }
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `lt_inherent` in this scope
|
error: cannot find attribute `lt_inherent` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:26:8
|
--> $DIR/feature-gate-custom_attribute2.rs:24:8
|
||||||
|
|
|
|
||||||
LL | impl<#[lt_inherent] 'e> StLt<'e> { }
|
LL | impl<#[lt_inherent] 'e> StLt<'e> { }
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `ty_type` in this scope
|
error: cannot find attribute `ty_type` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:23:13
|
--> $DIR/feature-gate-custom_attribute2.rs:21:13
|
||||||
|
|
|
|
||||||
LL | type TyTy<#[ty_type] L> = (L, );
|
LL | type TyTy<#[ty_type] L> = (L, );
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `lt_type` in this scope
|
error: cannot find attribute `lt_type` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:21:13
|
--> $DIR/feature-gate-custom_attribute2.rs:19:13
|
||||||
|
|
|
|
||||||
LL | type TyLt<#[lt_type] 'd> = &'d u32;
|
LL | type TyLt<#[lt_type] 'd> = &'d u32;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `ty_trait` in this scope
|
error: cannot find attribute `ty_trait` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:18:14
|
--> $DIR/feature-gate-custom_attribute2.rs:16:14
|
||||||
|
|
|
|
||||||
LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
|
LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `lt_trait` in this scope
|
error: cannot find attribute `lt_trait` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:16:14
|
--> $DIR/feature-gate-custom_attribute2.rs:14:14
|
||||||
|
|
|
|
||||||
LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
|
LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `ty_enum` in this scope
|
error: cannot find attribute `ty_enum` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:13:13
|
--> $DIR/feature-gate-custom_attribute2.rs:11:13
|
||||||
|
|
|
|
||||||
LL | enum EnTy<#[ty_enum] J> { A(J), B }
|
LL | enum EnTy<#[ty_enum] J> { A(J), B }
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `lt_enum` in this scope
|
error: cannot find attribute `lt_enum` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:11:13
|
--> $DIR/feature-gate-custom_attribute2.rs:9:13
|
||||||
|
|
|
|
||||||
LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
|
LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `ty_struct` in this scope
|
error: cannot find attribute `ty_struct` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:8:15
|
--> $DIR/feature-gate-custom_attribute2.rs:6:15
|
||||||
|
|
|
|
||||||
LL | struct StTy<#[ty_struct] I>(I);
|
LL | struct StTy<#[ty_struct] I>(I);
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `lt_struct` in this scope
|
error: cannot find attribute `lt_struct` in this scope
|
||||||
--> $DIR/feature-gate-custom_attribute2.rs:6:15
|
--> $DIR/feature-gate-custom_attribute2.rs:4:15
|
||||||
|
|
|
|
||||||
LL | struct StLt<#[lt_struct] 'a>(&'a u32);
|
LL | struct StLt<#[lt_struct] 'a>(&'a u32);
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
3
src/test/ui/feature-gates/feature-gate-register_attr.rs
Normal file
3
src/test/ui/feature-gates/feature-gate-register_attr.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#![register_attr(attr)] //~ ERROR the `#[register_attr]` attribute is an experimental feature
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
12
src/test/ui/feature-gates/feature-gate-register_attr.stderr
Normal file
12
src/test/ui/feature-gates/feature-gate-register_attr.stderr
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0658]: the `#[register_attr]` attribute is an experimental feature
|
||||||
|
--> $DIR/feature-gate-register_attr.rs:1:1
|
||||||
|
|
|
||||||
|
LL | #![register_attr(attr)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: for more information, see https://github.com/rust-lang/rust/issues/66080
|
||||||
|
= help: add `#![feature(register_attr)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
3
src/test/ui/feature-gates/feature-gate-register_tool.rs
Normal file
3
src/test/ui/feature-gates/feature-gate-register_tool.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#![register_tool(tool)] //~ ERROR the `#[register_tool]` attribute is an experimental feature
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
12
src/test/ui/feature-gates/feature-gate-register_tool.stderr
Normal file
12
src/test/ui/feature-gates/feature-gate-register_tool.stderr
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0658]: the `#[register_tool]` attribute is an experimental feature
|
||||||
|
--> $DIR/feature-gate-register_tool.rs:1:1
|
||||||
|
|
|
||||||
|
LL | #![register_tool(tool)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: for more information, see https://github.com/rust-lang/rust/issues/66079
|
||||||
|
= help: add `#![feature(register_tool)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
// aux-build:derive-unstable-2.rs
|
// aux-build:derive-unstable-2.rs
|
||||||
|
|
||||||
#![feature(custom_attribute)]
|
#![feature(register_attr)]
|
||||||
|
|
||||||
|
#![register_attr(rustc_foo)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate derive_unstable_2;
|
extern crate derive_unstable_2;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0658]: attributes starting with `rustc` are reserved for use by the `rustc` compiler
|
error[E0658]: attributes starting with `rustc` are reserved for use by the `rustc` compiler
|
||||||
--> $DIR/expand-to-unstable-2.rs:8:10
|
--> $DIR/expand-to-unstable-2.rs:10:10
|
||||||
|
|
|
|
||||||
LL | #[derive(Unstable)]
|
LL | #[derive(Unstable)]
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,13 @@
|
||||||
// FIXME: https://github.com/rust-lang/rust/issues/41430
|
// FIXME: https://github.com/rust-lang/rust/issues/41430
|
||||||
// This is a temporary regression test for the ICE reported in #41211
|
// This is a temporary regression test for the ICE reported in #41211
|
||||||
|
|
||||||
#![feature(custom_attribute)]
|
|
||||||
#![feature(custom_inner_attributes)]
|
#![feature(custom_inner_attributes)]
|
||||||
|
#![feature(register_attr)]
|
||||||
|
|
||||||
|
#![register_attr(identity_attr)]
|
||||||
|
|
||||||
#![identity_attr]
|
#![identity_attr]
|
||||||
//~^ ERROR inconsistent resolution for a macro: first custom attribute, then attribute macro
|
//~^ ERROR `identity_attr` is ambiguous
|
||||||
extern crate test_macros;
|
extern crate test_macros;
|
||||||
use test_macros::identity_attr;
|
use test_macros::identity_attr;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,21 @@
|
||||||
error: inconsistent resolution for a macro: first custom attribute, then attribute macro
|
error[E0659]: `identity_attr` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
|
||||||
--> $DIR/issue-41211.rs:9:4
|
--> $DIR/issue-41211.rs:11:4
|
||||||
|
|
|
|
||||||
LL | #![identity_attr]
|
LL | #![identity_attr]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^ ambiguous name
|
||||||
|
|
|
||||||
|
note: `identity_attr` could refer to the attribute macro imported here
|
||||||
|
--> $DIR/issue-41211.rs:14:5
|
||||||
|
|
|
||||||
|
LL | use test_macros::identity_attr;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= help: use `crate::identity_attr` to refer to this attribute macro unambiguously
|
||||||
|
note: `identity_attr` could also refer to the explicitly registered attribute defined here
|
||||||
|
--> $DIR/issue-41211.rs:9:18
|
||||||
|
|
|
||||||
|
LL | #![register_attr(identity_attr)]
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0659`.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
// gate-test-custom_inner_attributes
|
// gate-test-custom_inner_attributes
|
||||||
|
|
||||||
#![feature(custom_attribute)]
|
#![feature(register_attr)]
|
||||||
|
|
||||||
|
#![register_attr(foo)]
|
||||||
|
|
||||||
#[foo]
|
#[foo]
|
||||||
mod foo {
|
mod foo {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0658]: non-builtin inner attributes are unstable
|
error[E0658]: non-builtin inner attributes are unstable
|
||||||
--> $DIR/issue-36530.rs:7:5
|
--> $DIR/issue-36530.rs:9:5
|
||||||
|
|
|
|
||||||
LL | #![foo]
|
LL | #![foo]
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue