about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMark Rousskov <mark.simulacrum@gmail.com>2021-09-30 14:25:46 -0400
committerMark Rousskov <mark.simulacrum@gmail.com>2021-09-30 14:27:57 -0400
commit56fcf0725a164f16b9d7f1ff8fe2f3d6b4aab3db (patch)
tree07b1467b47b65f43293568143359e8a6e5ab9fe5
parent69c1c6a173dcae20c245348f6c7d19074b6109b7 (diff)
downloadrust-56fcf0725a164f16b9d7f1ff8fe2f3d6b4aab3db.tar.gz
rust-56fcf0725a164f16b9d7f1ff8fe2f3d6b4aab3db.zip
Avoid nondeterminism in trimmed_def_paths
Previously this query depended on the global interning order of Symbols, which
meant that irrelevant changes could influence the query and cause
recompilations. This commit ensures that the return set is stable and will not
be affected by the global order by deterministically (in lexicographic order)
choosing a name to use if there are multiple names for a single DefId.
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs25
1 files changed, 23 insertions, 2 deletions
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index b8bca6363db..e7dc0c2fc86 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2408,7 +2408,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
 ///
 /// The implementation uses similar import discovery logic to that of 'use' suggestions.
 fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
-    let mut map = FxHashMap::default();
+    let mut map: FxHashMap<DefId, Symbol> = FxHashMap::default();
 
     if let TrimmedDefPaths::GoodPath = tcx.sess.opts.trimmed_def_paths {
         // For good paths causing this bug, the `rustc_middle::ty::print::with_no_trimmed_paths`
@@ -2446,8 +2446,29 @@ fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
     });
 
     for ((_, symbol), opt_def_id) in unique_symbols_rev.drain() {
+        use std::collections::hash_map::Entry::{Occupied, Vacant};
+
         if let Some(def_id) = opt_def_id {
-            map.insert(def_id, symbol);
+            match map.entry(def_id) {
+                Occupied(mut v) => {
+                    // A single DefId can be known under multiple names (e.g.,
+                    // with a `pub use ... as ...;`). We need to ensure that the
+                    // name placed in this map is chosen deterministically, so
+                    // if we find multiple names (`symbol`) resolving to the
+                    // same `def_id`, we prefer the lexicographically smallest
+                    // name.
+                    //
+                    // Any stable ordering would be fine here though.
+                    if *v.get() != symbol {
+                        if v.get().as_str() > symbol.as_str() {
+                            v.insert(symbol);
+                        }
+                    }
+                }
+                Vacant(v) => {
+                    v.insert(symbol);
+                }
+            }
         }
     }