Skip to content

Commit 9490e1e

Browse files
committed
Allow items to shadow glob imports
1 parent 7342dd8 commit 9490e1e

File tree

5 files changed

+75
-9
lines changed

5 files changed

+75
-9
lines changed

src/librustc_resolve/build_reduced_graph.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
359359

360360
// These items live in both the type and value namespaces.
361361
ItemStruct(ref struct_def, _) => {
362+
let modifiers = match !struct_def.is_struct() {
363+
true => modifiers | DefModifiers::LINKED_NAMESPACES,
364+
false => modifiers,
365+
};
366+
362367
// Define a name in the type namespace.
363368
let def = Def::Struct(self.ast_map.local_def_id(item.id));
364369
self.define(parent, name, TypeNS, (def, sp, modifiers));
@@ -434,7 +439,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
434439

435440
// Variants are always treated as importable to allow them to be glob used.
436441
// All variants are defined in both type and value namespaces as future-proofing.
437-
let modifiers = DefModifiers::PUBLIC | DefModifiers::IMPORTABLE | variant_modifiers;
442+
let modifiers = DefModifiers::PUBLIC | DefModifiers::IMPORTABLE | variant_modifiers |
443+
DefModifiers::LINKED_NAMESPACES;
438444
let def = Def::Variant(item_id, self.ast_map.local_def_id(variant.node.data.id()));
439445

440446
self.define(parent, name, ValueNS, (def, variant.span, modifiers));
@@ -523,7 +529,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
523529
final_ident);
524530
// Variants are always treated as importable to allow them to be glob used.
525531
// All variants are defined in both type and value namespaces as future-proofing.
526-
let modifiers = DefModifiers::PUBLIC | DefModifiers::IMPORTABLE;
532+
let modifiers = DefModifiers::PUBLIC | DefModifiers::IMPORTABLE |
533+
DefModifiers::LINKED_NAMESPACES;
527534
self.try_define(new_parent, name, TypeNS, (def, DUMMY_SP, modifiers));
528535
self.try_define(new_parent, name, ValueNS, (def, DUMMY_SP, modifiers));
529536
if self.session.cstore.variant_kind(variant_id) == Some(VariantKind::Struct) {
@@ -577,8 +584,14 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
577584
debug!("(building reduced graph for external crate) building type and value for \
578585
{}",
579586
final_ident);
587+
let ctor_def_id = self.session.cstore.struct_ctor_def_id(def_id);
588+
let modifiers = match ctor_def_id {
589+
Some(_) => modifiers | DefModifiers::LINKED_NAMESPACES,
590+
None => modifiers,
591+
};
592+
580593
self.try_define(new_parent, name, TypeNS, (def, DUMMY_SP, modifiers));
581-
if let Some(ctor_def_id) = self.session.cstore.struct_ctor_def_id(def_id) {
594+
if let Some(ctor_def_id) = ctor_def_id {
582595
let def = Def::Struct(ctor_def_id);
583596
self.try_define(new_parent, name, ValueNS, (def, DUMMY_SP, modifiers));
584597
}

src/librustc_resolve/lib.rs

+14
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,17 @@ impl<'a> ModuleS<'a> {
873873
// Define the name or return the existing binding if there is a collision.
874874
fn try_define_child(&self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>)
875875
-> Result<(), &'a NameBinding<'a>> {
876+
// If binding is glob imported and is an item that defines both namespaces,
877+
// it will be shadowed by an existing non-imported item in either namespace.
878+
if binding.defined_with(DefModifiers::GLOB_IMPORTED | DefModifiers::LINKED_NAMESPACES) {
879+
for &ns in &[ValueNS, TypeNS] {
880+
match self.children.borrow().get(&(name, ns)).cloned().unwrap_or_default().binding {
881+
Some(binding) if !binding.is_import() => return Ok(()),
882+
_ => {}
883+
}
884+
}
885+
}
886+
876887
let mut children = self.children.borrow_mut();
877888
let resolution = children.entry((name, ns)).or_insert_with(Default::default);
878889

@@ -989,6 +1000,9 @@ bitflags! {
9891000
const PRIVATE_VARIANT = 1 << 2,
9901001
const PRELUDE = 1 << 3,
9911002
const GLOB_IMPORTED = 1 << 4,
1003+
// A binding for a name in a namespace has this flag if the name is defined in both
1004+
// namespaces by the same non-import item (i.e. by a tuple struct, unit struct, or variant).
1005+
const LINKED_NAMESPACES = 1 << 5,
9921006
}
9931007
}
9941008

src/librustc_resolve/resolve_imports.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ impl ImportDirective {
9090
if self.shadowable == Shadowable::Always {
9191
modifiers = modifiers | DefModifiers::PRELUDE;
9292
}
93+
if binding.defined_with(DefModifiers::LINKED_NAMESPACES) {
94+
modifiers = modifiers | DefModifiers::LINKED_NAMESPACES;
95+
}
9396

9497
NameBinding {
9598
kind: NameBindingKind::Import { binding: binding, id: self.id },
@@ -136,11 +139,9 @@ impl<'a> NameResolution<'a> {
136139
_ => { self.binding = Some(binding); return Ok(()); }
137140
};
138141

139-
// FIXME #31337: We currently allow items to shadow glob-imported re-exports.
142+
// We currently allow items to shadow glob-imports.
140143
if !old_binding.is_import() && binding.defined_with(DefModifiers::GLOB_IMPORTED) {
141-
if let NameBindingKind::Import { binding, .. } = binding.kind {
142-
if binding.is_import() { return Ok(()); }
143-
}
144+
return Ok(());
144145
}
145146

146147
Err(old_binding)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
mod foo {
12+
pub struct Bar;
13+
14+
pub enum E { V }
15+
pub use self::E::V;
16+
17+
pub fn baz() -> bool {}
18+
pub mod baz { pub fn f() {} }
19+
}
20+
21+
use foo::*;
22+
fn Bar() {}
23+
struct V { x: i32 }
24+
fn baz() {}
25+
26+
fn main() {
27+
// The function `Bar` shadows the imported struct `Bar` in both namespaces
28+
Bar();
29+
let x: Bar = unimplemented!(); //~ ERROR use of undeclared type name `Bar`
30+
31+
// The struct `V` shadows the imported variant `V` in both namespaces
32+
let _ = V { x: 0 };
33+
let _ = V; //~ ERROR `V` is the name of a struct
34+
35+
// The function `baz` only shadows the imported name `baz` in the value namespace
36+
let _: () = baz();
37+
let _ = baz::f();
38+
}

src/test/compile-fail/variant-namespacing.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
// aux-build:variant-namespacing.rs
1212

1313
extern crate variant_namespacing;
14-
pub use variant_namespacing::XE::*;
14+
pub use variant_namespacing::XE::{XStruct, XTuple, XUnit};
1515
//~^ ERROR import `XStruct` conflicts with type in this module
1616
//~| ERROR import `XStruct` conflicts with value in this module
1717
//~| ERROR import `XTuple` conflicts with type in this module
1818
//~| ERROR import `XTuple` conflicts with value in this module
1919
//~| ERROR import `XUnit` conflicts with type in this module
2020
//~| ERROR import `XUnit` conflicts with value in this module
21-
pub use E::*;
21+
pub use E::{Struct, Tuple, Unit};
2222
//~^ ERROR import `Struct` conflicts with type in this module
2323
//~| ERROR import `Struct` conflicts with value in this module
2424
//~| ERROR import `Tuple` conflicts with type in this module

0 commit comments

Comments
 (0)