diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a564e8060d930..205e04cc5d2c4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1113,6 +1113,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("CACHE MISS"); self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result); stack.cache().on_completion(stack.dfn); + } else if let Some(_guar) = self.infcx.tainted_by_errors() { + // When an error has occurred, we allow global caching of results even if they + // appear stack-dependent. This prevents exponential re-evaluation of cycles + // in the presence of errors, avoiding compiler hangs like #150907. + // This is safe because compilation will fail anyway. + debug!("CACHE MISS (tainted by errors)"); + self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result); + stack.cache().on_completion(stack.dfn); } else { debug!("PROVISIONAL"); debug!( diff --git a/tests/ui/traits/cycle-cache-err-150907.rs b/tests/ui/traits/cycle-cache-err-150907.rs new file mode 100644 index 0000000000000..86bceab442ffc --- /dev/null +++ b/tests/ui/traits/cycle-cache-err-150907.rs @@ -0,0 +1,125 @@ +// Test that we don't hang or take exponential time when evaluating +// auto-traits for cyclic types containing errors, based on the reproducer +// provided in issue #150907. + +use std::sync::Arc; +use std::marker::PhantomData; + +struct Weak(PhantomData); +unsafe impl Send for Weak {} +unsafe impl Sync for Weak {} + +struct BTreeMap(K, V); + +trait DeviceOps: Send {} + +struct SerialDevice { + terminal: Weak, +} + +impl DeviceOps for SerialDevice {} + +struct TtyState { + terminals: Weak, +} + +struct TerminalMutableState { + controller: TerminalController, +} + +struct Terminal { + weak_self: Weak, + state: Arc, + mutable_state: Weak, +} + +struct TerminalController { + session: Weak, +} + +struct Kernel { + weak_self: Weak, + kthreads: KernelThreads, + pids: Weak, +} + +struct KernelThreads { + system_task: SystemTask, + kernel: Weak, +} + +struct SystemTask { + system_thread_group: Weak, +} + +enum ProcessEntry { + ThreadGroup(Weak), +} + +struct PidEntry { + task: Arc, + process: ProcessEntry, +} + +struct PidTable { + table: PidEntry, + process_groups: Arc, +} + +struct ProcessGroupMutableState { + thread_groups: Weak, +} + +struct ProcessGroup { + session: Arc, + mutable_state: Arc, +} + +struct SessionMutableState { + process_groups: BTreeMap<(), Weak>, + controlling_terminal: ControllingTerminal, +} + +struct Session { + mutable_state: Weak, +} + +struct ControllingTerminal { + terminal: Arc, +} + +struct TaskPersistentInfoState { + thread_group_key: ThreadGroupKey, +} + +struct Task { + thread_group_key: ThreadGroupKey, + kernel: Arc, + thread_group: Arc, + persistent_info: Arc, + vfork_event: Arc, //~ ERROR missing generics for struct `Arc` +} + +struct ThreadGroupKey { + thread_group: Arc, +} + +struct ThreadGroupMutableState { + tasks: BTreeMap<(), TaskContainer>, + children: BTreeMap<(), Weak>, + process_group: Arc, +} + +struct ThreadGroup { + kernel: Arc, + mutable_state: Weak, +} + +struct TaskContainer(Arc, Arc); + +fn main() { + // Trigger auto-trait check for one of the cyclic types + is_send::(); +} + +fn is_send() {} diff --git a/tests/ui/traits/cycle-cache-err-150907.stderr b/tests/ui/traits/cycle-cache-err-150907.stderr new file mode 100644 index 0000000000000..a8d680af55377 --- /dev/null +++ b/tests/ui/traits/cycle-cache-err-150907.stderr @@ -0,0 +1,14 @@ +error[E0107]: missing generics for struct `Arc` + --> $DIR/cycle-cache-err-150907.rs:100:18 + | +LL | vfork_event: Arc, + | ^^^ expected at least 1 generic argument + | +help: add missing generic argument + | +LL | vfork_event: Arc, + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`.