-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Tracking Issue for const_refs_to_static #119618
Comments
My understanding is that many of the vtables in the kernel have the following shape: use core::ptr::addr_of_mut;
struct ThisModule;
trait Module {
const THIS_MODULE: *mut ThisModule;
}
struct MyModule;
// Generated by a macro.
extern "C" {
static mut THIS_MODULE: ThisModule;
}
// Generated by a macro.
impl Module for MyModule {
const THIS_MODULE: *mut ThisModule = unsafe { addr_of_mut!(THIS_MODULE) };
}
struct Vtable {
module: *mut ThisModule,
foo_fn: fn(*mut ()) -> i32,
}
pub trait Foo {
type Mod: Module;
fn foo(&mut self) -> i32;
}
fn generate_vtable<T: Foo>() -> &'static Vtable {
&Vtable {
module: T::Mod::THIS_MODULE,
foo_fn: |ptr| unsafe { &mut *ptr.cast::<T>() }.foo(),
}
}
We do not need to read or write to |
Your code literally reads the value of Or did you mean |
Oh wait, you have multiple items with the same name in different modules. That's very confusing code. I'll have to de-obfuscate it first.^^ |
I added your testcase in #120932, it then passes with |
Potential use case in the standard library: rust/library/core/src/task/wake.rs Lines 492 to 495 in 5dbaafd
By using |
There's no mutability here that I can see, so yeah that would work. Basically it's a trade-off between a lower risk of monomorphization-time errors and letting |
This is the next upgrade to the Rust toolchain, from 1.77.1 to 1.78.0 (i.e. the latest) [1]. See the upgrade policy [2] and the comments on the first upgrade in commit 3ed03f4 ("rust: upgrade to Rust 1.68.2"). It is much smaller than previous upgrades, since the `alloc` fork was dropped in commit 9d0441b ("rust: alloc: remove our fork of the `alloc` crate") [3]. # Unstable features There have been no changes to the set of unstable features used in our own code. Therefore, the only unstable features allowed to be used outside the `kernel` crate is still `new_uninit`. However, since we finally dropped our `alloc` fork [3], all the unstable features used by `alloc` (~30 language ones, ~60 library ones) are not a concern anymore. This reduces the maintenance burden, increases the chances of new compiler versions working without changes and gets us closer to the goal of supporting several compiler versions. It also means that, ignoring non-language/library features, we are currently left with just the few language features needed to implement the kernel `Arc`, the `new_uninit` library feature, the `compiler_builtins` marker and the few `no_*` `cfg`s we pass when compiling `core`/`alloc`. Please see [4] for details. # Required changes ## LLVM's data layout Rust 1.77.0 (i.e. the previous upgrade) introduced a check for matching LLVM data layouts [5]. Then, Rust 1.78.0 upgraded LLVM's bundled major version from 17 to 18 [6], which changed the data layout in x86 [7]. Thus update the data layout in our custom target specification for x86 so that the compiler does not complain about the mismatch: error: data-layout for target `target-5559158138856098584`, `e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128`, differs from LLVM target's `x86_64-linux-gnu` default layout, `e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128` In the future, the goal is to drop the custom target specifications. Meanwhile, if we want to support other LLVM versions used in `rustc` (e.g. for LTO), we will need to add some extra logic (e.g. conditional on LLVM's version, or extracting the data layout from an existing built-in target specification). ## `unused_imports` Rust's `unused_imports` lint covers both unused and redundant imports. Now, in 1.78.0, the lint detects more cases of redundant imports [8]. Thus one of the previous patches cleaned them up. ## Clippy's `new_without_default` Clippy now suggests to implement `Default` even when `new()` is `const`, since `Default::default()` may call `const` functions even if it is not `const` itself [9]. Thus one of the previous patches implemented it. # Other changes in Rust Rust 1.78.0 introduced `feature(asm_goto)` [10] [11]. This feature was discussed in the past [12]. Rust 1.78.0 introduced `feature(const_refs_to_static)` [13] to allow referencing statics in constants and extended `feature(const_mut_refs)` to allow raw mutable pointers in constants. Together, this should cover the kernel's `VTABLE` use case. In fact, the implementation [14] in upstream Rust added a test case for it [15]. Rust 1.78.0 with debug assertions enabled (i.e. `-Cdebug-assertions=y`, kernel's `CONFIG_RUST_DEBUG_ASSERTIONS=y`) now always checks all unsafe preconditions, though without a way to opt-out for particular cases [16]. It would be ideal to have a way to selectively disable certain checks per-call site for this one (i.e. not just per check but for particular instances of a check), even if the vast majority of the checks remain in place [17]. Rust 1.78.0 also improved a couple issues we reported when giving feedback for the new `--check-cfg` feature [18] [19]. # `alloc` upgrade and reviewing As mentioned above, compiler upgrades will not update `alloc` anymore, since we dropped our `alloc` fork [3]. Link: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-1780-2024-05-02 [1] Link: https://rust-for-linux.com/rust-version-policy [2] Link: https://lore.kernel.org/rust-for-linux/[email protected]/ [3] Link: Rust-for-Linux#2 [4] Link: rust-lang/rust#120062 [5] Link: rust-lang/rust#120055 [6] Link: https://reviews.llvm.org/D86310 [7] Link: rust-lang/rust#117772 [8] Link: rust-lang/rust-clippy#10903 [9] Link: rust-lang/rust#119365 [10] Link: rust-lang/rust#119364 [11] Link: https://lore.kernel.org/rust-for-linux/[email protected]/ [12] Link: rust-lang/rust#119618 [13] Link: rust-lang/rust#120932 [14] Link: https://github.com/rust-lang/rust/pull/120932/files#diff-e6fc1622c46054cd46b1d225c5386c5554564b3b0fa8a03c2dc2d8627a1079d9 [15] Link: rust-lang/rust#120969 [16] Link: Rust-for-Linux#354 [17] Link: rust-lang/rust#121202 [18] Link: rust-lang/rust#121237 [19] Reviewed-by: Alice Ryhl <[email protected]> Link: https://lore.kernel.org/r/[email protected] [ Added a few more details and links I mentioned in the list. - Miguel ] Signed-off-by: Miguel Ojeda <[email protected]>
What is the current status here -- in particular, the Rust For Linux project makes use of this feature to support creation of vtables (example code) and I am hoping that in the next 6 months we can move their subset to stabilization. @RalfJung or @oli-obk -- can you enlighten me as to what the key blockers and/or questions are? EDIT: Oh, that example appears earlier in the thread -- right, I forgot, we have already added a testcase to ensure that it continues to compile. EDIT: Created a Zulip thread to discuss. |
Yeah, the feature was added specifically to support that example. ;) Main concerns/blockers I can think of:
|
My general feeling is that we are overrotating on this. It is already observable that generics don't always have unique addresses (e.g., with function pointers). Certainly for types that lack interior mutability this is much less likely to be an issue. However, reading the issue, I remembered that I still feel a bit uneasy about when two constants are equal, and can never remember if we've landed somewhere or what. |
While consts, vtables, and function pointers do not have a unique address, so far it has been very clear that IMO we should still allow const_refs_to_static, and do something about this on the side of const generics instead, like reject const generics that point to statics or actually preserve their identity in the valtree somehow or so. |
Hello, is it correct that this feature is required for this code? static A: usize = 0;
static B1: [u8; A] = [0; A];
|
Yes, array lengths are constants, so the feature is required for that |
Note that it is currently possible to declare a If we now replace if let Some(y) = nonzero(X) { with if let Some(y) = const { nonzero(X) } { It won't compile. Which means that |
We could detect some simple cases but in general it is your responsibility, as part of writing unsafe code, to ensure this does not happen. Consider that one can take a reference or raw pointer to a The |
#1532) A subtle unsoundness / undefined behaviour made its way into the fairly recently added ExternalOneByteStringResource object: The as_str API is not sound as the data inside may be be Latin-1, not ASCII. As the API was not used anywhere in deno or deno_core, I opted to simply remove it and replace it with an as_bytes API. I also modified the test to showcase the Latin-1 string case and added copious notes and explanations around the code to make sure this doesn't accidentally happen again. The likely reason why the API originally slipped in is because the OneByteConst has this API where it is safe because the OneByteConst creation checks the data for ASCII-ness. I also tried to add an API to extract an Option<&'static OneByteConst> from an &ExternalOneByteStringResource but run into rust-lang/rust#119618 ie. OneByteConst is actually duplicating the vtables... which is not great.
Stabilization proposal: |
Seeing as #128183 is in FCP, I'm assigning @dingxiangfei2009 to prepare the stabilization PR: @rustbot assign @dingxiangfei2009 |
…efs-to-static, r=petrochenkov Stabilize `const_refs_to_static` Close rust-lang#128183 Tracked by rust-lang#119618 cc `@nikomatsakis` Meanwhile, I am cooking a sub-section in the language reference.
This is a tracking issue for consts referencing statics, a @rust-lang/wg-const-eval experiment.
The feature gate for the issue is
#![feature(const_refs_to_static)]
.This feature allow constants to refer to statics. However, reading from a static that is mutable (
static mut
, orstatic
with interior mutability) leads to an evaluator error. This is done to ensure that it doesn't matter when the constant is evaluated, it will always produce the same result.Having a reference to a mutable static in the final value leads to a validation error. This is necessary to ensure that converting these references to a valtree (e.g. for pattern matching) will not error. (The conversion would error because valtree conversion must never read from anything mutable.)
The same goes for reading from or having a reference to extern static; those obviously can't be read as we can't know their value at compile time. Mutating any static is also not possible -- we can't have global mutable state shared between const-eval queries.
About tracking issues
Tracking issues are used to record the overall progress of implementation.
They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
Steps
const_refs_to_static
#128183const_refs_to_static
#129759const
expression can borrow static items reference#1610Unresolved Questions
Implementation history
This issue has been assigned to @dingxiangfei2009 via this comment.
The text was updated successfully, but these errors were encountered: