about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-08-09 14:07:29 +0200
committerGitHub <noreply@github.com>2019-08-09 14:07:29 +0200
commit714c8ea9b5f1c15fec4211eef2ea04385fe4d386 (patch)
tree2a6ba0b6e5280ac86fa97e80c5e4eab237a99d71 /src
parenta03872645fc655125e43e56bd12c335b2fb19c2e (diff)
parentd9d9246418ae884cb67feb3574832696660b8e2e (diff)
downloadrust-714c8ea9b5f1c15fec4211eef2ea04385fe4d386.tar.gz
rust-714c8ea9b5f1c15fec4211eef2ea04385fe4d386.zip
Rollup merge of #63114 - matthewjasper:hygienic-format-args, r=petrochenkov
Remove gensym in format_args

This also fixes some things to allow us to export opaque macros from libcore:

* Don't consider items that are only reachable through opaque macros as public/exported (so they aren't linted as needing docs)
* Mark private items reachable from the root of libcore as unstable - they are now reachable (in principle) in other crates via macros in libcore

r? @petrochenkov
Diffstat (limited to 'src')
-rw-r--r--src/libcore/macros.rs2
-rw-r--r--src/libcore/unicode/tables.rs32
-rwxr-xr-xsrc/libcore/unicode/unicode.py8
-rw-r--r--src/librustc_privacy/lib.rs190
-rw-r--r--src/libsyntax_ext/format.rs4
-rw-r--r--src/test/ui/definition-reachable/auxiliary/field-method-macro.rs23
-rw-r--r--src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs11
-rw-r--r--src/test/ui/definition-reachable/auxiliary/private-use-macro.rs11
-rw-r--r--src/test/ui/definition-reachable/field-method.rs11
-rw-r--r--src/test/ui/definition-reachable/nested-fn.rs11
-rw-r--r--src/test/ui/definition-reachable/private-non-types.rs21
-rw-r--r--src/test/ui/definition-reachable/private-types.rs19
-rw-r--r--src/test/ui/definition-reachable/private-use.rs10
-rw-r--r--src/test/ui/format-hygiene.rs8
-rw-r--r--src/test/ui/hygiene/format-args.rs12
15 files changed, 310 insertions, 63 deletions
diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs
index aa661078e71..667b35d0f77 100644
--- a/src/libcore/macros.rs
+++ b/src/libcore/macros.rs
@@ -768,7 +768,6 @@ pub(crate) mod builtin {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[allow_internal_unstable(fmt_internals)]
     #[rustc_builtin_macro]
-    #[rustc_macro_transparency = "semitransparent"]
     pub macro format_args {
         ($fmt:expr) => ({ /* compiler built-in */ }),
         ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
@@ -780,7 +779,6 @@ pub(crate) mod builtin {
                          language use and is subject to change")]
     #[allow_internal_unstable(fmt_internals)]
     #[rustc_builtin_macro]
-    #[rustc_macro_transparency = "semitransparent"]
     pub macro format_args_nl {
         ($fmt:expr) => ({ /* compiler built-in */ }),
         ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs
index bfe784afaa4..3fae3a46ada 100644
--- a/src/libcore/unicode/tables.rs
+++ b/src/libcore/unicode/tables.rs
@@ -14,8 +14,8 @@ pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion {
     micro: 0,
     _priv: (),
 };
-pub mod general_category {
-    pub const Cc_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
+pub(crate) mod general_category {
+    const Cc_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
         r1: &[
             0, 1, 0
         ],
@@ -28,7 +28,7 @@ pub mod general_category {
         Cc_table.lookup(c)
     }
 
-    pub const N_table: &super::BoolTrie = &super::BoolTrie {
+    const N_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x03ff000000000000, 0x0000000000000000, 0x720c000000000000, 0x0000000000000000,
             0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
@@ -141,8 +141,8 @@ pub mod general_category {
 
 }
 
-pub mod derived_property {
-    pub const Alphabetic_table: &super::BoolTrie = &super::BoolTrie {
+pub(crate) mod derived_property {
+    const Alphabetic_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff,
             0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
@@ -327,7 +327,7 @@ pub mod derived_property {
         Alphabetic_table.lookup(c)
     }
 
-    pub const Case_Ignorable_table: &super::BoolTrie = &super::BoolTrie {
+    const Case_Ignorable_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0400408000000000, 0x0000000140000000, 0x0190a10000000000, 0x0000000000000000,
             0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
@@ -464,7 +464,7 @@ pub mod derived_property {
         Case_Ignorable_table.lookup(c)
     }
 
-    pub const Cased_table: &super::BoolTrie = &super::BoolTrie {
+    const Cased_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff,
             0xffffffffffffffff, 0xffffffffffffffff, 0xf7ffffffffffffff, 0xfffffffffffffff0,
@@ -565,7 +565,7 @@ pub mod derived_property {
         Cased_table.lookup(c)
     }
 
-    pub const Grapheme_Extend_table: &super::BoolTrie = &super::BoolTrie {
+    const Grapheme_Extend_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
             0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
@@ -689,7 +689,7 @@ pub mod derived_property {
         Grapheme_Extend_table.lookup(c)
     }
 
-    pub const Lowercase_table: &super::BoolTrie = &super::BoolTrie {
+    const Lowercase_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x07fffffe00000000, 0x0420040000000000, 0xff7fffff80000000,
             0x55aaaaaaaaaaaaaa, 0xd4aaaaaaaaaaab55, 0xe6512d2a4e243129, 0xaa29aaaab5555240,
@@ -789,7 +789,7 @@ pub mod derived_property {
         Lowercase_table.lookup(c)
     }
 
-    pub const Uppercase_table: &super::BoolTrie = &super::BoolTrie {
+    const Uppercase_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x0000000007fffffe, 0x0000000000000000, 0x000000007f7fffff,
             0xaa55555555555555, 0x2b555555555554aa, 0x11aed2d5b1dbced6, 0x55d255554aaaa490,
@@ -890,7 +890,7 @@ pub mod derived_property {
         Uppercase_table.lookup(c)
     }
 
-    pub const XID_Continue_table: &super::BoolTrie = &super::BoolTrie {
+    const XID_Continue_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x03ff000000000000, 0x07fffffe87fffffe, 0x04a0040000000000, 0xff7fffffff7fffff,
             0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
@@ -1068,7 +1068,7 @@ pub mod derived_property {
         XID_Continue_table.lookup(c)
     }
 
-    pub const XID_Start_table: &super::BoolTrie = &super::BoolTrie {
+    const XID_Start_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff,
             0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
@@ -1250,8 +1250,8 @@ pub mod derived_property {
 
 }
 
-pub mod property {
-    pub const Pattern_White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
+pub(crate) mod property {
+    const Pattern_White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
         r1: &[
             0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -1268,7 +1268,7 @@ pub mod property {
         Pattern_White_Space_table.lookup(c)
     }
 
-    pub const White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
+    const White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
         r1: &[
             0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -1290,7 +1290,7 @@ pub mod property {
 
 }
 
-pub mod conversions {
+pub(crate) mod conversions {
     pub fn to_lower(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_lowercase_table) {
             None        => [c, '\0', '\0'],
diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py
index 5389d1cf803..6de5d9e033b 100755
--- a/src/libcore/unicode/unicode.py
+++ b/src/libcore/unicode/unicode.py
@@ -606,7 +606,7 @@ def compute_trie(raw_data, chunk_size):
     return root, child_data
 
 
-def generate_bool_trie(name, codepoint_ranges, is_pub=True):
+def generate_bool_trie(name, codepoint_ranges, is_pub=False):
     # type: (str, List[Tuple[int, int]], bool) -> Iterator[str]
     """
     Generate Rust code for BoolTrie struct.
@@ -681,7 +681,7 @@ def generate_bool_trie(name, codepoint_ranges, is_pub=True):
     yield "    };\n\n"
 
 
-def generate_small_bool_trie(name, codepoint_ranges, is_pub=True):
+def generate_small_bool_trie(name, codepoint_ranges, is_pub=False):
     # type: (str, List[Tuple[int, int]], bool) -> Iterator[str]
     """
     Generate Rust code for `SmallBoolTrie` struct.
@@ -726,7 +726,7 @@ def generate_property_module(mod, grouped_categories, category_subset):
     Generate Rust code for module defining properties.
     """
 
-    yield "pub mod %s {\n" % mod
+    yield "pub(crate) mod %s {\n" % mod
     for cat in sorted(category_subset):
         if cat in ("Cc", "White_Space", "Pattern_White_Space"):
             generator = generate_small_bool_trie("%s_table" % cat, grouped_categories[cat])
@@ -749,7 +749,7 @@ def generate_conversions_module(unicode_data):
     Generate Rust code for module defining conversions.
     """
 
-    yield "pub mod conversions {"
+    yield "pub(crate) mod conversions {"
     yield """
     pub fn to_lower(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_lowercase_table) {
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 4040c0166d8..9dce61492da 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -229,6 +229,13 @@ fn def_id_visibility<'tcx>(
             let vis = match tcx.hir().get(hir_id) {
                 Node::Item(item) => &item.vis,
                 Node::ForeignItem(foreign_item) => &foreign_item.vis,
+                Node::MacroDef(macro_def) => {
+                    if attr::contains_name(&macro_def.attrs, sym::macro_export) {
+                        return (ty::Visibility::Public, macro_def.span, "public");
+                    } else {
+                        &macro_def.vis
+                    }
+                },
                 Node::TraitItem(..) | Node::Variant(..) => {
                     return def_id_visibility(tcx, tcx.hir().get_parent_did(hir_id));
                 }
@@ -433,11 +440,24 @@ impl VisibilityLike for Option<AccessLevel> {
 struct EmbargoVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
 
-    // Accessibility levels for reachable nodes.
+    /// Accessibility levels for reachable nodes.
     access_levels: AccessLevels,
-    // Previous accessibility level; `None` means unreachable.
+    /// A set of pairs corresponding to modules, where the first module is
+    /// reachable via a macro that's defined in the second module. This cannot
+    /// be represented as reachable because it can't handle the following case:
+    ///
+    /// pub mod n {                         // Should be `Public`
+    ///     pub(crate) mod p {              // Should *not* be accessible
+    ///         pub fn f() -> i32 { 12 }    // Must be `Reachable`
+    ///     }
+    /// }
+    /// pub macro m() {
+    ///     n::p::f()
+    /// }
+    macro_reachable: FxHashSet<(hir::HirId, DefId)>,
+    /// Previous accessibility level; `None` means unreachable.
     prev_level: Option<AccessLevel>,
-    // Has something changed in the level map?
+    /// Has something changed in the level map?
     changed: bool,
 }
 
@@ -452,7 +472,7 @@ impl EmbargoVisitor<'tcx> {
         self.access_levels.map.get(&id).cloned()
     }
 
-    // Updates node level and returns the updated level.
+    /// Updates node level and returns the updated level.
     fn update(&mut self, id: hir::HirId, level: Option<AccessLevel>) -> Option<AccessLevel> {
         let old_level = self.get(id);
         // Accessibility levels can only grow.
@@ -477,6 +497,127 @@ impl EmbargoVisitor<'tcx> {
         }
     }
 
+    /// Updates the item as being reachable through a macro defined in the given
+    /// module. Returns `true` if the level has changed.
+    fn update_macro_reachable(&mut self, reachable_mod: hir::HirId, defining_mod: DefId) -> bool {
+        if self.macro_reachable.insert((reachable_mod, defining_mod)) {
+            self.update_macro_reachable_mod(reachable_mod, defining_mod);
+            true
+        } else {
+            false
+        }
+    }
+
+    fn update_macro_reachable_mod(
+        &mut self,
+        reachable_mod: hir::HirId,
+        defining_mod: DefId,
+    ) {
+        let module_def_id = self.tcx.hir().local_def_id(reachable_mod);
+        let module = self.tcx.hir().get_module(module_def_id).0;
+        for item_id in &module.item_ids {
+            let hir_id = item_id.id;
+            let item_def_id = self.tcx.hir().local_def_id(hir_id);
+            if let Some(def_kind) = self.tcx.def_kind(item_def_id) {
+                let item = self.tcx.hir().expect_item(hir_id);
+                let vis = ty::Visibility::from_hir(&item.vis, hir_id, self.tcx);
+                self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod);
+            }
+        }
+
+        if let Some(exports) = self.tcx.module_exports(module_def_id) {
+            for export in exports {
+                if export.vis.is_accessible_from(defining_mod, self.tcx) {
+                    if let Res::Def(def_kind, def_id) = export.res {
+                        let vis = def_id_visibility(self.tcx, def_id).0;
+                        if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) {
+                            self.update_macro_reachable_def(
+                                hir_id,
+                                def_kind,
+                                vis,
+                                defining_mod,
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    fn update_macro_reachable_def(
+        &mut self,
+        hir_id: hir::HirId,
+        def_kind: DefKind,
+        vis: ty::Visibility,
+        module: DefId,
+    ) {
+        let level = Some(AccessLevel::Reachable);
+        if let ty::Visibility::Public = vis {
+            self.update(hir_id, level);
+        }
+        match def_kind {
+            // No type privacy, so can be directly marked as reachable.
+            DefKind::Const
+            | DefKind::Macro(_)
+            | DefKind::Static
+            | DefKind::TraitAlias
+            | DefKind::TyAlias => {
+                if vis.is_accessible_from(module, self.tcx) {
+                    self.update(hir_id, level);
+                }
+            },
+
+            // We can't use a module name as the final segment of a path, except
+            // in use statements. Since re-export checking doesn't consider
+            // hygiene these don't need to be marked reachable. The contents of
+            // the module, however may be reachable.
+            DefKind::Mod => {
+                if vis.is_accessible_from(module, self.tcx) {
+                    self.update_macro_reachable(hir_id, module);
+                }
+            }
+
+            DefKind::Struct | DefKind::Union => {
+                // While structs and unions have type privacy, their fields do
+                // not.
+                if let ty::Visibility::Public = vis {
+                    let item = self.tcx.hir().expect_item(hir_id);
+                    if let hir::ItemKind::Struct(ref struct_def, _)
+                        | hir::ItemKind::Union(ref struct_def, _) = item.node
+                    {
+                        for field in struct_def.fields() {
+                            let field_vis = ty::Visibility::from_hir(
+                                &field.vis,
+                                field.hir_id,
+                                self.tcx,
+                            );
+                            if field_vis.is_accessible_from(module, self.tcx) {
+                                self.reach(field.hir_id, level).ty();
+                            }
+                        }
+                    } else {
+                        bug!("item {:?} with DefKind {:?}", item, def_kind);
+                    }
+                }
+            }
+
+            // These have type privacy, so are not reachable unless they're
+            // public
+            DefKind::AssocConst
+            | DefKind::AssocTy
+            | DefKind::AssocOpaqueTy
+            | DefKind::ConstParam
+            | DefKind::Ctor(_, _)
+            | DefKind::Enum
+            | DefKind::ForeignTy
+            | DefKind::Fn
+            | DefKind::OpaqueTy
+            | DefKind::Method
+            | DefKind::Trait
+            | DefKind::TyParam
+            | DefKind::Variant => (),
+        }
+    }
 
     /// Given the path segments of a `ItemKind::Use`, then we need
     /// to update the visibility of the intermediate use so that it isn't linted
@@ -746,40 +887,21 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             return
         }
 
-        let module_did = ty::DefIdTree::parent(
+        let macro_module_def_id = ty::DefIdTree::parent(
             self.tcx,
             self.tcx.hir().local_def_id(md.hir_id)
         ).unwrap();
-        let mut module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap();
+        let mut module_id = self.tcx.hir().as_local_hir_id(macro_module_def_id).unwrap();
         let level = if md.vis.node.is_pub() { self.get(module_id) } else { None };
-        let level = self.update(md.hir_id, level);
-        if level.is_none() {
+        let new_level = self.update(md.hir_id, level);
+        if new_level.is_none() {
             return
         }
 
         loop {
-            let module = if module_id == hir::CRATE_HIR_ID {
-                &self.tcx.hir().krate().module
-            } else if let hir::ItemKind::Mod(ref module) =
-                          self.tcx.hir().expect_item(module_id).node {
-                module
-            } else {
-                unreachable!()
-            };
-            for id in &module.item_ids {
-                self.update(id.id, level);
-            }
-            let def_id = self.tcx.hir().local_def_id(module_id);
-            if let Some(exports) = self.tcx.module_exports(def_id) {
-                for export in exports.iter() {
-                    if let Some(hir_id) = self.tcx.hir().as_local_hir_id(export.res.def_id()) {
-                        self.update(hir_id, level);
-                    }
-                }
-            }
-
-            if module_id == hir::CRATE_HIR_ID {
-                break
+            let changed_reachability = self.update_macro_reachable(module_id, macro_module_def_id);
+            if changed_reachability || module_id == hir::CRATE_HIR_ID {
+                break;
             }
             module_id = self.tcx.hir().get_parent_node(module_id);
         }
@@ -826,7 +948,12 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> { self.ev.tcx }
     fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
         if let Some(hir_id) = self.ev.tcx.hir().as_local_hir_id(def_id) {
-            self.ev.update(hir_id, self.access_level);
+            if let ((ty::Visibility::Public, ..), _)
+                | (_, Some(AccessLevel::ReachableFromImplTrait))
+                = (def_id_visibility(self.tcx(), def_id), self.access_level)
+            {
+                self.ev.update(hir_id, self.access_level);
+            }
         }
         false
     }
@@ -1865,6 +1992,7 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, krate: CrateNum) -> &AccessLevels {
     let mut visitor = EmbargoVisitor {
         tcx,
         access_levels: Default::default(),
+        macro_reachable: Default::default(),
         prev_level: Some(AccessLevel::Public),
         changed: false,
     };
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 2a299cc4f92..2ae13b66e28 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -645,7 +645,7 @@ impl<'a, 'b> Context<'a, 'b> {
         let mut heads = Vec::with_capacity(self.args.len());
 
         let names_pos: Vec<_> = (0..self.args.len())
-            .map(|i| self.ecx.ident_of(&format!("arg{}", i)).gensym())
+            .map(|i| ast::Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
             .collect();
 
         // First, build up the static array which will become our precompiled
@@ -842,7 +842,7 @@ pub fn expand_preparsed_format_args(
     let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
 
     let mut macsp = ecx.call_site();
-    macsp = macsp.apply_mark(ecx.current_expansion.id);
+    macsp = macsp.with_ctxt(ecx.backtrace());
 
     let msg = "format argument must be a string literal";
     let fmt_sp = efmt.span;
diff --git a/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs b/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs
new file mode 100644
index 00000000000..30ba70bdfeb
--- /dev/null
+++ b/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs
@@ -0,0 +1,23 @@
+#![feature(decl_macro)]
+
+mod n {
+    pub struct B(pub(crate) p::C);
+    impl B {
+        pub fn new() -> Self {
+            B(p::C)
+        }
+    }
+    mod p {
+        pub struct C;
+
+        impl C {
+            pub fn foo(&self) -> i32 {
+                33
+            }
+        }
+    }
+}
+
+pub macro m() {
+    n::B::new().0.foo()
+}
diff --git a/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs b/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs
new file mode 100644
index 00000000000..a39e8c986c3
--- /dev/null
+++ b/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs
@@ -0,0 +1,11 @@
+#![feature(decl_macro)]
+
+mod n {
+    pub(crate) mod p {
+        pub fn f() -> i32 { 12 }
+    }
+}
+
+pub macro m() {
+    n::p::f()
+}
diff --git a/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs b/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs
new file mode 100644
index 00000000000..4f283d9c19c
--- /dev/null
+++ b/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs
@@ -0,0 +1,11 @@
+#![feature(decl_macro)]
+
+mod n {
+    pub static S: i32 = 57;
+}
+
+use n::S;
+
+pub macro m() {
+    S
+}
diff --git a/src/test/ui/definition-reachable/field-method.rs b/src/test/ui/definition-reachable/field-method.rs
new file mode 100644
index 00000000000..60e895a2f9a
--- /dev/null
+++ b/src/test/ui/definition-reachable/field-method.rs
@@ -0,0 +1,11 @@
+// Check that functions accessible through a field visible to a macro are
+// considered reachable
+
+// aux-build:nested-fn-macro.rs
+// run-pass
+
+extern crate nested_fn_macro;
+
+fn main() {
+    assert_eq!(nested_fn_macro::m!(), 12);
+}
diff --git a/src/test/ui/definition-reachable/nested-fn.rs b/src/test/ui/definition-reachable/nested-fn.rs
new file mode 100644
index 00000000000..b596ba8936a
--- /dev/null
+++ b/src/test/ui/definition-reachable/nested-fn.rs
@@ -0,0 +1,11 @@
+// Check that functions visible to macros through paths with >2 segements are
+// considered reachable
+
+// aux-build:field-method-macro.rs
+// run-pass
+
+extern crate field_method_macro;
+
+fn main() {
+    assert_eq!(field_method_macro::m!(), 33);
+}
diff --git a/src/test/ui/definition-reachable/private-non-types.rs b/src/test/ui/definition-reachable/private-non-types.rs
new file mode 100644
index 00000000000..a601dabcb0b
--- /dev/null
+++ b/src/test/ui/definition-reachable/private-non-types.rs
@@ -0,0 +1,21 @@
+// Check that we don't require stability annotations for private modules,
+// imports and fields that are accessible to opaque macros.
+
+// check-pass
+
+#![feature(decl_macro, staged_api)]
+#![stable(feature = "test", since = "1.0.0")]
+
+extern crate std as local_std;
+use local_std::marker::Copy as LocalCopy;
+mod private_mod {
+    #[stable(feature = "test", since = "1.0.0")]
+    pub struct A {
+        pub(crate) f: i32,
+    }
+}
+
+#[stable(feature = "test", since = "1.0.0")]
+pub macro m() {}
+
+fn main() {}
diff --git a/src/test/ui/definition-reachable/private-types.rs b/src/test/ui/definition-reachable/private-types.rs
new file mode 100644
index 00000000000..02c1224f4e1
--- /dev/null
+++ b/src/test/ui/definition-reachable/private-types.rs
@@ -0,0 +1,19 @@
+// Check that type privacy is taken into account when considering reachability
+
+// check-pass
+
+#![feature(decl_macro, staged_api)]
+#![stable(feature = "test", since = "1.0.0")]
+
+// Type privacy should prevent use of these in other crates, so we shouldn't
+// need a stability annotation.
+fn private_function() {}
+struct PrivateStruct { f: () }
+enum PrivateEnum { V }
+union PrivateUnion { g: () }
+trait PrivateTrait {}
+
+#[stable(feature = "test", since = "1.0.0")]
+pub macro m() {}
+
+fn main() {}
diff --git a/src/test/ui/definition-reachable/private-use.rs b/src/test/ui/definition-reachable/private-use.rs
new file mode 100644
index 00000000000..02cff0475e5
--- /dev/null
+++ b/src/test/ui/definition-reachable/private-use.rs
@@ -0,0 +1,10 @@
+// Check that private use statements can be used by
+
+// run-pass
+// aux-build:private-use-macro.rs
+
+extern crate private_use_macro;
+
+fn main() {
+    assert_eq!(private_use_macro::m!(), 57);
+}
diff --git a/src/test/ui/format-hygiene.rs b/src/test/ui/format-hygiene.rs
deleted file mode 100644
index 6bf5ae8bead..00000000000
--- a/src/test/ui/format-hygiene.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// run-pass
-
-#![allow(non_upper_case_globals)]
-pub const arg0: u8 = 1;
-
-pub fn main() {
-    format!("{}", 1);
-}
diff --git a/src/test/ui/hygiene/format-args.rs b/src/test/ui/hygiene/format-args.rs
new file mode 100644
index 00000000000..d74889b95cc
--- /dev/null
+++ b/src/test/ui/hygiene/format-args.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![allow(non_upper_case_globals)]
+#![feature(format_args_nl)]
+
+static arg0: () = ();
+
+fn main() {
+    static arg1: () = ();
+    format_args!("{} {:?}", 0, 1);
+    format_args_nl!("{} {:?}", 0, 1);
+}