Skip to content

Commit 06546d4

Browse files
committed
Avoid sorting predicates by DefId
Fixes issue #82920 Even if an item does not change between compilation sessions, it may end up with a different `DefId`, since inserting/deleting an item affects the `DefId`s of all subsequent items. Therefore, we use a `DefPathHash` in the incremental compilation system, which is stable in the face of changes to unrelated items. In particular, the query system will consider the inputs to a query to be unchanged if any `DefId`s in the inputs have their `DefPathHash`es unchanged. Queries are pure functions, so the query result should be unchanged if the query inputs are unchanged. Unfortunately, it's possible to inadvertantly make a query result incorrectly change across compilations, by relying on the specific value of a `DefId`. Specifically, if the query result is a slice that gets sorted by `DefId`, the precise order will depend on how the `DefId`s got assigned in a particular compilation session. If some definitions end up with different `DefId`s (but the same `DefPathHash`es) in a subsequent compilation session, we will end up re-computing a *different* value for the query, even though the query system expects the result to unchanged due to the unchanged inputs. It turns out that we have been sorting the predicates computed during `astconv` by their `DefId`. These predicates make their way into the `super_predicates_that_define_assoc_type`, which ends up getting used to compute the vtables of trait objects. This, re-ordering these predicates between compilation sessions can lead to undefined behavior at runtime - the query system will re-use code built with a *differently ordered* vtable, resulting in the wrong method being invoked at runtime. This PR avoids sorting by `DefId` in `astconv`, fixing the miscompilation. However, it's possible that other instances of this issue exist - they could also be easily introduced in the future. To fully fix this issue, we should 1. Turn on `-Z incremental-verify-ich` by default. This will cause the compiler to ICE whenver an 'unchanged' query result changes between compilation sessions, instead of causing a miscompilation. 2. Remove the `Ord` impls for `CrateNum` and `DefId`. This will make it difficult to introduce ICEs in the first place.
1 parent b3e19a2 commit 06546d4

File tree

11 files changed

+102
-65
lines changed

11 files changed

+102
-65
lines changed

compiler/rustc_typeck/src/astconv/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
942942
let mut bounds = Bounds::default();
943943

944944
self.add_bounds(param_ty, ast_bounds, &mut bounds);
945-
bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id());
946945

947946
bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
948947
if !self.is_unsized(ast_bounds, span) { Some(span) } else { None }
@@ -1318,8 +1317,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
13181317

13191318
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
13201319
// `dyn Trait + Send`.
1321-
auto_traits.sort_by_key(|i| i.trait_ref().def_id());
1322-
auto_traits.dedup_by_key(|i| i.trait_ref().def_id());
1320+
// We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
1321+
// the bounds
1322+
let mut duplicates = FxHashSet::default();
1323+
auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id()));
13231324
debug!("regular_traits: {:?}", regular_traits);
13241325
debug!("auto_traits: {:?}", auto_traits);
13251326

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// revisions: rpass1 rpass2
2+
3+
trait MyTrait: One + Two {}
4+
impl<T> One for T {
5+
fn method_one(&self) -> usize {
6+
1
7+
}
8+
}
9+
impl<T> Two for T {
10+
fn method_two(&self) -> usize {
11+
2
12+
}
13+
}
14+
impl<T: One + Two> MyTrait for T {}
15+
16+
fn main() {
17+
let a: &dyn MyTrait = &true;
18+
assert_eq!(a.method_one(), 1);
19+
assert_eq!(a.method_two(), 2);
20+
}
21+
22+
// Re-order traits 'One' and 'Two' between compilation
23+
// sessions
24+
25+
#[cfg(rpass1)]
26+
trait One { fn method_one(&self) -> usize; }
27+
28+
trait Two { fn method_two(&self) -> usize; }
29+
30+
#[cfg(rpass2)]
31+
trait One { fn method_one(&self) -> usize; }

src/test/rustdoc/inline_cross/impl_trait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub use impl_trait_aux::func2;
1818

1919
// @has impl_trait/fn.func3.html
2020
// @has - '//pre[@class="rust fn"]' "func3("
21-
// @has - '//pre[@class="rust fn"]' "_x: impl Clone + Iterator<Item = impl Iterator<Item = u8>>)"
21+
// @has - '//pre[@class="rust fn"]' "_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone)"
2222
// @!has - '//pre[@class="rust fn"]' 'where'
2323
pub use impl_trait_aux::func3;
2424

src/test/rustdoc/unit-return.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ pub fn f0<F: FnMut(u8) + Clone>(f: F) {}
1010
// @has 'foo/fn.f1.html' '//*[@class="rust fn"]' 'F: FnMut(u16) + Clone'
1111
pub fn f1<F: FnMut(u16) -> () + Clone>(f: F) {}
1212

13-
// @has 'foo/fn.f2.html' '//*[@class="rust fn"]' 'F: Clone + FnMut(u32)'
13+
// @has 'foo/fn.f2.html' '//*[@class="rust fn"]' 'F: FnMut(u32) + Clone'
1414
pub use unit_return::f2;
1515

16-
// @has 'foo/fn.f3.html' '//*[@class="rust fn"]' 'F: Clone + FnMut(u64)'
16+
// @has 'foo/fn.f3.html' '//*[@class="rust fn"]' 'F: FnMut(u64) + Clone'
1717
pub use unit_return::f3;

src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr

+17-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
1-
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` is not an iterator
2-
--> $DIR/bad-bounds-on-assoc-in-trait.rs:27:5
3-
|
4-
LL | type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<<Self as Case1>::C as Iterator>::Item` is not an iterator
6-
|
7-
= help: the trait `Iterator` is not implemented for `<<Self as Case1>::C as Iterator>::Item`
8-
help: consider further restricting the associated type
9-
|
10-
LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Iterator {
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12-
131
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
142
--> $DIR/bad-bounds-on-assoc-in-trait.rs:27:36
153
|
@@ -27,6 +15,23 @@ help: consider further restricting the associated type
2715
LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Send {
2816
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2917

18+
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` is not an iterator
19+
--> $DIR/bad-bounds-on-assoc-in-trait.rs:27:43
20+
|
21+
LL | type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<<Self as Case1>::C as Iterator>::Item` is not an iterator
23+
|
24+
::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
25+
|
26+
LL | pub trait Iterator {
27+
| ------------------ required by this bound in `Iterator`
28+
|
29+
= help: the trait `Iterator` is not implemented for `<<Self as Case1>::C as Iterator>::Item`
30+
help: consider further restricting the associated type
31+
|
32+
LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Iterator {
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
3035
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
3136
--> $DIR/bad-bounds-on-assoc-in-trait.rs:27:93
3237
|

src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr

+10-10
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ LL | fn dent<C:BoxCar>(c: C, color: C::Color) {
2020
|
2121
help: use fully qualified syntax to disambiguate
2222
|
23-
LL | fn dent<C:BoxCar>(c: C, color: <C as Box>::Color) {
24-
| ^^^^^^^^^^^^^^^^^
25-
help: use fully qualified syntax to disambiguate
26-
|
2723
LL | fn dent<C:BoxCar>(c: C, color: <C as Vehicle>::Color) {
2824
| ^^^^^^^^^^^^^^^^^^^^^
25+
help: use fully qualified syntax to disambiguate
26+
|
27+
LL | fn dent<C:BoxCar>(c: C, color: <C as Box>::Color) {
28+
| ^^^^^^^^^^^^^^^^^
2929

3030
error[E0222]: ambiguous associated type `Color` in bounds of `BoxCar`
3131
--> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:37
@@ -42,8 +42,8 @@ LL | fn dent_object<COLOR>(c: dyn BoxCar<Color=COLOR>) {
4242
= help: consider introducing a new type parameter `T` and adding `where` constraints:
4343
where
4444
T: BoxCar,
45-
T: Box::Color = COLOR,
46-
T: Vehicle::Color = COLOR
45+
T: Vehicle::Color = COLOR,
46+
T: Box::Color = COLOR
4747

4848
error[E0191]: the value of the associated types `Color` (from trait `Box`), `Color` (from trait `Vehicle`) must be specified
4949
--> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:30
@@ -73,12 +73,12 @@ LL | fn paint<C:BoxCar>(c: C, d: C::Color) {
7373
|
7474
help: use fully qualified syntax to disambiguate
7575
|
76-
LL | fn paint<C:BoxCar>(c: C, d: <C as Box>::Color) {
77-
| ^^^^^^^^^^^^^^^^^
78-
help: use fully qualified syntax to disambiguate
79-
|
8076
LL | fn paint<C:BoxCar>(c: C, d: <C as Vehicle>::Color) {
8177
| ^^^^^^^^^^^^^^^^^^^^^
78+
help: use fully qualified syntax to disambiguate
79+
|
80+
LL | fn paint<C:BoxCar>(c: C, d: <C as Box>::Color) {
81+
| ^^^^^^^^^^^^^^^^^
8282

8383
error[E0191]: the value of the associated types `Color` (from trait `Box`), `Color` (from trait `Vehicle`) must be specified
8484
--> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:32

src/test/ui/associated-types/defaults-unsound-62211-1.stderr

+14-14
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,6 @@ help: consider further restricting `Self`
1313
LL | trait UncheckedCopy: Sized + std::fmt::Display {
1414
| ^^^^^^^^^^^^^^^^^^^
1515

16-
error[E0277]: the trait bound `Self: Deref` is not satisfied
17-
--> $DIR/defaults-unsound-62211-1.rs:20:5
18-
|
19-
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
20-
| ^^^^^^^^^^^^^^^^^^^^-------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21-
| | |
22-
| | required by this bound in `UncheckedCopy::Output`
23-
| the trait `Deref` is not implemented for `Self`
24-
|
25-
help: consider further restricting `Self`
26-
|
27-
LL | trait UncheckedCopy: Sized + Deref {
28-
| ^^^^^^^
29-
3016
error[E0277]: cannot add-assign `&'static str` to `Self`
3117
--> $DIR/defaults-unsound-62211-1.rs:20:5
3218
|
@@ -41,6 +27,20 @@ help: consider further restricting `Self`
4127
LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
4228
| ^^^^^^^^^^^^^^^^^^^^^^^^^
4329

30+
error[E0277]: the trait bound `Self: Deref` is not satisfied
31+
--> $DIR/defaults-unsound-62211-1.rs:20:5
32+
|
33+
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
34+
| ^^^^^^^^^^^^^^^^^^^^-------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35+
| | |
36+
| | required by this bound in `UncheckedCopy::Output`
37+
| the trait `Deref` is not implemented for `Self`
38+
|
39+
help: consider further restricting `Self`
40+
|
41+
LL | trait UncheckedCopy: Sized + Deref {
42+
| ^^^^^^^
43+
4444
error[E0277]: the trait bound `Self: Copy` is not satisfied
4545
--> $DIR/defaults-unsound-62211-1.rs:20:5
4646
|

src/test/ui/associated-types/defaults-unsound-62211-2.stderr

+14-14
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,6 @@ help: consider further restricting `Self`
1313
LL | trait UncheckedCopy: Sized + std::fmt::Display {
1414
| ^^^^^^^^^^^^^^^^^^^
1515

16-
error[E0277]: the trait bound `Self: Deref` is not satisfied
17-
--> $DIR/defaults-unsound-62211-2.rs:20:5
18-
|
19-
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
20-
| ^^^^^^^^^^^^^^^^^^^^-------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21-
| | |
22-
| | required by this bound in `UncheckedCopy::Output`
23-
| the trait `Deref` is not implemented for `Self`
24-
|
25-
help: consider further restricting `Self`
26-
|
27-
LL | trait UncheckedCopy: Sized + Deref {
28-
| ^^^^^^^
29-
3016
error[E0277]: cannot add-assign `&'static str` to `Self`
3117
--> $DIR/defaults-unsound-62211-2.rs:20:5
3218
|
@@ -41,6 +27,20 @@ help: consider further restricting `Self`
4127
LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
4228
| ^^^^^^^^^^^^^^^^^^^^^^^^^
4329

30+
error[E0277]: the trait bound `Self: Deref` is not satisfied
31+
--> $DIR/defaults-unsound-62211-2.rs:20:5
32+
|
33+
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
34+
| ^^^^^^^^^^^^^^^^^^^^-------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35+
| | |
36+
| | required by this bound in `UncheckedCopy::Output`
37+
| the trait `Deref` is not implemented for `Self`
38+
|
39+
help: consider further restricting `Self`
40+
|
41+
LL | trait UncheckedCopy: Sized + Deref {
42+
| ^^^^^^^
43+
4444
error[E0277]: the trait bound `Self: Copy` is not satisfied
4545
--> $DIR/defaults-unsound-62211-2.rs:20:5
4646
|

src/test/ui/issues/issue-40827.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
1-
error[E0277]: `Rc<Foo>` cannot be sent between threads safely
1+
error[E0277]: `Rc<Foo>` cannot be shared between threads safely
22
--> $DIR/issue-40827.rs:14:5
33
|
44
LL | fn f<T: Send>(_: T) {}
55
| ---- required by this bound in `f`
66
...
77
LL | f(Foo(Arc::new(Bar::B(None))));
8-
| ^ `Rc<Foo>` cannot be sent between threads safely
8+
| ^ `Rc<Foo>` cannot be shared between threads safely
99
|
10-
= help: within `Bar`, the trait `Send` is not implemented for `Rc<Foo>`
10+
= help: within `Bar`, the trait `Sync` is not implemented for `Rc<Foo>`
1111
= note: required because it appears within the type `Bar`
1212
= note: required because of the requirements on the impl of `Send` for `Arc<Bar>`
1313
= note: required because it appears within the type `Foo`
1414

15-
error[E0277]: `Rc<Foo>` cannot be shared between threads safely
15+
error[E0277]: `Rc<Foo>` cannot be sent between threads safely
1616
--> $DIR/issue-40827.rs:14:5
1717
|
1818
LL | fn f<T: Send>(_: T) {}
1919
| ---- required by this bound in `f`
2020
...
2121
LL | f(Foo(Arc::new(Bar::B(None))));
22-
| ^ `Rc<Foo>` cannot be shared between threads safely
22+
| ^ `Rc<Foo>` cannot be sent between threads safely
2323
|
24-
= help: within `Bar`, the trait `Sync` is not implemented for `Rc<Foo>`
24+
= help: within `Bar`, the trait `Send` is not implemented for `Rc<Foo>`
2525
= note: required because it appears within the type `Bar`
2626
= note: required because of the requirements on the impl of `Send` for `Arc<Bar>`
2727
= note: required because it appears within the type `Foo`

src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ LL | self.foo();
88
| ^^^ method cannot be called on `&Foo<T>` due to unsatisfied trait bounds
99
|
1010
= note: the following trait bounds were not satisfied:
11-
`T: Bar`
12-
which is required by `Foo<T>: Bar`
1311
`T: Default`
1412
which is required by `Foo<T>: Bar`
13+
`T: Bar`
14+
which is required by `Foo<T>: Bar`
1515
help: consider restricting the type parameters to satisfy the trait bounds
1616
|
1717
LL | struct Foo<T> where T: Bar, T: Default {

src/test/ui/traits/inductive-overflow/simultaneous.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0275]: overflow evaluating the requirement `{integer}: Tweedledum`
1+
error[E0275]: overflow evaluating the requirement `{integer}: Tweedledee`
22
--> $DIR/simultaneous.rs:18:5
33
|
44
LL | fn is_ee<T: Combo>(t: T) {

0 commit comments

Comments
 (0)