-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove need for mutable reference to static #13705
Conversation
One or more of the following people are relevant to this code:
|
Pull Request Test Coverage Report for Build 12891354532Details
💛 - Coveralls |
Mutable references to static data are inherently unsafe and typically unsound in Rust, because statics are implicitly shared between threads, and the borrow checker can only enforce the shared/exclusive reference limitations within a single thread here. This just moves the thread-exclusion logic into the individual elements of the `static`, where the `GILOnceCell` can correctly handle the runtime exclusion of multiple threads. (The GIL is no longer suitable for thread exclusion if we were doing a freethreaded Python build, but that's a problem we have all over Qiskit, and would need to change to `OnceLock` or the like.)
1ceac25
to
04b0ace
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This LGTM. I think I found the previous code cleaner but rust 1.84 warns 3 times about this being unsafe, and rust edition 2024 will actually make the mut ref static stuff unsafe. While we won't be using that for 2.x, it's good to remove the mut ref static preemptively.
static STDGATE_PYTHON_GATES: [GILOnceCell<PyObject>; STANDARD_GATE_SIZE] = [ | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
GILOnceCell::new(), | ||
]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pretty ugly. But I don't think there is a syntax that we can use here with GilOnceCell given the constraints defined in: https://doc.rust-lang.org/std/primitive.array.html so this is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's ugly. For anybody from the future looking: the trouble is that there's not enough available in const
functions to manage this. The closest I managed to get was
use std::mem::MaybeUninit;
use pyo3::prelude::*;
use pyo3::sync::GILOnceCell;
const STANDARD_GATE_SIZE: usize = 52;
static STDGATE_PYTHON_GATES: [GILOnceCell<Py<PyAny>>; STANDARD_GATE_SIZE] = const {
let mut out: [MaybeUninit<GILOnceCell<Py<PyAny>>>; STANDARD_GATE_SIZE] =
[const { MaybeUninit::uninit() }; STANDARD_GATE_SIZE];
let mut i = 0;
while i < STANDARD_GATE_SIZE {
out[i].write(GILOnceCell::new()); // error: `MaybeUninit::write` isn't const stable
i += 1;
}
unsafe { ::std::mem::transmute(out) }
};
Mutable references to static data are inherently unsafe and typically unsound in Rust, because statics are implicitly shared between threads, and the borrow checker can only enforce the shared/exclusive reference limitations within a single thread here. This just moves the thread-exclusion logic into the individual elements of the `static`, where the `GILOnceCell` can correctly handle the runtime exclusion of multiple threads. (The GIL is no longer suitable for thread exclusion if we were doing a freethreaded Python build, but that's a problem we have all over Qiskit, and would need to change to `OnceLock` or the like.) (cherry picked from commit 7b0b6fc) # Conflicts: # crates/circuit/src/imports.rs
* Remove need for mutable reference to static (#13705) Mutable references to static data are inherently unsafe and typically unsound in Rust, because statics are implicitly shared between threads, and the borrow checker can only enforce the shared/exclusive reference limitations within a single thread here. This just moves the thread-exclusion logic into the individual elements of the `static`, where the `GILOnceCell` can correctly handle the runtime exclusion of multiple threads. (The GIL is no longer suitable for thread exclusion if we were doing a freethreaded Python build, but that's a problem we have all over Qiskit, and would need to change to `OnceLock` or the like.) (cherry picked from commit 7b0b6fc) # Conflicts: # crates/circuit/src/imports.rs * Update imports.rs * Fix for older PyO3 --------- Co-authored-by: Jake Lishman <[email protected]> Co-authored-by: Elena Peña Tapia <[email protected]>
Mutable references to static data are inherently unsafe and typically unsound in Rust, because statics are implicitly shared between threads, and the borrow checker can only enforce the shared/exclusive reference limitations within a single thread here.
This just moves the thread-exclusion logic into the individual elements of the
static
, where theGILOnceCell
can correctly handle the runtime exclusion of multiple threads. (The GIL is no longer suitable for thread exclusion if we were doing a freethreaded Python build, but that's a problem we have all over Qiskit, and would need to change toOnceLock
or the like.)Summary
Details and comments
Minor conflict with the update to PyO3 0.23, but only a small syntactic one - the
import_bound
becomesimport
. The logic still works.