From 8ae8bc2808bd3b5e125b72a44bfdcd24353e5211 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 5 Aug 2019 23:06:02 +0100 Subject: [PATCH 1/3] Fix various issues with making items reachable through macros * Allow items to be accessible through private modules and fields when a macro can access them. * Don't mark type-private items as reachable. * Never make items exported/public via macros --- src/librustc_privacy/lib.rs | 190 +++++++++++++++--- .../auxiliary/field-method-macro.rs | 23 +++ .../auxiliary/nested-fn-macro.rs | 11 + .../auxiliary/private-use-macro.rs | 11 + .../ui/definition-reachable/field-method.rs | 11 + src/test/ui/definition-reachable/nested-fn.rs | 11 + .../definition-reachable/private-non-types.rs | 21 ++ .../ui/definition-reachable/private-types.rs | 19 ++ .../ui/definition-reachable/private-use.rs | 10 + 9 files changed, 276 insertions(+), 31 deletions(-) create mode 100644 src/test/ui/definition-reachable/auxiliary/field-method-macro.rs create mode 100644 src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs create mode 100644 src/test/ui/definition-reachable/auxiliary/private-use-macro.rs create mode 100644 src/test/ui/definition-reachable/field-method.rs create mode 100644 src/test/ui/definition-reachable/nested-fn.rs create mode 100644 src/test/ui/definition-reachable/private-non-types.rs create mode 100644 src/test/ui/definition-reachable/private-types.rs create mode 100644 src/test/ui/definition-reachable/private-use.rs diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index ac18f0e440b78..330370e3803dd 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(¯o_def.attrs, sym::macro_export) { + return (ty::Visibility::Public, macro_def.span, "public"); + } else { + ¯o_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 { 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, - // 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) -> Option { 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 } @@ -1860,6 +1987,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/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 0000000000000..30ba70bdfeb66 --- /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 0000000000000..a39e8c986c391 --- /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 0000000000000..4f283d9c19c04 --- /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 0000000000000..60e895a2f9a07 --- /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 0000000000000..b596ba8936a43 --- /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 0000000000000..a601dabcb0b3f --- /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 0000000000000..02c1224f4e142 --- /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 0000000000000..02cff0475e586 --- /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); +} From 7b41fd215893c06110c7f650be47efed3910d90b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 5 Aug 2019 23:06:40 +0100 Subject: [PATCH 2/3] Make some items in core::unicode private They were reachable through opaque macros defined in `core` --- src/libcore/unicode/tables.rs | 32 ++++++++++++++++---------------- src/libcore/unicode/unicode.py | 8 ++++---- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index bfe784afaa47d..3fae3a46ada6b 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 5389d1cf80383..6de5d9e033b93 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) { From d9d9246418ae884cb67feb3574832696660b8e2e Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 5 Aug 2019 23:10:32 +0100 Subject: [PATCH 3/3] Remove gensym from format_args --- src/libcore/macros.rs | 2 -- src/libsyntax_ext/format.rs | 4 ++-- src/test/ui/format-hygiene.rs | 8 -------- src/test/ui/hygiene/format-args.rs | 12 ++++++++++++ 4 files changed, 14 insertions(+), 12 deletions(-) delete mode 100644 src/test/ui/format-hygiene.rs create mode 100644 src/test/ui/hygiene/format-args.rs diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 37cc71bff62b4..6a2c3bff4ddca 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -767,7 +767,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 */ }) @@ -779,7 +778,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/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index fe9cad1e32fca..1dfcc14021c3b 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -646,7 +646,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 @@ -843,7 +843,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/format-hygiene.rs b/src/test/ui/format-hygiene.rs deleted file mode 100644 index 6bf5ae8beaddb..0000000000000 --- 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 0000000000000..d74889b95cc12 --- /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); +}