summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-11-28 17:55:52 +0000
committerJosh Stone <jistone@redhat.com>2025-01-02 13:43:18 -0800
commit21c75ad1ccc234b8cc2ffd23ed411b3a0da70833 (patch)
tree93a26f18159e565d4398879f6339ac2677084fe9
parent0857a8e32cd55fca2e6c648e586f9ce46c22eb42 (diff)
downloadrust-21c75ad1ccc234b8cc2ffd23ed411b3a0da70833.tar.gz
rust-21c75ad1ccc234b8cc2ffd23ed411b3a0da70833.zip
Do not call `extern_crate` on current trait on crate mismatch errors
When we encounter an error caused by traits/types of different versions of the same crate, filter out the current crate when collecting spans to add to the context so we don't call `extern_crate` on the `DefId` of the current crate, which is meaningless and ICEs.

Produced output with this filter:

```
error[E0277]: the trait bound `foo::Struct: Trait` is not satisfied
  --> y.rs:13:19
   |
13 |     check_trait::<foo::Struct>();
   |                   ^^^^^^^^^^^ the trait `Trait` is not implemented for `foo::Struct`
   |
note: there are multiple different versions of crate `foo` in the dependency graph
  --> y.rs:7:1
   |
4  | extern crate foo;
   | ----------------- one version of crate `foo` is used here, as a direct dependency of the current crate
5  |
6  | pub struct Struct;
   | ----------------- this type implements the required trait
7  | pub trait Trait {}
   | ^^^^^^^^^^^^^^^ this is the required trait
   |
  ::: x.rs:4:1
   |
4  | pub struct Struct;
   | ----------------- this type doesn't implement the required trait
5  | pub trait Trait {}
   | --------------- this is the found trait
   = note: two types coming from two different versions of the same crate are different types even if they look the same
   = help: you can use `cargo tree` to explore your dependency tree
note: required by a bound in `check_trait`
  --> y.rs:10:19
   |
10 | fn check_trait<T: Trait>() {}
   |                   ^^^^^ required by this bound in `check_trait`
```

Fix #133563.

(cherry picked from commit 8574f374e2cc27b53c8b81dc4031c59ca3035284)
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs4
-rw-r--r--tests/run-make/crate-loading-crate-depends-on-itself/foo-current.rs14
-rw-r--r--tests/run-make/crate-loading-crate-depends-on-itself/foo-prev.rs6
-rw-r--r--tests/run-make/crate-loading-crate-depends-on-itself/rmake.rs32
4 files changed, 56 insertions, 0 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 4e7d7b79ff4..20cef5e06a4 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1732,6 +1732,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             span.push_span_label(self.tcx.def_span(trait_def_id), "this is the required trait");
             for (sp, label) in [trait_def_id, other_trait_def_id]
                 .iter()
+                // The current crate-version might depend on another version of the same crate
+                // (Think "semver-trick"). Do not call `extern_crate` in that case for the local
+                // crate as that doesn't make sense and ICEs (#133563).
+                .filter(|def_id| !def_id.is_local())
                 .filter_map(|def_id| self.tcx.extern_crate(def_id.krate))
                 .map(|data| {
                     let dependency = if data.dependency_of == LOCAL_CRATE {
diff --git a/tests/run-make/crate-loading-crate-depends-on-itself/foo-current.rs b/tests/run-make/crate-loading-crate-depends-on-itself/foo-current.rs
new file mode 100644
index 00000000000..71b27cd85bf
--- /dev/null
+++ b/tests/run-make/crate-loading-crate-depends-on-itself/foo-current.rs
@@ -0,0 +1,14 @@
+#![crate_type = "lib"]
+#![crate_name = "foo"]
+
+extern crate foo;
+
+pub struct Struct;
+pub trait Trait {}
+impl Trait for Struct {}
+
+fn check_trait<T: Trait>() {}
+
+fn ice() {
+    check_trait::<foo::Struct>();
+}
diff --git a/tests/run-make/crate-loading-crate-depends-on-itself/foo-prev.rs b/tests/run-make/crate-loading-crate-depends-on-itself/foo-prev.rs
new file mode 100644
index 00000000000..19d3f3c972b
--- /dev/null
+++ b/tests/run-make/crate-loading-crate-depends-on-itself/foo-prev.rs
@@ -0,0 +1,6 @@
+#![crate_type = "lib"]
+#![crate_name = "foo"]
+
+pub struct Struct;
+pub trait Trait {}
+impl Trait for Struct {}
diff --git a/tests/run-make/crate-loading-crate-depends-on-itself/rmake.rs b/tests/run-make/crate-loading-crate-depends-on-itself/rmake.rs
new file mode 100644
index 00000000000..f52f3d791a7
--- /dev/null
+++ b/tests/run-make/crate-loading-crate-depends-on-itself/rmake.rs
@@ -0,0 +1,32 @@
+//@ only-linux
+//@ ignore-wasm32
+//@ ignore-wasm64
+// ignore-tidy-linelength
+
+// Verify that if the current crate depends on a different version of the same crate, *and* types
+// and traits of the different versions are mixed, we produce diagnostic output and not an ICE.
+// #133563
+
+use run_make_support::{rust_lib_name, rustc};
+
+fn main() {
+    rustc().input("foo-prev.rs").run();
+
+    rustc()
+        .extra_filename("current")
+        .metadata("current")
+        .input("foo-current.rs")
+        .extern_("foo", rust_lib_name("foo"))
+        .run_fail()
+        .assert_stderr_contains(r#"
+note: there are multiple different versions of crate `foo` in the dependency graph
+  --> foo-current.rs:7:1
+   |
+4  | extern crate foo;
+   | ----------------- one version of crate `foo` is used here, as a direct dependency of the current crate
+5  |
+6  | pub struct Struct;
+   | ----------------- this type implements the required trait
+7  | pub trait Trait {}
+   | ^^^^^^^^^^^^^^^ this is the required trait"#);
+}