about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-08-08 08:37:56 +0000
committerbors <bors@rust-lang.org>2018-08-08 08:37:56 +0000
commitffb09dfb3a9b252e26cd4f6570e9ff1b8a742edc (patch)
tree493e66a5c73fd6e5d81f7afcee1186c0ed106655 /src
parent52c785bfc24e43c668c9022cc1e79edcd6dcfd7c (diff)
parent50886115d7a7eba43b025e608aa156ef0e8dd7a8 (diff)
downloadrust-ffb09dfb3a9b252e26cd4f6570e9ff1b8a742edc.tar.gz
rust-ffb09dfb3a9b252e26cd4f6570e9ff1b8a742edc.zip
Auto merge of #53053 - petrochenkov:custattr, r=alexcrichton
resolve:  Support custom attributes when macro modularization is enabled

Basically, if resolution of a single-segment attribute is a determined error, then we interpret it as a custom attribute.

Since custom attributes are integrated into general macro resolution, `feature(custom_attribute)` now requires and implicitly enables macro modularization (`feature(use_extern_macros)`).
Actually, a few other "advanced" macro features now implicitly enable macro modularization too (and one bug was found and fixed in process of enabling it).

The first two commits are preliminary cleanups/refactorings.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/def.rs29
-rw-r--r--src/librustc/ich/impls_hir.rs9
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs6
-rw-r--r--src/librustc_resolve/lib.rs10
-rw-r--r--src/librustc_resolve/macros.rs168
-rw-r--r--src/librustc_save_analysis/lib.rs2
-rw-r--r--src/libsyntax/ext/base.rs16
-rw-r--r--src/libsyntax/ext/expand.rs71
-rw-r--r--src/libsyntax/feature_gate.rs61
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/attr-invalid-exprs.rs2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/attr-stmt-expr.rs2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/lints_in_proc_macros.rs2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs6
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates2.rs2
-rw-r--r--src/test/compile-fail/macro-with-seps-err-msg.rs4
-rw-r--r--src/test/compile-fail/macros-in-extern.rs6
-rw-r--r--src/test/compile-fail/stmt_expr_attrs_no_feature.rs2
-rw-r--r--src/test/compile-fail/unknown-tool-name.rs2
-rw-r--r--src/test/pretty/attr-literals.rs2
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs2
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/hello_macro.rs2
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs2
-rw-r--r--src/test/run-pass-fulldeps/macro-quote-cond.rs2
-rw-r--r--src/test/run-pass-fulldeps/macro-quote-test.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/bang-macro.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/call-site.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/derive-b.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc_macro.rs2
-rw-r--r--src/test/ui-fulldeps/auxiliary/attr_proc_macro.rs2
-rw-r--r--src/test/ui-fulldeps/auxiliary/bang_proc_macro.rs2
-rw-r--r--src/test/ui-fulldeps/auxiliary/lifetimes.rs1
-rw-r--r--src/test/ui-fulldeps/lifetimes.rs2
-rw-r--r--src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs1
-rw-r--r--src/test/ui-fulldeps/proc-macro/generate-mod.rs2
-rw-r--r--src/test/ui-fulldeps/proc-macro/invalid-attributes.rs1
-rw-r--r--src/test/ui-fulldeps/proc-macro/invalid-attributes.stderr12
-rw-r--r--src/test/ui-fulldeps/proc-macro/macro-namespace-reserved.rs2
-rw-r--r--src/test/ui-fulldeps/proc-macro/non-root.rs1
-rw-r--r--src/test/ui-fulldeps/proc-macro/non-root.stderr2
-rw-r--r--src/test/ui-fulldeps/proc-macro/three-equals.rs2
-rw-r--r--src/test/ui-fulldeps/resolve-error.rs8
-rw-r--r--src/test/ui-fulldeps/resolve-error.stderr28
-rw-r--r--src/test/ui/custom-attribute-multisegment.rs (renamed from src/test/compile-fail-fulldeps/proc-macro/proc-macro-custom-attr-mutex.rs)19
-rw-r--r--src/test/ui/custom-attribute-multisegment.stderr9
-rw-r--r--src/test/ui/feature-gate-macros_in_extern.rs6
-rw-r--r--src/test/ui/feature-gate-macros_in_extern.stderr6
-rw-r--r--src/test/ui/imports/macros.rs2
-rw-r--r--src/test/ui/issue-11692-2.rs2
-rw-r--r--src/test/ui/issue-11692-2.stderr2
-rw-r--r--src/test/ui/macro-path-prelude-fail-3.rs4
-rw-r--r--src/test/ui/macro-path-prelude-fail-3.stderr8
-rw-r--r--src/test/ui/tool-attributes-disabled-2.rs6
-rw-r--r--src/test/ui/tool-attributes-disabled-2.stderr11
-rw-r--r--src/test/ui/tool-attributes-misplaced-1.rs8
-rw-r--r--src/test/ui/tool-attributes-misplaced-1.stderr16
-rw-r--r--src/test/ui/tool-attributes-misplaced-2.rs4
-rw-r--r--src/test/ui/tool-attributes-misplaced-2.stderr8
66 files changed, 295 insertions, 320 deletions
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index b297accc75f..4a14223eb88 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -29,6 +29,18 @@ pub enum CtorKind {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum NonMacroAttrKind {
+    /// Single-segment attribute defined by the language (`#[inline]`)
+    Builtin,
+    /// Multi-segment custom attribute living in a "tool module" (`#[rustfmt::skip]`).
+    Tool,
+    /// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`).
+    DeriveHelper,
+    /// Single-segment custom attribute not registered in any way (`#[my_attr]`).
+    Custom,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum Def {
     // Type namespace
     Mod(DefId),
@@ -68,7 +80,7 @@ pub enum Def {
 
     // Macro namespace
     Macro(DefId, MacroKind),
-    NonMacroAttr, // e.g. `#[inline]` or `#[rustfmt::skip]`
+    NonMacroAttr(NonMacroAttrKind), // e.g. `#[inline]` or `#[rustfmt::skip]`
 
     // Both namespaces
     Err,
@@ -240,6 +252,17 @@ impl CtorKind {
     }
 }
 
+impl NonMacroAttrKind {
+    fn descr(self) -> &'static str {
+        match self {
+            NonMacroAttrKind::Builtin => "built-in attribute",
+            NonMacroAttrKind::Tool => "tool attribute",
+            NonMacroAttrKind::DeriveHelper => "derive helper attribute",
+            NonMacroAttrKind::Custom => "custom attribute",
+        }
+    }
+}
+
 impl Def {
     pub fn def_id(&self) -> DefId {
         match *self {
@@ -259,7 +282,7 @@ impl Def {
             Def::PrimTy(..) |
             Def::SelfTy(..) |
             Def::ToolMod |
-            Def::NonMacroAttr |
+            Def::NonMacroAttr(..) |
             Def::Err => {
                 bug!("attempted .def_id() on invalid def: {:?}", self)
             }
@@ -300,7 +323,7 @@ impl Def {
             Def::SelfTy(..) => "self type",
             Def::Macro(.., macro_kind) => macro_kind.descr(),
             Def::ToolMod => "tool module",
-            Def::NonMacroAttr => "non-macro attribute",
+            Def::NonMacroAttr(attr_kind) => attr_kind.descr(),
             Def::Err => "unresolved item",
         }
     }
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 53bd7106e96..76e57558bfe 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -990,6 +990,13 @@ impl_stable_hash_for!(enum hir::def::CtorKind {
     Fictive
 });
 
+impl_stable_hash_for!(enum hir::def::NonMacroAttrKind {
+    Builtin,
+    Tool,
+    DeriveHelper,
+    Custom,
+});
+
 impl_stable_hash_for!(enum hir::def::Def {
     Mod(def_id),
     Struct(def_id),
@@ -1018,7 +1025,7 @@ impl_stable_hash_for!(enum hir::def::Def {
     Label(node_id),
     Macro(def_id, macro_kind),
     ToolMod,
-    NonMacroAttr,
+    NonMacroAttr(attr_kind),
     Err
 });
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index c782f2072b9..0be1bf3011e 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -630,8 +630,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
     pub fn get_macro(&mut self, def: Def) -> Lrc<SyntaxExtension> {
         let def_id = match def {
             Def::Macro(def_id, ..) => def_id,
-            Def::NonMacroAttr => return Lrc::new(SyntaxExtension::NonMacroAttr),
-            _ => panic!("Expected Def::Macro(..) or Def::NonMacroAttr"),
+            Def::NonMacroAttr(attr_kind) => return Lrc::new(SyntaxExtension::NonMacroAttr {
+                mark_used: attr_kind == NonMacroAttrKind::Tool,
+            }),
+            _ => panic!("expected `Def::Macro` or `Def::NonMacroAttr`"),
         };
         if let Some(ext) = self.macro_map.get(&def_id) {
             return ext.clone();
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index a7fcc89f6b9..d96967725f4 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -3485,8 +3485,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
             let binding = if let Some(module) = module {
                 self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
             } else if opt_ns == Some(MacroNS) {
-                self.resolve_lexical_macro_path_segment(ident, ns, record_used, path_span)
-                    .map(MacroBinding::binding)
+                assert!(ns == TypeNS);
+                self.resolve_lexical_macro_path_segment(ident, ns, record_used, record_used,
+                                                        false, path_span).map(MacroBinding::binding)
             } else {
                 let record_used_id =
                     if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };
@@ -3514,7 +3515,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                     if let Some(next_module) = binding.module() {
                         module = Some(next_module);
                     } else if def == Def::ToolMod && i + 1 != path.len() {
-                        return PathResult::NonModule(PathResolution::new(Def::NonMacroAttr))
+                        let def = Def::NonMacroAttr(NonMacroAttrKind::Tool);
+                        return PathResult::NonModule(PathResolution::new(def));
                     } else if def == Def::Err {
                         return PathResult::NonModule(err_path_resolution());
                     } else if opt_ns.is_some() && (is_last || maybe_assoc) {
@@ -4548,6 +4550,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
             let result = self.resolve_lexical_macro_path_segment(ident,
                                                                  MacroNS,
                                                                  false,
+                                                                 false,
+                                                                 true,
                                                                  attr.path.span);
             if let Ok(binding) = result {
                 if let SyntaxExtension::AttrProcMacro(..) = *binding.binding().get_macro(self) {
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 993874d7c0b..d680b2d9f7d 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -15,18 +15,17 @@ use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
 use resolve_imports::ImportResolver;
 use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex,
                          DefIndexAddressSpace};
-use rustc::hir::def::{Def, Export};
+use rustc::hir::def::{Def, Export, NonMacroAttrKind};
 use rustc::hir::map::{self, DefCollector};
 use rustc::{ty, lint};
 use rustc::middle::cstore::CrateStore;
 use syntax::ast::{self, Name, Ident};
-use syntax::attr::{self, HasAttrs};
+use syntax::attr;
 use syntax::errors::DiagnosticBuilder;
-use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator};
+use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
 use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver};
-use syntax::ext::expand::{self, AstFragment, AstFragmentKind, Invocation, InvocationKind};
+use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
 use syntax::ext::hygiene::{self, Mark};
-use syntax::ext::placeholders::placeholder;
 use syntax::ext::tt::macro_rules;
 use syntax::feature_gate::{self, feature_err, emit_feature_err, is_builtin_attr_name, GateIssue};
 use syntax::fold::{self, Folder};
@@ -320,7 +319,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
         None
     }
 
-    fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
+    fn resolve_invoc(&mut self, invoc: &Invocation, scope: Mark, force: bool)
                      -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
         let def = match invoc.kind {
             InvocationKind::Attr { attr: None, .. } => return Ok(None),
@@ -329,17 +328,37 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
         if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
             self.report_proc_macro_stub(invoc.span());
             return Err(Determinacy::Determined);
-        } else if let Def::NonMacroAttr = def {
-            if let InvocationKind::Attr { .. } = invoc.kind {
-                if !self.session.features_untracked().tool_attributes {
-                    feature_err(&self.session.parse_sess, "tool_attributes",
-                                invoc.span(), GateIssue::Language,
-                                "tool attributes are unstable").emit();
+        } else if let Def::NonMacroAttr(attr_kind) = def {
+            // Note that not only attributes, but anything in macro namespace can result in a
+            // `Def::NonMacroAttr` definition (e.g. `inline!()`), so we must report the error
+            // below for these cases.
+            let is_attr_invoc =
+                if let InvocationKind::Attr { .. } = invoc.kind { true } else { false };
+            let path = invoc.path().expect("no path for non-macro attr");
+            match attr_kind {
+                NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper |
+                NonMacroAttrKind::Custom if is_attr_invoc => {
+                    if attr_kind == NonMacroAttrKind::Tool &&
+                       !self.session.features_untracked().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();
+                    }
+                    return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr {
+                        mark_used: attr_kind == NonMacroAttrKind::Tool,
+                    })));
+                }
+                _ => {
+                    self.report_non_macro_attr(path.span, def);
+                    return Err(Determinacy::Determined);
                 }
-                return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr)));
-            } else {
-                self.report_non_macro_attr(invoc.path_span());
-                return Err(Determinacy::Determined);
             }
         }
         let def_id = def.def_id();
@@ -363,8 +382,8 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
             if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
                 self.report_proc_macro_stub(path.span);
                 return Err(Determinacy::Determined);
-            } else if let Def::NonMacroAttr = def {
-                self.report_non_macro_attr(path.span);
+            } else if let Def::NonMacroAttr(..) = def {
+                self.report_non_macro_attr(path.span, def);
                 return Err(Determinacy::Determined);
             }
             self.unused_macros.remove(&def.def_id());
@@ -396,15 +415,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                               "can't use a procedural macro from the same crate that defines it");
     }
 
-    fn report_non_macro_attr(&self, span: Span) {
-        self.session.span_err(span,
-                              "expected a macro, found non-macro attribute");
+    fn report_non_macro_attr(&self, span: Span, def: Def) {
+        self.session.span_err(span, &format!("expected a macro, found {}", def.kind_name()));
     }
 
-    fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
+    fn resolve_invoc_to_def(&mut self, invoc: &Invocation, scope: Mark, force: bool)
                             -> Result<Def, Determinacy> {
-        let (attr, traits, item) = match invoc.kind {
-            InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item),
+        let (attr, traits) = match invoc.kind {
+            InvocationKind::Attr { ref attr, ref traits, .. } => (attr, traits),
             InvocationKind::Bang { ref mac, .. } => {
                 return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force);
             }
@@ -413,62 +431,43 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             }
         };
 
-
         let path = attr.as_ref().unwrap().path.clone();
-        let mut determinacy = Determinacy::Determined;
-        match self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force) {
-            Ok(def) => return Ok(def),
-            Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined,
-            Err(Determinacy::Determined) if force => return Err(Determinacy::Determined),
-            Err(Determinacy::Determined) => {}
+        let def = self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force);
+        if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = def {} else {
+            return def;
         }
 
-        // Ok at this point we've determined that the `attr` above doesn't
-        // actually resolve at this time, so we may want to report an error.
-        // It could be the case, though, that `attr` won't ever resolve! If
-        // there's a custom derive that could be used it might declare `attr` as
-        // a custom attribute accepted by the derive. In this case we don't want
-        // to report this particular invocation as unresolved, but rather we'd
-        // want to move on to the next invocation.
+        // At this point we've found that the `attr` is determinately unresolved and thus can be
+        // interpreted as a custom attribute. Normally custom attributes are feature gated, but
+        // it may be a custom attribute whitelisted by a derive macro and they do not require
+        // a feature gate.
         //
-        // This loop here looks through all of the derive annotations in scope
-        // and tries to resolve them. If they themselves successfully resolve
-        // *and* the resolve mentions that this attribute's name is a registered
-        // custom attribute then we flag this attribute as known and update
-        // `invoc` above to point to the next invocation.
-        //
-        // By then returning `Undetermined` we should continue resolution to
-        // resolve the next attribute.
-        let attr_name = match path.segments.len() {
-            1 => path.segments[0].ident.name,
-            _ => return Err(determinacy),
-        };
+        // So here we look through all of the derive annotations in scope and try to resolve them.
+        // If they themselves successfully resolve *and* one of the resolved derive macros
+        // whitelists this attribute's name, then this is a registered attribute and we can convert
+        // it from a "generic custom attrite" into a "known derive helper attribute".
+        enum ConvertToDeriveHelper { Yes, No, DontKnow }
+        let mut convert_to_derive_helper = ConvertToDeriveHelper::No;
+        let attr_name = path.segments[0].ident.name;
         for path in traits {
             match self.resolve_macro(scope, path, MacroKind::Derive, force) {
                 Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext {
                     if inert_attrs.contains(&attr_name) {
-                        // FIXME(jseyfried) Avoid `mem::replace` here.
-                        let dummy_item = placeholder(AstFragmentKind::Items, ast::DUMMY_NODE_ID)
-                            .make_items().pop().unwrap();
-                        let dummy_item = Annotatable::Item(dummy_item);
-                        *item = mem::replace(item, dummy_item).map_attrs(|mut attrs| {
-                            let inert_attr = attr.take().unwrap();
-                            attr::mark_known(&inert_attr);
-                            if self.use_extern_macros {
-                                *attr = expand::find_attr_invoc(&mut attrs);
-                            }
-                            attrs.push(inert_attr);
-                            attrs
-                        });
-                        return Err(Determinacy::Undetermined)
+                        convert_to_derive_helper = ConvertToDeriveHelper::Yes;
+                        break
                     }
                 },
-                Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined,
+                Err(Determinacy::Undetermined) =>
+                    convert_to_derive_helper = ConvertToDeriveHelper::DontKnow,
                 Err(Determinacy::Determined) => {}
             }
         }
 
-        Err(determinacy)
+        match convert_to_derive_helper {
+            ConvertToDeriveHelper::Yes => Ok(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)),
+            ConvertToDeriveHelper::No => def,
+            ConvertToDeriveHelper::DontKnow => Err(Determinacy::determined(force)),
+        }
     }
 
     fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
@@ -481,7 +480,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                                       "generic arguments in macro path");
             });
         }
-        if kind != MacroKind::Bang && path.segments.len() > 1 && def != Ok(Def::NonMacroAttr) {
+        if kind != MacroKind::Bang && path.segments.len() > 1 &&
+           def != Ok(Def::NonMacroAttr(NonMacroAttrKind::Tool)) {
             if !self.session.features_untracked().proc_macro_path_invoc {
                 emit_feature_err(
                     &self.session.parse_sess,
@@ -550,10 +550,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution {
             Ok(Def::Macro(binding.def_id, MacroKind::Bang))
         } else {
-            match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, span) {
+            match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, force,
+                                                          kind == MacroKind::Attr, span) {
                 Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()),
-                Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined),
-                Err(_) => {
+                Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
+                Err(Determinacy::Determined) => {
                     self.found_unresolved_macro = true;
                     Err(Determinacy::Determined)
                 }
@@ -574,6 +575,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                                               mut ident: Ident,
                                               ns: Namespace,
                                               record_used: bool,
+                                              force: bool,
+                                              is_attr: bool,
                                               path_span: Span)
                                               -> Result<MacroBinding<'a>, Determinacy> {
         // General principles:
@@ -604,6 +607,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         // 3. Builtin attributes (closed, controlled).
 
         assert!(ns == TypeNS  || ns == MacroNS);
+        assert!(force || !record_used); // `record_used` implies `force`
         ident = ident.modern();
 
         // Names from inner scope that can't shadow names from outer scopes, e.g.
@@ -647,8 +651,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                 }
                 WhereToResolve::BuiltinAttrs => {
                     if is_builtin_attr_name(ident.name) {
-                        let binding = (Def::NonMacroAttr, ty::Visibility::Public,
-                                       ident.span, Mark::root()).to_name_binding(self.arenas);
+                        let binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
+                                       ty::Visibility::Public, ident.span, Mark::root())
+                                       .to_name_binding(self.arenas);
                         Ok(MacroBinding::Global(binding))
                     } else {
                         Err(Determinacy::Determined)
@@ -776,7 +781,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                 Err(Determinacy::Determined) => {
                     continue_search!();
                 }
-                Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
+                Err(Determinacy::Undetermined) => return Err(Determinacy::determined(force)),
             }
         }
 
@@ -785,7 +790,19 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             return Ok(previous_result);
         }
 
-        if record_used { Err(Determinacy::Determined) } else { Err(Determinacy::Undetermined) }
+        let determinacy = Determinacy::determined(force);
+        if determinacy == Determinacy::Determined && is_attr {
+            // For single-segment attributes interpret determinate "no resolution" as a custom
+            // attribute. (Lexical resolution implies the first segment and is_attr should imply
+            // the last segment, so we are certainly working with a single-segment attribute here.)
+            assert!(ns == MacroNS);
+            let binding = (Def::NonMacroAttr(NonMacroAttrKind::Custom),
+                           ty::Visibility::Public, ident.span, Mark::root())
+                           .to_name_binding(self.arenas);
+            Ok(MacroBinding::Global(binding))
+        } else {
+            Err(determinacy)
+        }
     }
 
     pub fn resolve_legacy_scope(&mut self,
@@ -869,7 +886,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             let span = ident.span;
             let legacy_scope = &self.invocations[&mark].legacy_scope;
             let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident, true);
-            let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, span);
+            let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, true,
+                                                                     kind == MacroKind::Attr, span);
 
             let check_consistency = |this: &Self, binding: MacroBinding| {
                 if let Some(def) = def {
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 3fada8d4aa8..703489f56c1 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -811,7 +811,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             HirDef::Label(..) |
             HirDef::Macro(..) |
             HirDef::ToolMod |
-            HirDef::NonMacroAttr |
+            HirDef::NonMacroAttr(..) |
             HirDef::Err => None,
         }
     }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 8450daa3f7c..de391ee4219 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -589,7 +589,7 @@ impl MacroKind {
 /// An enum representing the different kinds of syntax extensions.
 pub enum SyntaxExtension {
     /// A trivial "extension" that does nothing, only keeps the attribute and marks it as known.
-    NonMacroAttr,
+    NonMacroAttr { mark_used: bool },
 
     /// A syntax extension that is attached to an item and creates new items
     /// based upon it.
@@ -670,7 +670,7 @@ impl SyntaxExtension {
             SyntaxExtension::IdentTT(..) |
             SyntaxExtension::ProcMacro { .. } =>
                 MacroKind::Bang,
-            SyntaxExtension::NonMacroAttr |
+            SyntaxExtension::NonMacroAttr { .. } |
             SyntaxExtension::MultiDecorator(..) |
             SyntaxExtension::MultiModifier(..) |
             SyntaxExtension::AttrProcMacro(..) =>
@@ -700,7 +700,7 @@ impl SyntaxExtension {
             SyntaxExtension::AttrProcMacro(.., edition) |
             SyntaxExtension::ProcMacroDerive(.., edition) => edition,
             // Unstable legacy stuff
-            SyntaxExtension::NonMacroAttr |
+            SyntaxExtension::NonMacroAttr { .. } |
             SyntaxExtension::IdentTT(..) |
             SyntaxExtension::MultiDecorator(..) |
             SyntaxExtension::MultiModifier(..) |
@@ -726,7 +726,7 @@ pub trait Resolver {
     fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<Attribute>, allow_derive: bool)
                               -> Option<Attribute>;
 
-    fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
+    fn resolve_invoc(&mut self, invoc: &Invocation, scope: Mark, force: bool)
                      -> Result<Option<Lrc<SyntaxExtension>>, Determinacy>;
     fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
                      -> Result<Lrc<SyntaxExtension>, Determinacy>;
@@ -739,6 +739,12 @@ pub enum Determinacy {
     Undetermined,
 }
 
+impl Determinacy {
+    pub fn determined(determined: bool) -> Determinacy {
+        if determined { Determinacy::Determined } else { Determinacy::Undetermined }
+    }
+}
+
 pub struct DummyResolver;
 
 impl Resolver for DummyResolver {
@@ -754,7 +760,7 @@ impl Resolver for DummyResolver {
     fn resolve_imports(&mut self) {}
     fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>, _allow_derive: bool)
                               -> Option<Attribute> { None }
-    fn resolve_invoc(&mut self, _invoc: &mut Invocation, _scope: Mark, _force: bool)
+    fn resolve_invoc(&mut self, _invoc: &Invocation, _scope: Mark, _force: bool)
                      -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
         Err(Determinacy::Determined)
     }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 8bd30e43476..12941a85669 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -244,19 +244,12 @@ impl Invocation {
         }
     }
 
-    pub fn path_span(&self) -> Span {
+    pub fn path(&self) -> Option<&Path> {
         match self.kind {
-            InvocationKind::Bang { ref mac, .. } => mac.node.path.span,
-            InvocationKind::Attr { attr: Some(ref attr), .. } => attr.path.span,
-            InvocationKind::Attr { attr: None, .. } => DUMMY_SP,
-            InvocationKind::Derive { ref path, .. } => path.span,
-        }
-    }
-
-    pub fn attr_id(&self) -> Option<ast::AttrId> {
-        match self.kind {
-            InvocationKind::Attr { attr: Some(ref attr), .. } => Some(attr.id),
-            _ => None,
+            InvocationKind::Bang { ref mac, .. } => Some(&mac.node.path),
+            InvocationKind::Attr { attr: Some(ref attr), .. } => Some(&attr.path),
+            InvocationKind::Attr { attr: None, .. } => None,
+            InvocationKind::Derive { ref path, .. } => Some(path),
         }
     }
 }
@@ -338,7 +331,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let mut undetermined_invocations = Vec::new();
         let (mut progress, mut force) = (false, !self.monotonic);
         loop {
-            let mut invoc = if let Some(invoc) = invocations.pop() {
+            let invoc = if let Some(invoc) = invocations.pop() {
                 invoc
             } else {
                 self.resolve_imports();
@@ -350,20 +343,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
             let scope =
                 if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
-            let attr_id_before = invoc.attr_id();
-            let ext = match self.cx.resolver.resolve_invoc(&mut invoc, scope, force) {
+            let ext = match self.cx.resolver.resolve_invoc(&invoc, scope, force) {
                 Ok(ext) => Some(ext),
                 Err(Determinacy::Determined) => None,
                 Err(Determinacy::Undetermined) => {
-                    // Sometimes attributes which we thought were invocations
-                    // end up being custom attributes for custom derives. If
-                    // that's the case our `invoc` will have changed out from
-                    // under us. If this is the case we're making progress so we
-                    // want to flag it as such, and we test this by looking if
-                    // the `attr_id()` method has been changing over time.
-                    if invoc.attr_id() != attr_id_before {
-                        progress = true;
-                    }
                     undetermined_invocations.push(invoc);
                     continue
                 }
@@ -533,6 +516,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     }
 
     fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option<AstFragment> {
+        if invoc.fragment_kind == AstFragmentKind::ForeignItems &&
+           !self.cx.ecfg.macros_in_extern_enabled() {
+            if let SyntaxExtension::NonMacroAttr { .. } = *ext {} else {
+                emit_feature_err(&self.cx.parse_sess, "macros_in_extern",
+                                 invoc.span(), GateIssue::Language,
+                                 "macro invocations in `extern {}` blocks are experimental");
+            }
+        }
+
         let result = match invoc.kind {
             InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext)?,
             InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext)?,
@@ -565,7 +557,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             _ => unreachable!(),
         };
 
-        attr::mark_used(&attr);
+        if let NonMacroAttr { mark_used: false } = *ext {} else {
+            // Macro attrs are always used when expanded,
+            // non-macro attrs are considered used when the field says so.
+            attr::mark_used(&attr);
+        }
         invoc.expansion_data.mark.set_expn_info(ExpnInfo {
             call_site: attr.span,
             def_site: None,
@@ -577,7 +573,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         });
 
         match *ext {
-            NonMacroAttr => {
+            NonMacroAttr { .. } => {
                 attr::mark_known(&attr);
                 let item = item.map_attrs(|mut attrs| { attrs.push(attr); attrs });
                 Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item)))
@@ -827,7 +823,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             }
 
             MultiDecorator(..) | MultiModifier(..) |
-            AttrProcMacro(..) | SyntaxExtension::NonMacroAttr => {
+            AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => {
                 self.cx.span_err(path.span,
                                  &format!("`{}` can only be used in attributes", path));
                 self.cx.trace_macros_diag();
@@ -1497,20 +1493,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                          foreign_item: ast::ForeignItem) -> SmallVector<ast::ForeignItem> {
         let (attr, traits, foreign_item) = self.classify_item(foreign_item);
 
-        let explain = if self.cx.ecfg.use_extern_macros_enabled() {
-            feature_gate::EXPLAIN_PROC_MACROS_IN_EXTERN
-        } else {
-            feature_gate::EXPLAIN_MACROS_IN_EXTERN
-        };
-
-        if attr.is_some() || !traits.is_empty()  {
-            if !self.cx.ecfg.macros_in_extern_enabled() {
-                if let Some(ref attr) = attr {
-                    emit_feature_err(&self.cx.parse_sess, "macros_in_extern", attr.span,
-                                     GateIssue::Language, explain);
-                }
-            }
-
+        if attr.is_some() || !traits.is_empty() {
             let item = Annotatable::ForeignItem(P(foreign_item));
             return self.collect_attr(attr, traits, item, AstFragmentKind::ForeignItems)
                 .make_foreign_items();
@@ -1518,12 +1501,6 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
 
         if let ast::ForeignItemKind::Macro(mac) = foreign_item.node {
             self.check_attributes(&foreign_item.attrs);
-
-            if !self.cx.ecfg.macros_in_extern_enabled() {
-                emit_feature_err(&self.cx.parse_sess, "macros_in_extern", foreign_item.span,
-                                 GateIssue::Language, explain);
-            }
-
             return self.collect_bang(mac, foreign_item.span, AstFragmentKind::ForeignItems)
                 .make_foreign_items();
         }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 6d71d276390..65eeaff3f10 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -32,7 +32,7 @@ use attr;
 use codemap::Spanned;
 use edition::{ALL_EDITIONS, Edition};
 use syntax_pos::{Span, DUMMY_SP};
-use errors::{DiagnosticBuilder, Handler, FatalError};
+use errors::{DiagnosticBuilder, Handler};
 use visit::{self, FnKind, Visitor};
 use parse::ParseSess;
 use symbol::{keywords, Symbol};
@@ -83,8 +83,14 @@ macro_rules! declare_features {
             }
 
             pub fn use_extern_macros(&self) -> bool {
-                // The `decl_macro` and `tool_attributes` features imply `use_extern_macros`.
-                self.use_extern_macros || self.decl_macro || self.tool_attributes
+                // A number of "advanced" macro features enable
+                // macro modularization (`use_extern_macros`) implicitly.
+                self.use_extern_macros || self.decl_macro ||
+                self.tool_attributes || self.custom_attribute ||
+                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
             }
         }
     };
@@ -714,7 +720,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.check_name(builtin_name)) ||
+    BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.path == builtin_name) ||
     attr.name().as_str().starts_with("rustc_")
 }
 
@@ -1364,13 +1370,6 @@ pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
 pub const EXPLAIN_MACRO_AT_MOST_ONCE_REP: &'static str =
     "using the `?` macro Kleene operator for \"at most one\" repetition is unstable";
 
-pub const EXPLAIN_MACROS_IN_EXTERN: &'static str =
-    "macro invocations in `extern {}` blocks are experimental.";
-
-// mention proc-macros when enabled
-pub const EXPLAIN_PROC_MACROS_IN_EXTERN: &'static str =
-    "macro and proc-macro invocations in `extern {}` blocks are experimental.";
-
 struct PostExpansionVisitor<'a> {
     context: &'a Context<'a>,
 }
@@ -1914,9 +1913,6 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
     }
 
     let mut features = Features::new();
-
-    let mut feature_checker = FeatureChecker::default();
-
     let mut edition_enabled_features = FxHashMap();
 
     for &(name, .., f_edition, set) in ACTIVE_FEATURES.iter() {
@@ -1982,7 +1978,6 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
                     ).emit();
                 } else {
                     set(&mut features, mi.span);
-                    feature_checker.collect(&features, mi.span);
                     features.declared_lang_features.push((name, mi.span, None));
                 }
                 continue
@@ -2005,45 +2000,9 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
         }
     }
 
-    feature_checker.check(span_handler);
-
     features
 }
 
-/// A collector for mutually exclusive and interdependent features and their flag spans.
-#[derive(Default)]
-struct FeatureChecker {
-    use_extern_macros: Option<Span>,
-    custom_attribute: Option<Span>,
-}
-
-impl FeatureChecker {
-    // If this method turns out to be a hotspot due to branching,
-    // the branching can be eliminated by modifying `set!()` to set these spans
-    // only for the features that need to be checked for mutual exclusion.
-    fn collect(&mut self, features: &Features, span: Span) {
-        if features.use_extern_macros() {
-            // If self.use_extern_macros is None, set to Some(span)
-            self.use_extern_macros = self.use_extern_macros.or(Some(span));
-        }
-
-        if features.custom_attribute {
-            self.custom_attribute = self.custom_attribute.or(Some(span));
-        }
-    }
-
-    fn check(self, handler: &Handler) {
-        if let (Some(pm_span), Some(ca_span)) = (self.use_extern_macros, self.custom_attribute) {
-            handler.struct_span_err(pm_span, "Cannot use `#![feature(use_extern_macros)]` and \
-                                              `#![feature(custom_attribute)] at the same time")
-                .span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
-                .emit();
-
-            FatalError.raise();
-        }
-    }
-}
-
 pub fn check_crate(krate: &ast::Crate,
                    sess: &ParseSess,
                    features: &Features,
diff --git a/src/test/compile-fail-fulldeps/proc-macro/attr-invalid-exprs.rs b/src/test/compile-fail-fulldeps/proc-macro/attr-invalid-exprs.rs
index 64af21dbe10..91b72510e3e 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/attr-invalid-exprs.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/attr-invalid-exprs.rs
@@ -13,7 +13,7 @@
 
 //! Attributes producing expressions in invalid locations
 
-#![feature(use_extern_macros, stmt_expr_attributes, proc_macro_expr)]
+#![feature(stmt_expr_attributes, proc_macro_expr)]
 
 extern crate attr_stmt_expr;
 use attr_stmt_expr::{duplicate, no_output};
diff --git a/src/test/compile-fail-fulldeps/proc-macro/attr-stmt-expr.rs b/src/test/compile-fail-fulldeps/proc-macro/attr-stmt-expr.rs
index 05b5c918ef0..52b2a473ecd 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/attr-stmt-expr.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/attr-stmt-expr.rs
@@ -11,7 +11,7 @@
 // aux-build:attr-stmt-expr.rs
 // ignore-stage1
 
-#![feature(use_extern_macros, proc_macro_expr)]
+#![feature(proc_macro_expr)]
 
 extern crate attr_stmt_expr;
 use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr};
diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs
index 8fced7d8c70..f71d4b86f1e 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs
@@ -15,7 +15,7 @@
 
 #![feature(use_extern_macros)]
 #![emit_unchanged]
-//~^ ERROR: cannot find attribute macro `emit_unchanged` in this scope
+//~^ ERROR attribute `emit_unchanged` is currently unknown to the compiler
 extern crate issue_41211;
 use issue_41211::emit_unchanged;
 
diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs
index 51112f202c8..eaa64c6ba36 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs
@@ -11,8 +11,6 @@
 // aux-build:issue_50493.rs
 // ignore-stage1
 
-#![feature(proc_macro)]
-
 #[macro_use]
 extern crate issue_50493;
 
diff --git a/src/test/compile-fail-fulldeps/proc-macro/lints_in_proc_macros.rs b/src/test/compile-fail-fulldeps/proc-macro/lints_in_proc_macros.rs
index 6473b69b459..6e9d231ea99 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/lints_in_proc_macros.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/lints_in_proc_macros.rs
@@ -11,7 +11,7 @@
 // aux-build:bang_proc_macro2.rs
 // ignore-stage1
 
-#![feature(use_extern_macros, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 #![allow(unused_macros)]
 
 extern crate bang_proc_macro2;
diff --git a/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs b/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs
index 9a35dc0edc4..e418ecc114c 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs
@@ -26,13 +26,13 @@ fn main() {
 #[link(name = "rust_test_helpers", kind = "static")]
 extern {
     #[no_output]
-    //~^ ERROR macro and proc-macro invocations in `extern {}` blocks are experimental.
+    //~^ ERROR macro invocations in `extern {}` blocks are experimental
     fn some_definitely_unknown_symbol_which_should_be_removed();
 
     #[nop_attr]
-    //~^ ERROR macro and proc-macro invocations in `extern {}` blocks are experimental.
+    //~^ ERROR macro invocations in `extern {}` blocks are experimental
     fn rust_get_test_int() -> isize;
 
     emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
-    //~^ ERROR macro and proc-macro invocations in `extern {}` blocks are experimental.
+    //~^ ERROR macro invocations in `extern {}` blocks are experimental
 }
diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs
index 51b1bfca294..9a0171c2ae5 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs
@@ -16,7 +16,7 @@
 // gate-test-proc_macro_mod
 // gate-test-proc_macro_gen
 
-#![feature(use_extern_macros, stmt_expr_attributes)]
+#![feature(stmt_expr_attributes)]
 
 extern crate proc_macro_gates as foo;
 
diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates2.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates2.rs
index ef6d4557f4c..dc182414a1d 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates2.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates2.rs
@@ -10,7 +10,7 @@
 
 // aux-build:proc-macro-gates.rs
 
-#![feature(use_extern_macros, stmt_expr_attributes)]
+#![feature(stmt_expr_attributes)]
 
 extern crate proc_macro_gates as foo;
 
diff --git a/src/test/compile-fail/macro-with-seps-err-msg.rs b/src/test/compile-fail/macro-with-seps-err-msg.rs
index 6567a100d8c..1281adce5c5 100644
--- a/src/test/compile-fail/macro-with-seps-err-msg.rs
+++ b/src/test/compile-fail/macro-with-seps-err-msg.rs
@@ -10,10 +10,6 @@
 
 // gate-test-use_extern_macros
 
-#![feature(proc_macro_path_invoc)]
-
 fn main() {
     globnar::brotz!(); //~ ERROR non-ident macro paths are experimental
-    #[derive(foo::Bar)] struct T; //~ ERROR non-ident macro paths are experimental
-    ::foo!(); //~ ERROR non-ident macro paths are experimental
 }
diff --git a/src/test/compile-fail/macros-in-extern.rs b/src/test/compile-fail/macros-in-extern.rs
index b6e273881cc..40053853b15 100644
--- a/src/test/compile-fail/macros-in-extern.rs
+++ b/src/test/compile-fail/macros-in-extern.rs
@@ -34,9 +34,9 @@ fn main() {
 #[link(name = "rust_test_helpers", kind = "static")]
 extern {
     returns_isize!(rust_get_test_int);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental.
+    //~^ ERROR macro invocations in `extern {}` blocks are experimental
     takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental.
+    //~^ ERROR macro invocations in `extern {}` blocks are experimental
     emits_nothing!();
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental.
+    //~^ ERROR macro invocations in `extern {}` blocks are experimental
 }
diff --git a/src/test/compile-fail/stmt_expr_attrs_no_feature.rs b/src/test/compile-fail/stmt_expr_attrs_no_feature.rs
index d8626dfd39e..896817bb858 100644
--- a/src/test/compile-fail/stmt_expr_attrs_no_feature.rs
+++ b/src/test/compile-fail/stmt_expr_attrs_no_feature.rs
@@ -20,7 +20,7 @@ fn main() {
     #[attr]
     fn a() {}
 
-    #[attr]
+    #[attr] //~ ERROR attributes on expressions are experimental
     {
 
     }
diff --git a/src/test/compile-fail/unknown-tool-name.rs b/src/test/compile-fail/unknown-tool-name.rs
index c4d22e6d392..99c336c28cd 100644
--- a/src/test/compile-fail/unknown-tool-name.rs
+++ b/src/test/compile-fail/unknown-tool-name.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(use_extern_macros, proc_macro_path_invoc)]
+#![feature(proc_macro_path_invoc)]
 
 #[foo::bar] //~ ERROR failed to resolve. Use of undeclared type or module `foo`
 fn main() {}
diff --git a/src/test/pretty/attr-literals.rs b/src/test/pretty/attr-literals.rs
index ba8c580cb0a..ce157e3632c 100644
--- a/src/test/pretty/attr-literals.rs
+++ b/src/test/pretty/attr-literals.rs
@@ -18,6 +18,6 @@ fn main() {
     #[align = 8]
     fn f() { }
 
-    #[vec(1, 2, 3)]
+    #[vector(1, 2, 3)]
     fn g() { }
 }
diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
index ec6f54fb137..94c5b208a37 100644
--- a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
@@ -11,7 +11,7 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 
 extern crate proc_macro;
 
diff --git a/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs b/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs
index 545eabe00ff..b54543c73fb 100644
--- a/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs
@@ -11,7 +11,7 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(use_extern_macros, proc_macro_non_items, proc_macro_quote)]
+#![feature(proc_macro_non_items, proc_macro_quote)]
 
 extern crate proc_macro;
 
diff --git a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs
index 9a5bffb92a4..9faa7366ec5 100644
--- a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs
@@ -11,7 +11,7 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 
 extern crate proc_macro;
 
diff --git a/src/test/run-pass-fulldeps/macro-quote-cond.rs b/src/test/run-pass-fulldeps/macro-quote-cond.rs
index f1dcec8af69..3eb7e8cc9a4 100644
--- a/src/test/run-pass-fulldeps/macro-quote-cond.rs
+++ b/src/test/run-pass-fulldeps/macro-quote-cond.rs
@@ -11,7 +11,7 @@
 // aux-build:cond_plugin.rs
 // ignore-stage1
 
-#![feature(use_extern_macros, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 
 extern crate cond_plugin;
 
diff --git a/src/test/run-pass-fulldeps/macro-quote-test.rs b/src/test/run-pass-fulldeps/macro-quote-test.rs
index 2349fa68c65..1005a6bfc50 100644
--- a/src/test/run-pass-fulldeps/macro-quote-test.rs
+++ b/src/test/run-pass-fulldeps/macro-quote-test.rs
@@ -13,7 +13,7 @@
 // aux-build:hello_macro.rs
 // ignore-stage1
 
-#![feature(use_extern_macros, proc_macro_non_items, proc_macro_gen)]
+#![feature(proc_macro_non_items, proc_macro_gen)]
 
 extern crate hello_macro;
 
diff --git a/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs b/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs
index 3356828c04b..b5272e6608b 100644
--- a/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs
@@ -11,7 +11,7 @@
 // aux-build:attr-stmt-expr.rs
 // ignore-stage1
 
-#![feature(use_extern_macros, stmt_expr_attributes, proc_macro_expr)]
+#![feature(stmt_expr_attributes, proc_macro_expr)]
 
 extern crate attr_stmt_expr;
 use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr,
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs
index c6bcc37ac4a..a84e029f9d8 100644
--- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs
@@ -10,7 +10,7 @@
 
 // no-prefer-dynamic
 
-#![feature(proc_macro_non_items, proc_macro_quote, use_extern_macros)]
+#![feature(proc_macro_non_items, proc_macro_quote)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs
index 8f95bdd9c39..43c1d5fcc8d 100644
--- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs
@@ -10,7 +10,7 @@
 
 // no-prefer-dynamic
 
-#![feature(use_extern_macros, proc_macro_quote, proc_macro_non_items)]
+#![feature(proc_macro_quote, proc_macro_non_items)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro as proc_macro_renamed; // This does not break `quote!`
diff --git a/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs b/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs
index f9d17a9decb..955b6ab986d 100644
--- a/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs
@@ -11,7 +11,7 @@
 // aux-build:bang-macro.rs
 // ignore-stage1
 
-#![feature(use_extern_macros, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 
 extern crate bang_macro;
 use bang_macro::rewrite;
diff --git a/src/test/run-pass-fulldeps/proc-macro/call-site.rs b/src/test/run-pass-fulldeps/proc-macro/call-site.rs
index 505994f66e7..dfe97eb587c 100644
--- a/src/test/run-pass-fulldeps/proc-macro/call-site.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/call-site.rs
@@ -11,7 +11,7 @@
 // aux-build:call-site.rs
 // ignore-stage1
 
-#![feature(proc_macro_non_items, use_extern_macros)]
+#![feature(proc_macro_non_items)]
 
 extern crate call_site;
 use call_site::*;
diff --git a/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs b/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs
index f4a51d0624a..6601d66e586 100644
--- a/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs
@@ -11,7 +11,7 @@
 // aux-build:count_compound_ops.rs
 // ignore-stage1
 
-#![feature(use_extern_macros, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 
 extern crate count_compound_ops;
 use count_compound_ops::count_compound_ops;
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 35d5084d9f6..4a7c8f3e834 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(use_extern_macros, proc_macro_path_invoc)]
+#![feature(proc_macro_path_invoc)]
 
 extern crate derive_b;
 
diff --git a/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs b/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs
index 5ee164415a1..579e8c33773 100644
--- a/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs
@@ -12,7 +12,7 @@
 // aux-build:hygiene_example.rs
 // ignore-stage1
 
-#![feature(use_extern_macros, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 
 extern crate hygiene_example;
 use hygiene_example::hello;
diff --git a/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs b/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs
index e5f8c844b6b..bd76cc38054 100644
--- a/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs
@@ -12,7 +12,7 @@
 // ignore-stage1
 // ignore-wasm32
 
-#![feature(use_extern_macros, macros_in_extern)]
+#![feature(macros_in_extern)]
 
 extern crate test_macros;
 
diff --git a/src/test/run-pass-fulldeps/proc_macro.rs b/src/test/run-pass-fulldeps/proc_macro.rs
index 46b62d7e34a..c9d7b0423ec 100644
--- a/src/test/run-pass-fulldeps/proc_macro.rs
+++ b/src/test/run-pass-fulldeps/proc_macro.rs
@@ -12,7 +12,7 @@
 // ignore-stage1
 // ignore-cross-compile
 
-#![feature(use_extern_macros, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 
 extern crate proc_macro_def;
 
diff --git a/src/test/ui-fulldeps/auxiliary/attr_proc_macro.rs b/src/test/ui-fulldeps/auxiliary/attr_proc_macro.rs
index db0c19e96f8..679cb772868 100644
--- a/src/test/ui-fulldeps/auxiliary/attr_proc_macro.rs
+++ b/src/test/ui-fulldeps/auxiliary/attr_proc_macro.rs
@@ -10,7 +10,7 @@
 
 // force-host
 // no-prefer-dynamic
-#![feature(proc_macro)]
+
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
diff --git a/src/test/ui-fulldeps/auxiliary/bang_proc_macro.rs b/src/test/ui-fulldeps/auxiliary/bang_proc_macro.rs
index 89ac11b309d..6484725814a 100644
--- a/src/test/ui-fulldeps/auxiliary/bang_proc_macro.rs
+++ b/src/test/ui-fulldeps/auxiliary/bang_proc_macro.rs
@@ -10,7 +10,7 @@
 
 // force-host
 // no-prefer-dynamic
-#![feature(proc_macro)]
+
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
diff --git a/src/test/ui-fulldeps/auxiliary/lifetimes.rs b/src/test/ui-fulldeps/auxiliary/lifetimes.rs
index ecf0a56edf7..fc59a622bfa 100644
--- a/src/test/ui-fulldeps/auxiliary/lifetimes.rs
+++ b/src/test/ui-fulldeps/auxiliary/lifetimes.rs
@@ -10,7 +10,6 @@
 
 // no-prefer-dynamic
 
-#![feature(proc_macro)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
diff --git a/src/test/ui-fulldeps/lifetimes.rs b/src/test/ui-fulldeps/lifetimes.rs
index 3200e8fb2b1..6879848d269 100644
--- a/src/test/ui-fulldeps/lifetimes.rs
+++ b/src/test/ui-fulldeps/lifetimes.rs
@@ -10,7 +10,7 @@
 
 // aux-build:lifetimes.rs
 
-#![feature(use_extern_macros, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 
 extern crate lifetimes;
 
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs
index 632dba42ad0..1ed8ef52027 100644
--- a/src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs
+++ b/src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs
@@ -11,7 +11,6 @@
 // run-pass
 // no-prefer-dynamic
 
-#![feature(proc_macro)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
diff --git a/src/test/ui-fulldeps/proc-macro/generate-mod.rs b/src/test/ui-fulldeps/proc-macro/generate-mod.rs
index ee0077c3ed3..b0cccd8728b 100644
--- a/src/test/ui-fulldeps/proc-macro/generate-mod.rs
+++ b/src/test/ui-fulldeps/proc-macro/generate-mod.rs
@@ -12,7 +12,7 @@
 
 // aux-build:generate-mod.rs
 
-#![feature(use_extern_macros, proc_macro_gen, proc_macro_path_invoc)]
+#![feature(proc_macro_gen, proc_macro_path_invoc)]
 
 extern crate generate_mod;
 
diff --git a/src/test/ui-fulldeps/proc-macro/invalid-attributes.rs b/src/test/ui-fulldeps/proc-macro/invalid-attributes.rs
index c06f98ed5ff..8b940a0f405 100644
--- a/src/test/ui-fulldeps/proc-macro/invalid-attributes.rs
+++ b/src/test/ui-fulldeps/proc-macro/invalid-attributes.rs
@@ -11,7 +11,6 @@
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(proc_macro)]
 
 extern crate proc_macro;
 
diff --git a/src/test/ui-fulldeps/proc-macro/invalid-attributes.stderr b/src/test/ui-fulldeps/proc-macro/invalid-attributes.stderr
index c480bcb5df9..5fd87362db2 100644
--- a/src/test/ui-fulldeps/proc-macro/invalid-attributes.stderr
+++ b/src/test/ui-fulldeps/proc-macro/invalid-attributes.stderr
@@ -1,35 +1,35 @@
 error: `#[proc_macro]` attribute does not take any arguments
-  --> $DIR/invalid-attributes.rs:20:1
+  --> $DIR/invalid-attributes.rs:19:1
    |
 LL | #[proc_macro = "test"] //~ ERROR: does not take any arguments
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[proc_macro]` attribute does not take any arguments
-  --> $DIR/invalid-attributes.rs:23:1
+  --> $DIR/invalid-attributes.rs:22:1
    |
 LL | #[proc_macro()] //~ ERROR: does not take any arguments
    | ^^^^^^^^^^^^^^^
 
 error: `#[proc_macro]` attribute does not take any arguments
-  --> $DIR/invalid-attributes.rs:26:1
+  --> $DIR/invalid-attributes.rs:25:1
    |
 LL | #[proc_macro(x)] //~ ERROR: does not take any arguments
    | ^^^^^^^^^^^^^^^^
 
 error: `#[proc_macro_attribute]` attribute does not take any arguments
-  --> $DIR/invalid-attributes.rs:29:1
+  --> $DIR/invalid-attributes.rs:28:1
    |
 LL | #[proc_macro_attribute = "test"] //~ ERROR: does not take any arguments
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[proc_macro_attribute]` attribute does not take any arguments
-  --> $DIR/invalid-attributes.rs:32:1
+  --> $DIR/invalid-attributes.rs:31:1
    |
 LL | #[proc_macro_attribute()] //~ ERROR: does not take any arguments
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[proc_macro_attribute]` attribute does not take any arguments
-  --> $DIR/invalid-attributes.rs:35:1
+  --> $DIR/invalid-attributes.rs:34:1
    |
 LL | #[proc_macro_attribute(x)] //~ ERROR: does not take any arguments
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui-fulldeps/proc-macro/macro-namespace-reserved.rs b/src/test/ui-fulldeps/proc-macro/macro-namespace-reserved.rs
index 21d625ae09d..e7bb05de88c 100644
--- a/src/test/ui-fulldeps/proc-macro/macro-namespace-reserved.rs
+++ b/src/test/ui-fulldeps/proc-macro/macro-namespace-reserved.rs
@@ -10,7 +10,7 @@
 
 // no-prefer-dynamic
 
-#![feature(proc_macro, decl_macro)]
+#![feature(decl_macro)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
diff --git a/src/test/ui-fulldeps/proc-macro/non-root.rs b/src/test/ui-fulldeps/proc-macro/non-root.rs
index 288c63b4c77..24404885788 100644
--- a/src/test/ui-fulldeps/proc-macro/non-root.rs
+++ b/src/test/ui-fulldeps/proc-macro/non-root.rs
@@ -10,7 +10,6 @@
 
 // no-prefer-dynamic
 
-#![feature(proc_macro)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
diff --git a/src/test/ui-fulldeps/proc-macro/non-root.stderr b/src/test/ui-fulldeps/proc-macro/non-root.stderr
index 8c14f644d7a..23222a2b851 100644
--- a/src/test/ui-fulldeps/proc-macro/non-root.stderr
+++ b/src/test/ui-fulldeps/proc-macro/non-root.stderr
@@ -1,5 +1,5 @@
 error: functions tagged with `#[proc_macro]` must currently reside in the root of the crate
-  --> $DIR/non-root.rs:21:5
+  --> $DIR/non-root.rs:20:5
    |
 LL |     pub fn foo(arg: TokenStream) -> TokenStream { arg }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui-fulldeps/proc-macro/three-equals.rs b/src/test/ui-fulldeps/proc-macro/three-equals.rs
index ee5f3b33a06..f6b0e90da00 100644
--- a/src/test/ui-fulldeps/proc-macro/three-equals.rs
+++ b/src/test/ui-fulldeps/proc-macro/three-equals.rs
@@ -11,7 +11,7 @@
 // aux-build:three-equals.rs
 // ignore-stage1
 
-#![feature(use_extern_macros, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
 
 extern crate three_equals;
 
diff --git a/src/test/ui-fulldeps/resolve-error.rs b/src/test/ui-fulldeps/resolve-error.rs
index df9b263534f..1940151357c 100644
--- a/src/test/ui-fulldeps/resolve-error.rs
+++ b/src/test/ui-fulldeps/resolve-error.rs
@@ -13,7 +13,7 @@
 // aux-build:attr_proc_macro.rs
 // aux-build:bang_proc_macro.rs
 
-#![feature(use_extern_macros)]
+#![feature(custom_attribute)]
 
 #[macro_use]
 extern crate derive_foo;
@@ -37,12 +37,10 @@ macro_rules! attr_proc_mac {
 //~^ ERROR cannot find
 struct Foo;
 
-#[attr_proc_macra]
-//~^ ERROR cannot find
+#[attr_proc_macra] // OK, interpreted as a custom attribute
 struct Bar;
 
-#[FooWithLongNan]
-//~^ ERROR cannot find
+#[FooWithLongNan]  // OK, interpreted as a custom attribute
 struct Asdf;
 
 #[derive(Dlone)]
diff --git a/src/test/ui-fulldeps/resolve-error.stderr b/src/test/ui-fulldeps/resolve-error.stderr
index caa79664614..278409c688a 100644
--- a/src/test/ui-fulldeps/resolve-error.stderr
+++ b/src/test/ui-fulldeps/resolve-error.stderr
@@ -4,59 +4,47 @@ error: cannot find derive macro `FooWithLongNan` in this scope
 LL | #[derive(FooWithLongNan)]
    |          ^^^^^^^^^^^^^^ help: try: `FooWithLongName`
 
-error: cannot find attribute macro `attr_proc_macra` in this scope
-  --> $DIR/resolve-error.rs:40:3
-   |
-LL | #[attr_proc_macra]
-   |   ^^^^^^^^^^^^^^^ help: try: `attr_proc_macro`
-
-error: cannot find attribute macro `FooWithLongNan` in this scope
-  --> $DIR/resolve-error.rs:44:3
-   |
-LL | #[FooWithLongNan]
-   |   ^^^^^^^^^^^^^^
-
 error: cannot find derive macro `Dlone` in this scope
-  --> $DIR/resolve-error.rs:48:10
+  --> $DIR/resolve-error.rs:46:10
    |
 LL | #[derive(Dlone)]
    |          ^^^^^ help: try: `Clone`
 
 error: cannot find derive macro `Dlona` in this scope
-  --> $DIR/resolve-error.rs:52:10
+  --> $DIR/resolve-error.rs:50:10
    |
 LL | #[derive(Dlona)]
    |          ^^^^^ help: try: `Clona`
 
 error: cannot find derive macro `attr_proc_macra` in this scope
-  --> $DIR/resolve-error.rs:56:10
+  --> $DIR/resolve-error.rs:54:10
    |
 LL | #[derive(attr_proc_macra)]
    |          ^^^^^^^^^^^^^^^
 
 error: cannot find macro `FooWithLongNama!` in this scope
-  --> $DIR/resolve-error.rs:61:5
+  --> $DIR/resolve-error.rs:59:5
    |
 LL |     FooWithLongNama!();
    |     ^^^^^^^^^^^^^^^ help: you could try the macro: `FooWithLongNam`
 
 error: cannot find macro `attr_proc_macra!` in this scope
-  --> $DIR/resolve-error.rs:64:5
+  --> $DIR/resolve-error.rs:62:5
    |
 LL |     attr_proc_macra!();
    |     ^^^^^^^^^^^^^^^ help: you could try the macro: `attr_proc_mac`
 
 error: cannot find macro `Dlona!` in this scope
-  --> $DIR/resolve-error.rs:67:5
+  --> $DIR/resolve-error.rs:65:5
    |
 LL |     Dlona!();
    |     ^^^^^
 
 error: cannot find macro `bang_proc_macrp!` in this scope
-  --> $DIR/resolve-error.rs:70:5
+  --> $DIR/resolve-error.rs:68:5
    |
 LL |     bang_proc_macrp!();
    |     ^^^^^^^^^^^^^^^ help: you could try the macro: `bang_proc_macro`
 
-error: aborting due to 10 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-custom-attr-mutex.rs b/src/test/ui/custom-attribute-multisegment.rs
index 9ed665b6e68..ad8e0e76e14 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-custom-attr-mutex.rs
+++ b/src/test/ui/custom-attribute-multisegment.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,18 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// aux-build:attr_proc_macro.rs
-// ignore-tidy-linelength
+// Unresolved multi-segment attributes are not treated as custom.
 
-#![feature(use_extern_macros, custom_attribute)]
-//~^ ERROR Cannot use `#![feature(use_extern_macros)]` and `#![feature(custom_attribute)] at the same time
+#![feature(custom_attribute, proc_macro_path_invoc)]
 
-extern crate attr_proc_macro;
-use attr_proc_macro::attr_proc_macro;
+mod existent {}
 
-#[attr_proc_macro]
-fn foo() {}
-
-fn main() {
-    foo();
-}
+#[existent::nonexistent] //~ ERROR failed to resolve. Could not find `nonexistent` in `existent`
+fn main() {}
diff --git a/src/test/ui/custom-attribute-multisegment.stderr b/src/test/ui/custom-attribute-multisegment.stderr
new file mode 100644
index 00000000000..ff72d1c36d8
--- /dev/null
+++ b/src/test/ui/custom-attribute-multisegment.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve. Could not find `nonexistent` in `existent`
+  --> $DIR/custom-attribute-multisegment.rs:17:13
+   |
+LL | #[existent::nonexistent] //~ ERROR failed to resolve. Could not find `nonexistent` in `existent`
+   |             ^^^^^^^^^^^ Could not find `nonexistent` in `existent`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/feature-gate-macros_in_extern.rs b/src/test/ui/feature-gate-macros_in_extern.rs
index 5271f75b632..77080e3c348 100644
--- a/src/test/ui/feature-gate-macros_in_extern.rs
+++ b/src/test/ui/feature-gate-macros_in_extern.rs
@@ -27,9 +27,9 @@ macro_rules! emits_nothing(
 #[link(name = "rust_test_helpers", kind = "static")]
 extern {
     returns_isize!(rust_get_test_int);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental.
+    //~^ ERROR macro invocations in `extern {}` blocks are experimental
     takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental.
+    //~^ ERROR macro invocations in `extern {}` blocks are experimental
     emits_nothing!();
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental.
+    //~^ ERROR macro invocations in `extern {}` blocks are experimental
 }
diff --git a/src/test/ui/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gate-macros_in_extern.stderr
index 5d7e01fbbb7..23b63078dbf 100644
--- a/src/test/ui/feature-gate-macros_in_extern.stderr
+++ b/src/test/ui/feature-gate-macros_in_extern.stderr
@@ -1,4 +1,4 @@
-error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476)
   --> $DIR/feature-gate-macros_in_extern.rs:29:5
    |
 LL |     returns_isize!(rust_get_test_int);
@@ -6,7 +6,7 @@ LL |     returns_isize!(rust_get_test_int);
    |
    = help: add #![feature(macros_in_extern)] to the crate attributes to enable
 
-error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476)
   --> $DIR/feature-gate-macros_in_extern.rs:31:5
    |
 LL |     takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
@@ -14,7 +14,7 @@ LL |     takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
    |
    = help: add #![feature(macros_in_extern)] to the crate attributes to enable
 
-error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476)
   --> $DIR/feature-gate-macros_in_extern.rs:33:5
    |
 LL |     emits_nothing!();
diff --git a/src/test/ui/imports/macros.rs b/src/test/ui/imports/macros.rs
index 5d6a1191384..ed5907800e9 100644
--- a/src/test/ui/imports/macros.rs
+++ b/src/test/ui/imports/macros.rs
@@ -10,7 +10,7 @@
 
 // aux-build:two_macros.rs
 
-#![feature(item_like_imports, use_extern_macros)]
+#![feature(use_extern_macros)]
 
 extern crate two_macros; // two identity macros `m` and `n`
 
diff --git a/src/test/ui/issue-11692-2.rs b/src/test/ui/issue-11692-2.rs
index c595b0fb2c2..50525e03acf 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 non-macro attribute
+    //~^ ERROR expected a macro, found built-in attribute
 }
diff --git a/src/test/ui/issue-11692-2.stderr b/src/test/ui/issue-11692-2.stderr
index 3d080bd46dc..0c130943fd8 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 non-macro attribute
+error: expected a macro, found built-in attribute
   --> $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 4cf90019d40..bdbc7bd660f 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 non-macro attribute
+#[derive(inline)] //~ ERROR expected a macro, found built-in attribute
 struct S;
 
 fn main() {
-    inline!(); //~ ERROR expected a macro, found non-macro attribute
+    inline!(); //~ ERROR expected a macro, found built-in attribute
 }
diff --git a/src/test/ui/macro-path-prelude-fail-3.stderr b/src/test/ui/macro-path-prelude-fail-3.stderr
index bd1015b7ee1..396bba2408f 100644
--- a/src/test/ui/macro-path-prelude-fail-3.stderr
+++ b/src/test/ui/macro-path-prelude-fail-3.stderr
@@ -1,13 +1,13 @@
-error: expected a macro, found non-macro attribute
+error: expected a macro, found built-in attribute
   --> $DIR/macro-path-prelude-fail-3.rs:13:10
    |
-LL | #[derive(inline)] //~ ERROR expected a macro, found non-macro attribute
+LL | #[derive(inline)] //~ ERROR expected a macro, found built-in attribute
    |          ^^^^^^
 
-error: expected a macro, found non-macro attribute
+error: expected a macro, found built-in attribute
   --> $DIR/macro-path-prelude-fail-3.rs:17:5
    |
-LL |     inline!(); //~ ERROR expected a macro, found non-macro attribute
+LL |     inline!(); //~ ERROR expected a macro, found built-in attribute
    |     ^^^^^^
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/tool-attributes-disabled-2.rs b/src/test/ui/tool-attributes-disabled-2.rs
index 160dda05b1e..2d97e160f49 100644
--- a/src/test/ui/tool-attributes-disabled-2.rs
+++ b/src/test/ui/tool-attributes-disabled-2.rs
@@ -11,9 +11,5 @@
 // If macro modularization (`use_extern_macros`) is not enabled,
 // then tool attributes are treated as custom attributes.
 
-// compile-pass
-
-#![feature(custom_attribute)]
-
-#[rustfmt::bar]
+#[rustfmt::bar] //~ ERROR attribute `rustfmt::bar` is currently unknown to the compiler
 fn main() {}
diff --git a/src/test/ui/tool-attributes-disabled-2.stderr b/src/test/ui/tool-attributes-disabled-2.stderr
new file mode 100644
index 00000000000..b327773dd6a
--- /dev/null
+++ b/src/test/ui/tool-attributes-disabled-2.stderr
@@ -0,0 +1,11 @@
+error[E0658]: The attribute `rustfmt::bar` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
+  --> $DIR/tool-attributes-disabled-2.rs:14:1
+   |
+LL | #[rustfmt::bar] //~ ERROR attribute `rustfmt::bar` is currently unknown to the compiler
+   | ^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(custom_attribute)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/tool-attributes-misplaced-1.rs b/src/test/ui/tool-attributes-misplaced-1.rs
index b3355352423..7a6b9ae9943 100644
--- a/src/test/ui/tool-attributes-misplaced-1.rs
+++ b/src/test/ui/tool-attributes-misplaced-1.rs
@@ -8,15 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(tool_attributes)]
+#![feature(tool_attributes, custom_attribute)]
 
 type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt`
-type B = rustfmt::skip; //~ ERROR expected type, found non-macro attribute `rustfmt::skip`
+type B = rustfmt::skip; //~ ERROR expected type, found tool attribute `rustfmt::skip`
 
 #[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
 struct S;
 
-#[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
+#[rustfmt] // OK, interpreted as a custom attribute
 fn check() {}
 
 #[rustfmt::skip] // OK
@@ -24,5 +24,5 @@ fn main() {
     rustfmt; //~ ERROR expected value, found tool module `rustfmt`
     rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope
 
-    rustfmt::skip; //~ ERROR expected value, found non-macro attribute `rustfmt::skip`
+    rustfmt::skip; //~ ERROR expected value, found tool attribute `rustfmt::skip`
 }
diff --git a/src/test/ui/tool-attributes-misplaced-1.stderr b/src/test/ui/tool-attributes-misplaced-1.stderr
index b9e61121406..60188aebce7 100644
--- a/src/test/ui/tool-attributes-misplaced-1.stderr
+++ b/src/test/ui/tool-attributes-misplaced-1.stderr
@@ -4,12 +4,6 @@ error: cannot find derive macro `rustfmt` in this scope
 LL | #[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
    |          ^^^^^^^
 
-error: cannot find attribute macro `rustfmt` in this scope
-  --> $DIR/tool-attributes-misplaced-1.rs:19:3
-   |
-LL | #[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
-   |   ^^^^^^^
-
 error: cannot find macro `rustfmt!` in this scope
   --> $DIR/tool-attributes-misplaced-1.rs:25:5
    |
@@ -22,10 +16,10 @@ error[E0573]: expected type, found tool module `rustfmt`
 LL | type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt`
    |          ^^^^^^^ not a type
 
-error[E0573]: expected type, found non-macro attribute `rustfmt::skip`
+error[E0573]: expected type, found tool attribute `rustfmt::skip`
   --> $DIR/tool-attributes-misplaced-1.rs:14:10
    |
-LL | type B = rustfmt::skip; //~ ERROR expected type, found non-macro attribute `rustfmt::skip`
+LL | type B = rustfmt::skip; //~ ERROR expected type, found tool attribute `rustfmt::skip`
    |          ^^^^^^^^^^^^^ not a type
 
 error[E0423]: expected value, found tool module `rustfmt`
@@ -34,13 +28,13 @@ error[E0423]: expected value, found tool module `rustfmt`
 LL |     rustfmt; //~ ERROR expected value, found tool module `rustfmt`
    |     ^^^^^^^ not a value
 
-error[E0423]: expected value, found non-macro attribute `rustfmt::skip`
+error[E0423]: expected value, found tool attribute `rustfmt::skip`
   --> $DIR/tool-attributes-misplaced-1.rs:27:5
    |
-LL |     rustfmt::skip; //~ ERROR expected value, found non-macro attribute `rustfmt::skip`
+LL |     rustfmt::skip; //~ ERROR expected value, found tool attribute `rustfmt::skip`
    |     ^^^^^^^^^^^^^ not a value
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
 Some errors occurred: E0423, E0573.
 For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/tool-attributes-misplaced-2.rs b/src/test/ui/tool-attributes-misplaced-2.rs
index 3bb0e3dc343..102edf2813b 100644
--- a/src/test/ui/tool-attributes-misplaced-2.rs
+++ b/src/test/ui/tool-attributes-misplaced-2.rs
@@ -10,9 +10,9 @@
 
 #![feature(tool_attributes)]
 
-#[derive(rustfmt::skip)] //~ ERROR expected a macro, found non-macro attribute
+#[derive(rustfmt::skip)] //~ ERROR expected a macro, found tool attribute
 struct S;
 
 fn main() {
-    rustfmt::skip!(); //~ ERROR expected a macro, found non-macro attribute
+    rustfmt::skip!(); //~ ERROR expected a macro, found tool attribute
 }
diff --git a/src/test/ui/tool-attributes-misplaced-2.stderr b/src/test/ui/tool-attributes-misplaced-2.stderr
index 66452267e94..5b968cd6b8e 100644
--- a/src/test/ui/tool-attributes-misplaced-2.stderr
+++ b/src/test/ui/tool-attributes-misplaced-2.stderr
@@ -1,13 +1,13 @@
-error: expected a macro, found non-macro attribute
+error: expected a macro, found tool attribute
   --> $DIR/tool-attributes-misplaced-2.rs:13:10
    |
-LL | #[derive(rustfmt::skip)] //~ ERROR expected a macro, found non-macro attribute
+LL | #[derive(rustfmt::skip)] //~ ERROR expected a macro, found tool attribute
    |          ^^^^^^^^^^^^^
 
-error: expected a macro, found non-macro attribute
+error: expected a macro, found tool attribute
   --> $DIR/tool-attributes-misplaced-2.rs:17:5
    |
-LL |     rustfmt::skip!(); //~ ERROR expected a macro, found non-macro attribute
+LL |     rustfmt::skip!(); //~ ERROR expected a macro, found tool attribute
    |     ^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors