Skip to content

Commit

Permalink
rustc_resolve: fix a bug in which unused imports can get wrongly mark…
Browse files Browse the repository at this point in the history
…ed as used when checking for unused qualifications in resolve_path (fixes rust-lang#30078)
  • Loading branch information
jseyfried committed Dec 12, 2015
1 parent 9a2549e commit 83dde14
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 16 deletions.
35 changes: 20 additions & 15 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1462,7 +1462,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
fn resolve_item_in_lexical_scope(&mut self,
module_: Rc<Module>,
name: Name,
namespace: Namespace)
namespace: Namespace,
record_used: bool)
-> ResolveResult<(Target, bool)> {
debug!("(resolving item in lexical scope) resolving `{}` in namespace {:?} in `{}`",
name,
Expand Down Expand Up @@ -1502,10 +1503,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
debug!("(resolving item in lexical scope) using import resolution");
// track used imports and extern crates as well
let id = import_resolution[namespace].id;
self.used_imports.insert((id, namespace));
self.record_import_use(id, name);
if let Some(DefId{krate: kid, ..}) = target.target_module.def_id() {
self.used_crates.insert(kid);
if record_used {
self.used_imports.insert((id, namespace));
self.record_import_use(id, name);
if let Some(DefId{krate: kid, ..}) = target.target_module.def_id() {
self.used_crates.insert(kid);
}
}
return Success((target, false));
}
Expand Down Expand Up @@ -1582,7 +1585,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
-> ResolveResult<Rc<Module>> {
// If this module is an anonymous module, resolve the item in the
// lexical scope. Otherwise, resolve the item from the crate root.
let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS);
let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS, true);
match resolve_result {
Success((target, _)) => {
if let Some(module_def) = target.binding.module() {
Expand Down Expand Up @@ -2776,7 +2779,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
span: Span)
-> BareIdentifierPatternResolution {
let module = self.current_module.clone();
match self.resolve_item_in_lexical_scope(module, name, ValueNS) {
match self.resolve_item_in_lexical_scope(module, name, ValueNS, true) {
Success((target, _)) => {
debug!("(resolve bare identifier pattern) succeeded in finding {} at {:?}",
name,
Expand Down Expand Up @@ -2884,17 +2887,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}

// Try to find a path to an item in a module.
let unqualified_def = self.resolve_identifier(segments.last().unwrap().identifier,
namespace,
check_ribs);

let last_ident = segments.last().unwrap().identifier;
if segments.len() <= 1 {
let unqualified_def = self.resolve_identifier(last_ident, namespace, check_ribs, true);
return unqualified_def.and_then(|def| self.adjust_local_def(def, span))
.map(|def| {
PathResolution::new(def, LastMod(AllPublic), path_depth)
});
}

let unqualified_def = self.resolve_identifier(last_ident, namespace, check_ribs, false);
let def = self.resolve_module_relative_path(span, segments, namespace);
match (def, unqualified_def) {
(Some((ref d, _)), Some(ref ud)) if *d == ud.def => {
Expand All @@ -2914,7 +2916,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
fn resolve_identifier(&mut self,
identifier: hir::Ident,
namespace: Namespace,
check_ribs: bool)
check_ribs: bool,
record_used: bool)
-> Option<LocalDef> {
// First, check to see whether the name is a primitive type.
if namespace == TypeNS {
Expand All @@ -2931,7 +2934,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
}

self.resolve_item_by_name_in_lexical_scope(identifier.unhygienic_name, namespace)
let name = identifier.unhygienic_name;
self.resolve_item_by_name_in_lexical_scope(name, namespace, record_used)
.map(LocalDef::from_def)
}

Expand Down Expand Up @@ -3182,11 +3186,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {

fn resolve_item_by_name_in_lexical_scope(&mut self,
name: Name,
namespace: Namespace)
namespace: Namespace,
record_used: bool)
-> Option<Def> {
// Check the items.
let module = self.current_module.clone();
match self.resolve_item_in_lexical_scope(module, name, namespace) {
match self.resolve_item_in_lexical_scope(module, name, namespace, record_used) {
Success((target, _)) => {
match target.binding.def() {
None => {
Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/lint-qualification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ mod foo {
fn main() {
use foo::bar;
foo::bar(); //~ ERROR: unnecessary qualification
bar();
}
5 changes: 4 additions & 1 deletion src/test/compile-fail/lint-unused-imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,14 @@ mod foo {
mod bar {
// Don't ignore on 'pub use' because we're not sure if it's used or not
pub use std::cmp::PartialEq;
pub struct Square;

pub mod c {
use foo::Point;
use foo::Square; //~ ERROR unused import
pub fn cc(p: Point) -> isize { return 2 * (p.x + p.y); }
pub fn cc(_p: Point) -> super::Square {
super::Square
}
}

#[allow(unused_imports)]
Expand Down

0 comments on commit 83dde14

Please sign in to comment.