Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve and test cross-crate hygiene #90202

Merged
merged 5 commits into from
Oct 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1198,8 +1198,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
}
}

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,
Expand All @@ -1219,10 +1219,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
}

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)),
}
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1086,11 +1086,11 @@ impl EncodeContext<'a, 'tcx> {
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
Expand Down
8 changes: 1 addition & 7 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ enum EntryKind {
Union(Lazy<VariantData>, ReprOptions),
Fn(Lazy<FnData>),
ForeignFn(Lazy<FnData>),
Mod(Lazy<ModData>),
Mod(Lazy<[Export]>),
MacroDef(Lazy<MacroDef>),
ProcMacro(MacroKind),
Closure,
Expand All @@ -364,12 +364,6 @@ enum EntryKind {
#[derive(Encodable, Decodable)]
struct RenderedConst(String);

#[derive(MetadataEncodable, MetadataDecodable)]
struct ModData {
reexports: Lazy<[Export]>,
expansion: ExpnId,
}

#[derive(MetadataEncodable, MetadataDecodable)]
struct FnData {
asyncness: hir::IsAsync,
Expand Down
8 changes: 1 addition & 7 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,11 @@ impl<'a> Resolver<'a> {
} 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),
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -831,9 +831,11 @@ impl<'a> Resolver<'a> {

// 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) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_span/src/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@ impl SyntaxContext {
/// 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`
Expand Down
73 changes: 73 additions & 0 deletions src/test/ui/hygiene/auxiliary/fields.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#![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);
}
160 changes: 160 additions & 0 deletions src/test/ui/hygiene/auxiliary/methods.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#![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);
}
7 changes: 7 additions & 0 deletions src/test/ui/hygiene/auxiliary/pub_hygiene.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#![feature(decl_macro)]

macro x() {
pub struct MyStruct;
}

x!();
15 changes: 15 additions & 0 deletions src/test/ui/hygiene/auxiliary/use_by_macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![feature(decl_macro)]

macro x($macro_name:ident) {
#[macro_export]
macro_rules! $macro_name {
(define) => {
pub struct MyStruct;
};
(create) => {
MyStruct {}
};
}
}

x!(my_struct);
36 changes: 36 additions & 0 deletions src/test/ui/hygiene/auxiliary/variants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#![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!();
}
Loading