You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
#[linkage = "weak"] const fn accepted without warning #134451
I'm trying to define a "weak" const in a library, which allows users to redefine their const. On stable Rust, there's no way to do it. On nightly, linkage feature seems the solution, but I found that it doesn't work as well. The following is the repro code:
Const items are always evaluated at compile time, which happens before linking, so this is expected. Perhaps const functions should not be allowed weak linkage, because it allows their compile-time and runtime behavior to differ.
CHANNEL gets fully codegened when compiling the crate that contains it. To do this, it's full type needs to be known, which in turn requires CH_SIZE to be known. Note that the very fact if compilation succeeds or not and which functions get codegened can depend on the value of a const item or const function. As such weak linkage for const items and const functions can't work. And that is not even taking into account the fact that const items by definition don't have a symbol name unlike statics, but weak linkage matches on symbol name.
Indeed, we may wish to investigate making this a compiler error.
But first, while an expert on the linking side of things has spoken, let us consult the experts on the CTFE side of things. cc @rust-lang/wg-const-eval do any of you wish to entertain the possibility of a const fn having its symbol name overwritten at runtime, and users like @HaoboGu consequently seriously misunderstanding the model?
@HaoboGu The idea of "generic singletons" is an interesting idea, but it's absolutely not the way things work, and if it did work, it would have to be designed in such a way as to actually be evaluated without taking linkage into account.
No I don't think const fn intends to ever support terrible linker hacks like that. ;) If there's a use-case here, it should be solved with proper, type-safe Rust mechanisms, not at the linker level. What should even happen if 3 crates each overwrite get_foo (or CH_SIZE) with a different value? I don't see how we could have a sensible safe system here.
Even on regular fn this is rather questionable, considering things like inlining. What even is the semantics here? When you call get_foo it non-deterministically calls some function with that name? AFAIK currently we have a safety requirement on no_mangle that there must be only one function with that name, so technically your code has UB. We probably want to adjust this to support weak linkage since people want to use their terrible linker hacks, but we should do so carefully.
And, as a library author, we may want the CH_SIZE to be customizable by library users.
Constants are called that because they must be constant. It would be unsound to let anyone change them. The type system relies hard to the fact that the same constant has the same value everywhere in the crate graph.
If you want to write your code in a way that is generic over some constant, you need to make it explicitly generic. We have mechanisms for that already (associated consts in a trait). I know that making an entire module generic can be annoying, but the solution for that definitely does not involve fundamentally changing the nature of consts in Rust; the solution is to explore module-level generics.
Yeah that's definitely on our list. We're now calling our project "externally implementable items", and consts are also on our list of items, although not our first priority. We'll see how far we can get. :)
Reacted by HaoboGu, zachs18, Kane York and Jubilee
Activity
zopsicle commentedon Dec 18, 2024
Const items are always evaluated at compile time, which happens before linking, so this is expected. Perhaps const functions should not be allowed weak linkage, because it allows their compile-time and runtime behavior to differ.
HaoboGu commentedon Dec 18, 2024
I think it's valuable to have "weak constants" in Rust, just disallowing weak linkage for const fns is not we want.
For example, in no_std env, it's very common to define a global channel with a fixed size:
And, as a library author, we may want the
CH_SIZEto be customizable by library users. It's impossible for Rust without using weak linkage now.[-][linkage = "weak"] doesn't work for const fn[/-][+]`#[linkage = "weak"]` doesn't work for const fn[/+]bjorn3 commentedon Dec 18, 2024
CHANNELgets fully codegened when compiling the crate that contains it. To do this, it's full type needs to be known, which in turn requiresCH_SIZEto be known. Note that the very fact if compilation succeeds or not and which functions get codegened can depend on the value of a const item or const function. As such weak linkage for const items and const functions can't work. And that is not even taking into account the fact that const items by definition don't have a symbol name unlike statics, but weak linkage matches on symbol name.workingjubilee commentedon Dec 18, 2024
Indeed, we may wish to investigate making this a compiler error.
But first, while an expert on the linking side of things has spoken, let us consult the experts on the CTFE side of things. cc @rust-lang/wg-const-eval do any of you wish to entertain the possibility of a const fn having its symbol name overwritten at runtime, and users like @HaoboGu consequently seriously misunderstanding the model?
workingjubilee commentedon Dec 18, 2024
@HaoboGu The idea of "generic singletons" is an interesting idea, but it's absolutely not the way things work, and if it did work, it would have to be designed in such a way as to actually be evaluated without taking linkage into account.
RalfJung commentedon Dec 18, 2024
No I don't think
const fnintends to ever support terrible linker hacks like that. ;) If there's a use-case here, it should be solved with proper, type-safe Rust mechanisms, not at the linker level. What should even happen if 3 crates each overwriteget_foo(orCH_SIZE) with a different value? I don't see how we could have a sensible safe system here.Even on regular
fnthis is rather questionable, considering things like inlining. What even is the semantics here? When you callget_fooit non-deterministically calls some function with that name? AFAIK currently we have a safety requirement onno_manglethat there must be only one function with that name, so technically your code has UB. We probably want to adjust this to support weak linkage since people want to use their terrible linker hacks, but we should do so carefully.RalfJung commentedon Dec 18, 2024
Constants are called that because they must be constant. It would be unsound to let anyone change them. The type system relies hard to the fact that the same constant has the same value everywhere in the crate graph.
If you want to write your code in a way that is generic over some constant, you need to make it explicitly generic. We have mechanisms for that already (associated consts in a trait). I know that making an entire module generic can be annoying, but the solution for that definitely does not involve fundamentally changing the nature of consts in Rust; the solution is to explore module-level generics.
4 remaining items
workingjubilee commentedon Dec 18, 2024
Plausible. cc @m-ou-se if you have any thoughts (or not if not, it's just a data point of possible interest).
m-ou-se commentedon Dec 19, 2024
Yeah that's definitely on our list. We're now calling our project "externally implementable items", and consts are also on our list of items, although not our first priority. We'll see how far we can get. :)
workingjubilee commentedon Dec 21, 2024
Cool!
This issue is now about diagnostics! We should at least warn, probably compile error on this.
[-]`#[linkage = "weak"]` doesn't work for const fn[/-][+]`#[linkage = "weak"] const fn` accepted without warning[/+]Rollup merge of rust-lang#159617 - mejrs:weak_linkage, r=JonathanBrouwer
Rollup merge of rust-lang#159617 - mejrs:weak_linkage, r=JonathanBrouwer
Rollup merge of rust-lang#159617 - mejrs:weak_linkage, r=JonathanBrouwer
Rollup merge of rust-lang#159617 - mejrs:weak_linkage, r=JonathanBrouwer
Rollup merge of rust-lang#159617 - mejrs:weak_linkage, r=JonathanBrouwer
Rollup merge of rust-lang#159617 - mejrs:weak_linkage, r=JonathanBrouwer
Unrolled build for #159617
Rollup merge of #159617 - mejrs:weak_linkage, r=JonathanBrouwer