Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand Down
125 changes: 125 additions & 0 deletions tests/ui/traits/cycle-cache-err-150907.rs
Original file line number Diff line number Diff line change
@@ -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<T>(PhantomData<T>);
unsafe impl<T: Sync + Send> Send for Weak<T> {}
unsafe impl<T: Sync + Send> Sync for Weak<T> {}

struct BTreeMap<K, V>(K, V);

trait DeviceOps: Send {}

struct SerialDevice {
terminal: Weak<Terminal>,
}

impl DeviceOps for SerialDevice {}

struct TtyState {
terminals: Weak<Terminal>,
}

struct TerminalMutableState {
controller: TerminalController,
}

struct Terminal {
weak_self: Weak<Self>,
state: Arc<TtyState>,
mutable_state: Weak<TerminalMutableState>,
}

struct TerminalController {
session: Weak<Session>,
}

struct Kernel {
weak_self: Weak<Kernel>,
kthreads: KernelThreads,
pids: Weak<PidTable>,
}

struct KernelThreads {
system_task: SystemTask,
kernel: Weak<Kernel>,
}

struct SystemTask {
system_thread_group: Weak<ThreadGroup>,
}

enum ProcessEntry {
ThreadGroup(Weak<ThreadGroup>),
}

struct PidEntry {
task: Arc<Task>,
process: ProcessEntry,
}

struct PidTable {
table: PidEntry,
process_groups: Arc<ProcessGroup>,
}

struct ProcessGroupMutableState {
thread_groups: Weak<ThreadGroup>,
}

struct ProcessGroup {
session: Arc<Session>,
mutable_state: Arc<ProcessGroupMutableState>,
}

struct SessionMutableState {
process_groups: BTreeMap<(), Weak<ProcessGroup>>,
controlling_terminal: ControllingTerminal,
}

struct Session {
mutable_state: Weak<SessionMutableState>,
}

struct ControllingTerminal {
terminal: Arc<Terminal>,
}

struct TaskPersistentInfoState {
thread_group_key: ThreadGroupKey,
}

struct Task {
thread_group_key: ThreadGroupKey,
kernel: Arc<Kernel>,
thread_group: Arc<ThreadGroup>,
persistent_info: Arc<TaskPersistentInfoState>,
vfork_event: Arc, //~ ERROR missing generics for struct `Arc`
}

struct ThreadGroupKey {
thread_group: Arc<ThreadGroup>,
}

struct ThreadGroupMutableState {
tasks: BTreeMap<(), TaskContainer>,
children: BTreeMap<(), Weak<ThreadGroup>>,
process_group: Arc<ProcessGroup>,
}

struct ThreadGroup {
kernel: Arc<Kernel>,
mutable_state: Weak<ThreadGroupMutableState>,
}

struct TaskContainer(Arc<Task>, Arc<TaskPersistentInfoState>);

fn main() {
// Trigger auto-trait check for one of the cyclic types
is_send::<Kernel>();
}

fn is_send<T: Send>() {}
14 changes: 14 additions & 0 deletions tests/ui/traits/cycle-cache-err-150907.stderr
Original file line number Diff line number Diff line change
@@ -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<T>,
| +++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0107`.
Loading