about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-07-14 14:33:17 -0700
committerGitHub <noreply@github.com>2016-07-14 14:33:17 -0700
commite08a6c2068aad3539cf0fa58e097962e3a3cf0b5 (patch)
tree1f30733ee9c15f00428faa79f64acb2c9dab6a1e
parent78d49bfac2bbcd48de522199212a1209f498e834 (diff)
parent5a99d798577a1e5a3e5434bad4b68835b708f6c0 (diff)
Auto merge of #34797 - doomrobo:fix-import-trait-method, r=jseyfried
Fixed issue where importing a trait method directly and then calling the method causes a compiler panic

The code below triggers the panic, and is included in a new regression test.

```rust
trait Foo {
    fn foo();
}

use Foo::foo;

fn main() {
    foo();
}
```
The bug is caused by `librustc_resolve` allowing the illegal binding to be imported even after displaying the error message above.

The fix amounts to importing a dummy binding (`rustc::hir::def::Def::Err`) instead of the actual trait method.
-rw-r--r--src/librustc_resolve/resolve_imports.rs28
-rw-r--r--src/test/compile-fail/import-trait-method.rs17
2 files changed, 35 insertions, 10 deletions
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 16a59fbb800..681d9ec735b 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -400,26 +400,30 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         }
     }
 
-    /// Resolves an `ImportResolvingError` into the correct enum discriminant
-    /// and passes that on to `resolve_error`.
-    fn import_resolving_error(&self, e: ImportResolvingError<'b>) {
-        // If it's a single failed import then create a "fake" import
-        // resolution for it so that later resolve stages won't complain.
-        if let SingleImport { target, .. } = e.import_directive.subclass {
+    // Define a "dummy" resolution containing a Def::Err as a placeholder for a
+    // failed resolution
+    fn import_dummy_binding(&self, source_module: Module<'b>, directive: &'b ImportDirective<'b>) {
+        if let SingleImport { target, .. } = directive.subclass {
             let dummy_binding = self.resolver.arenas.alloc_name_binding(NameBinding {
                 kind: NameBindingKind::Def(Def::Err),
                 span: DUMMY_SP,
                 vis: ty::Visibility::Public,
             });
-            let dummy_binding = e.import_directive.import(dummy_binding, None);
+            let dummy_binding = directive.import(dummy_binding, None);
 
-            let _ = e.source_module.try_define_child(target, ValueNS, dummy_binding.clone());
-            let _ = e.source_module.try_define_child(target, TypeNS, dummy_binding);
+            let _ = source_module.try_define_child(target, ValueNS, dummy_binding.clone());
+            let _ = source_module.try_define_child(target, TypeNS, dummy_binding);
         }
+    }
 
+    /// Resolves an `ImportResolvingError` into the correct enum discriminant
+    /// and passes that on to `resolve_error`.
+    fn import_resolving_error(&self, e: ImportResolvingError<'b>) {
+        // If the error is a single failed import then create a "fake" import
+        // resolution for it so that later resolve stages won't complain.
+        self.import_dummy_binding(e.source_module, e.import_directive);
         let path = import_path_to_string(&e.import_directive.module_path,
                                          &e.import_directive.subclass);
-
         resolve_error(self.resolver,
                       e.span,
                       ResolutionError::UnresolvedImport(Some((&path, &e.help))));
@@ -500,6 +504,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                 if !binding.is_importable() {
                     let msg = format!("`{}` is not directly importable", target);
                     span_err!(self.resolver.session, directive.span, E0253, "{}", &msg);
+                    // Do not import this illegal binding. Import a dummy binding and pretend
+                    // everything is fine
+                    self.import_dummy_binding(module_, directive);
+                    return Success(());
                 }
 
                 let privacy_error = if !self.resolver.is_accessible(binding.vis) {
diff --git a/src/test/compile-fail/import-trait-method.rs b/src/test/compile-fail/import-trait-method.rs
new file mode 100644
index 00000000000..75081b10d86
--- /dev/null
+++ b/src/test/compile-fail/import-trait-method.rs
@@ -0,0 +1,17 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo {
+    fn foo();
+}
+
+use Foo::foo; //~ ERROR not directly importable
+
+fn main() { foo(); }