}
}
- if let EntryKind::Mod(data) = kind {
- for exp in data.decode((self, sess)).reexports.decode((self, sess)) {
+ if let EntryKind::Mod(exports) = kind {
+ for exp in exports.decode((self, sess)) {
match exp.res {
Res::Def(DefKind::Macro(..), _) => {}
_ if macros_only => continue,
}
fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
- if let EntryKind::Mod(m) = self.kind(id) {
- m.decode((self, sess)).expansion
- } else {
- panic!("Expected module, found {:?}", self.local_def_id(id))
+ match self.kind(id) {
+ EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => {
+ self.get_expn_that_defined(id, sess)
+ }
+ _ => panic!("Expected module, found {:?}", self.local_def_id(id)),
}
}
Lazy::empty()
};
- let data = ModData { reexports, expansion: tcx.expn_that_defined(local_def_id) };
-
- record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
+ record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
if self.is_proc_macro {
record!(self.tables.children[def_id] <- &[]);
+ // Encode this here because we don't do it in encode_def_ids.
+ record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
} else {
record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| {
item_id.def_id.local_def_index
Union(Lazy<VariantData>, ReprOptions),
Fn(Lazy<FnData>),
ForeignFn(Lazy<FnData>),
- Mod(Lazy<ModData>),
+ Mod(Lazy<[Export]>),
MacroDef(Lazy<MacroDef>),
ProcMacro(MacroKind),
Closure,
#[derive(Encodable, Decodable)]
struct RenderedConst(String);
-#[derive(MetadataEncodable, MetadataDecodable)]
-struct ModData {
- reexports: Lazy<[Export]>,
- expansion: ExpnId,
-}
-
#[derive(MetadataEncodable, MetadataDecodable)]
struct FnData {
asyncness: hir::IsAsync,
} else {
def_key.disambiguated_data.data.get_opt_name().expect("module without name")
};
- let expn_id = if def_kind == DefKind::Mod {
- self.cstore().module_expansion_untracked(def_id, &self.session)
- } else {
- // FIXME: Parent expansions for enums and traits are not kept in metadata.
- ExpnId::root()
- };
Some(self.new_module(
parent,
ModuleKind::Def(def_kind, def_id, name),
- expn_id,
+ self.cstore().module_expansion_untracked(def_id, &self.session),
self.cstore().get_span_untracked(def_id, &self.session),
// FIXME: Account for `#[no_implicit_prelude]` attributes.
parent.map_or(false, |module| module.no_implicit_prelude),
// collect results based on the filter function
// avoid suggesting anything from the same module in which we are resolving
+ // avoid suggesting anything with a hygienic name
if ident.name == lookup_ident.name
&& ns == namespace
&& !ptr::eq(in_module, parent_scope.module)
+ && !ident.span.normalize_to_macros_2_0().from_expansion()
{
let res = name_binding.res();
if filter_fn(res) {
/// pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`.
/// pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
/// }
- /// n(f);
+ /// n!(f);
/// macro n($j:ident) {
/// use foo::*;
/// f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
--- /dev/null
+#![feature(decl_macro)]
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum Field {
+ RootCtxt,
+ MacroCtxt,
+}
+
+#[rustfmt::skip]
+macro x(
+ $macro_name:ident,
+ $macro2_name:ident,
+ $type_name:ident,
+ $field_name:ident,
+ $const_name:ident
+) {
+ #[derive(Copy, Clone)]
+ pub struct $type_name {
+ pub field: Field,
+ pub $field_name: Field,
+ }
+
+ pub const $const_name: $type_name =
+ $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt };
+
+ #[macro_export]
+ macro_rules! $macro_name {
+ (check_fields_of $e:expr) => {{
+ let e = $e;
+ assert_eq!(e.field, Field::MacroCtxt);
+ assert_eq!(e.$field_name, Field::RootCtxt);
+ }};
+ (check_fields) => {{
+ assert_eq!($const_name.field, Field::MacroCtxt);
+ assert_eq!($const_name.$field_name, Field::RootCtxt);
+ }};
+ (construct) => {
+ $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt }
+ };
+ }
+
+ pub macro $macro2_name {
+ (check_fields_of $e:expr) => {{
+ let e = $e;
+ assert_eq!(e.field, Field::MacroCtxt);
+ assert_eq!(e.$field_name, Field::RootCtxt);
+ }},
+ (check_fields) => {{
+ assert_eq!($const_name.field, Field::MacroCtxt);
+ assert_eq!($const_name.$field_name, Field::RootCtxt);
+ }},
+ (construct) => {
+ $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt }
+ }
+ }
+}
+
+x!(test_fields, test_fields2, MyStruct, field, MY_CONST);
+
+pub fn check_fields(s: MyStruct) {
+ test_fields!(check_fields_of s);
+}
+
+pub fn check_fields_local() {
+ test_fields!(check_fields);
+ test_fields2!(check_fields);
+
+ let s1 = test_fields!(construct);
+ test_fields!(check_fields_of s1);
+
+ let s2 = test_fields2!(construct);
+ test_fields2!(check_fields_of s2);
+}
--- /dev/null
+#![feature(decl_macro)]
+
+#[derive(PartialEq, Eq, Debug)]
+pub enum Method {
+ DefaultMacroCtxt,
+ DefaultRootCtxt,
+ OverrideMacroCtxt,
+ OverrideRootCtxt,
+}
+
+#[rustfmt::skip]
+macro x($macro_name:ident, $macro2_name:ident, $trait_name:ident, $method_name:ident) {
+ pub trait $trait_name {
+ fn method(&self) -> Method {
+ Method::DefaultMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::DefaultRootCtxt
+ }
+ }
+
+ impl $trait_name for () {}
+ impl $trait_name for bool {
+ fn method(&self) -> Method {
+ Method::OverrideMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::OverrideRootCtxt
+ }
+ }
+
+ #[macro_export]
+ macro_rules! $macro_name {
+ (check_resolutions) => {
+ assert_eq!(().method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt);
+ assert_eq!(().$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt);
+
+ assert_eq!(false.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt);
+ assert_eq!(false.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt);
+
+ assert_eq!('a'.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt);
+ assert_eq!('a'.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt);
+
+ assert_eq!(1i32.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt);
+ assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt);
+
+ assert_eq!(1i64.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt);
+ assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt);
+ };
+ (assert_no_override $v:expr) => {
+ assert_eq!($v.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt);
+ assert_eq!($v.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt);
+ };
+ (assert_override $v:expr) => {
+ assert_eq!($v.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt);
+ assert_eq!($v.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt);
+ };
+ (impl for $t:ty) => {
+ impl $trait_name for $t {
+ fn method(&self) -> Method {
+ Method::OverrideMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::OverrideRootCtxt
+ }
+ }
+ };
+ }
+
+ pub macro $macro2_name {
+ (check_resolutions) => {
+ assert_eq!(().method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt);
+ assert_eq!(().$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt);
+
+ assert_eq!(false.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt);
+ assert_eq!(false.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt);
+
+ assert_eq!('a'.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt);
+ assert_eq!('a'.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt);
+
+ assert_eq!(1i32.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt);
+ assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt);
+
+ assert_eq!(1i64.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt);
+ assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt);
+ },
+ (assert_no_override $v:expr) => {
+ assert_eq!($v.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt);
+ assert_eq!($v.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt);
+ },
+ (assert_override $v:expr) => {
+ assert_eq!($v.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt);
+ assert_eq!($v.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt);
+ },
+ (impl for $t:ty) => {
+ impl $trait_name for $t {
+ fn method(&self) -> Method {
+ Method::OverrideMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::OverrideRootCtxt
+ }
+ }
+ }
+ }
+}
+
+x!(test_trait, test_trait2, MyTrait, method);
+
+impl MyTrait for char {}
+test_trait!(impl for i32);
+test_trait2!(impl for i64);
+
+pub fn check_crate_local() {
+ test_trait!(check_resolutions);
+ test_trait2!(check_resolutions);
+}
+
+// Check that any comparison of idents at monomorphization time is correct
+pub fn check_crate_local_generic<T: MyTrait, U: MyTrait>(t: T, u: U) {
+ test_trait!(check_resolutions);
+ test_trait2!(check_resolutions);
+
+ test_trait!(assert_no_override t);
+ test_trait2!(assert_no_override t);
+ test_trait!(assert_override u);
+ test_trait2!(assert_override u);
+}
--- /dev/null
+#![feature(decl_macro)]
+
+macro x() {
+ pub struct MyStruct;
+}
+
+x!();
--- /dev/null
+#![feature(decl_macro)]
+
+macro x($macro_name:ident) {
+ #[macro_export]
+ macro_rules! $macro_name {
+ (define) => {
+ pub struct MyStruct;
+ };
+ (create) => {
+ MyStruct {}
+ };
+ }
+}
+
+x!(my_struct);
--- /dev/null
+#![feature(decl_macro)]
+
+#[rustfmt::skip]
+macro x($macro_name:ident, $macro2_name:ident, $type_name:ident, $variant_name:ident) {
+ #[repr(u8)]
+ pub enum $type_name {
+ Variant = 0,
+ $variant_name = 1,
+ }
+
+ #[macro_export]
+ macro_rules! $macro_name {
+ () => {{
+ assert_eq!($type_name::Variant as u8, 0);
+ assert_eq!($type_name::$variant_name as u8, 1);
+ assert_eq!(<$type_name>::Variant as u8, 0);
+ assert_eq!(<$type_name>::$variant_name as u8, 1);
+ }};
+ }
+
+ pub macro $macro2_name {
+ () => {{
+ assert_eq!($type_name::Variant as u8, 0);
+ assert_eq!($type_name::$variant_name as u8, 1);
+ assert_eq!(<$type_name>::Variant as u8, 0);
+ assert_eq!(<$type_name>::$variant_name as u8, 1);
+ }},
+ }
+}
+
+x!(test_variants, test_variants2, MyEnum, Variant);
+
+pub fn check_variants() {
+ test_variants!();
+ test_variants2!();
+}
--- /dev/null
+// Check that a marco from another crate can define an item in one expansion
+// and use it from another, without it being visible to everyone.
+// This requires that the definition of `my_struct` preserves the hygiene
+// information for the tokens in its definition.
+
+// check-pass
+// aux-build:use_by_macro.rs
+
+#![feature(type_name_of_val)]
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+enum MyStruct {}
+my_struct!(define);
+
+fn main() {
+ let x = my_struct!(create);
+}
--- /dev/null
+// Test that fields on a struct defined in another crate are resolved correctly
+// their names differ only in `SyntaxContext`.
+
+// run-pass
+// aux-build:fields.rs
+
+extern crate fields;
+
+use fields::*;
+
+fn main() {
+ check_fields_local();
+
+ test_fields!(check_fields);
+ test_fields2!(check_fields);
+
+ let s1 = test_fields!(construct);
+ check_fields(s1);
+ test_fields!(check_fields_of s1);
+
+ let s2 = test_fields2!(construct);
+ check_fields(s2);
+ test_fields2!(check_fields_of s2);
+}
--- /dev/null
+// Check that globs cannot import hygienic identifiers from a macro expansion
+// in another crate. `my_struct` is a `macro_rules` macro, so the struct it
+// defines is only not imported because `my_struct` is defined by a macros 2.0
+// macro.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+mod m {
+ use use_by_macro::*;
+
+ my_struct!(define);
+}
+
+use m::*;
+
+fn main() {
+ let x = my_struct!(create);
+ //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
--- /dev/null
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+ --> $DIR/cross-crate-glob-hygiene.rs:21:13
+ |
+LL | let x = my_struct!(create);
+ | ^^^^^^^^^^^^^^^^^^ not found in this scope
+ |
+ = note: this error originates in the macro `my_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
--- /dev/null
+// Test that methods defined in another crate are resolved correctly their
+// names differ only in `SyntaxContext`. This also checks that any name
+// resolution done when monomorphizing is correct.
+
+// run-pass
+// aux-build:methods.rs
+
+extern crate methods;
+
+use methods::*;
+
+struct A;
+struct B;
+struct C;
+
+impl MyTrait for A {}
+test_trait!(impl for B);
+test_trait2!(impl for C);
+
+fn main() {
+ check_crate_local();
+ check_crate_local_generic(A, B);
+ check_crate_local_generic(A, C);
+
+ test_trait!(check_resolutions);
+ test_trait2!(check_resolutions);
+ test_trait!(assert_no_override A);
+ test_trait2!(assert_no_override A);
+ test_trait!(assert_override B);
+ test_trait2!(assert_override B);
+ test_trait!(assert_override C);
+ test_trait2!(assert_override C);
+}
--- /dev/null
+// Check that two items defined in another crate that have identifiers that
+// only differ by `SyntaxContext` do not cause name collisions when imported
+// in another crate.
+
+// check-pass
+// aux-build:needs_hygiene.rs
+
+extern crate needs_hygiene;
+
+use needs_hygiene::*;
+
+fn main() {}
--- /dev/null
+// Check that an identifier from a 2.0 macro in another crate cannot be
+// resolved with an identifier that's not from a macro expansion.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+my_struct!(define);
+
+fn main() {
+ let x = MyStruct {};
+ //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
--- /dev/null
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+ --> $DIR/cross-crate-name-hiding-2.rs:13:13
+ |
+LL | let x = MyStruct {};
+ | ^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
--- /dev/null
+// Check that an item defined by a 2.0 macro in another crate cannot be used in
+// another crate.
+
+// aux-build:pub_hygiene.rs
+
+extern crate pub_hygiene;
+
+use pub_hygiene::*;
+
+fn main() {
+ let x = MyStruct {};
+ //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
--- /dev/null
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+ --> $DIR/cross-crate-name-hiding.rs:11:13
+ |
+LL | let x = MyStruct {};
+ | ^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
--- /dev/null
+// Check that items with identical `SyntaxContext` conflict even when that
+// context involves a mark from another crate.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+my_struct!(define);
+//~^ ERROR the name `MyStruct` is defined multiple times
+my_struct!(define);
+
+fn main() {}
--- /dev/null
+error[E0428]: the name `MyStruct` is defined multiple times
+ --> $DIR/cross-crate-redefine.rs:10:1
+ |
+LL | my_struct!(define);
+ | ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here
+LL |
+LL | my_struct!(define);
+ | ------------------ previous definition of the type `MyStruct` here
+ |
+ = note: `MyStruct` must be defined only once in the type namespace of this module
+ = note: this error originates in the macro `my_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0428`.
--- /dev/null
+// Test that variants of an enum defined in another crate are resolved
+// correctly when their names differ only in `SyntaxContext`.
+
+// run-pass
+// aux-build:variants.rs
+
+extern crate variants;
+
+use variants::*;
+
+fn main() {
+ check_variants();
+
+ test_variants!();
+ test_variants2!();
+
+ assert_eq!(MyEnum::Variant as u8, 1);
+}
+++ /dev/null
-// check-pass
-// aux-build:needs_hygiene.rs
-
-extern crate needs_hygiene;
-
-use needs_hygiene::*;
-
-fn main() {}
crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it")
crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site")
crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer")
crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner")
crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)