-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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 future-incompatibility lint const_evaluatable_unchecked
#76200
Comments
Merging #74532 just now ran into this problem. I worked around it by using - let [] = [(); align_of::<Self>() - align_of::<*mut T>()];
+ let [] = [(); align_of::<AtomicPtr<()>>() - align_of::<*mut ()>()]; Here, not only |
Following from https://users.rust-lang.org/t/cant-understand-warning-when-using-const-evaluatable-checked/55630/6?u=yandros, the following snippet causes three warnings associated with the lint of this tracking issue, and a hard error: const _10: usize = 10;
fn write_struct<T> ()
where
can_be_evaluated!(_10 - 0):,
{
foo::<T, 10>(); // Warning
foo::<T, { _10 }>(); // Error (same for `{ 10 }`)
WithConst::<10>::foo::<T>(); // Warning
WithConst::<{ _10 }>::foo::<T>(); // Warning
WithConst::<10>::write_struct::<T>(); // OK
WithConst::<{ _10 }>::write_struct::<T>(); // OK
} where
In the case of As you can see, a caller that:
now triggers either this warning, or some related error when the constant is braced (which is sadly required when using a non-literal constant; even when the function features an evaluatable bound on said non-literal constant). Finally, the last two calls in this example are interesting: by moving the logic of the function within the generic-and-evaluatable-bounded This leads to two questions:
|
From what I can tell this is not expected, Afaict all of the examples you've given should work without warnings or errors. |
In |
While checking whether the fixed crate can be ported from typenum to nightly with I've reduced the code though I left some stuff to show why it would be useful. #![feature(generic_const_exprs)]
pub struct If<const CONDITION: bool>;
pub trait True {}
impl True for If<true> {}
pub struct FixedI8<const FRAC: u32> {
pub bits: i8,
}
impl<const FRAC_LHS: u32, const FRAC_RHS: u32> PartialEq<FixedI8<FRAC_RHS>> for FixedI8<FRAC_LHS>
where
If<{ FRAC_RHS <= 8 }>: True,
{
fn eq(&self, _rhs: &FixedI8<FRAC_RHS>) -> bool {
unimplemented!()
}
}
impl<const FRAC: u32> PartialEq<i8> for FixedI8<FRAC> {
fn eq(&self, rhs: &i8) -> bool {
let rhs_as_fixed = FixedI8::<0> { bits: *rhs };
PartialEq::eq(self, &rhs_as_fixed)
}
} |
I admit not understanding this (and reasoning behind it) fully. But I have use case for an associative type with a bound that depends on its owner (trait)'s const generic parameter. Any alternatives/workarounds, please? Short example failing no Nightly (thanks to ilyvion#9946 for narrowing it down): https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=c133c09b2fa155bb3f4b9ee45e6c011e. My use case: https://github.com/ranging-rs/slicing-rs/blob/main/src/slices/mod.rs#L30=. I know it's a semantic/voluntary-like constraint only, but I believe it deserves its place. (Feel free to follow up at ranging-rs/slicing-rs#1.) |
@peter-kehl this is #94293 again, this lint is only relevant when not using |
I don't really understand the rationality of this limitation, also, it's weird to need to read it on external link and not directly in github. I think this subject didn't get much attention. Recent question where an user would want to use it How can I give a name to the constant size of an array which is a member of a struct? |
Disclaimer: I'm neither a compiler engineer, nor a typesystem-language-lawyer – I'm sure, from a technical point of view, the rationale behind this is probably sound. However, if I look at this from the developer-UX-perspective, I'm not happy with this warning... Specific use-caseI have a struct (simplified): /// Raw SPI command interface for RFM95
pub struct Rfm95<Peripheral, Tx, Rx, Sck, Select, Reset>
where
Peripheral: SpiDevice,
Tx: PinId + ValidPinIdTx<Peripheral>,
Rx: PinId + ValidPinIdRx<Peripheral>,
Sck: PinId + ValidPinIdSck<Peripheral>,
Select: PinId,
Reset: PinId,
{
/// The SPI bus
bus: SpiBus<Peripheral, Tx, Rx, Sck>,
/// The chip select line
select: PinChipSelect<Select>,
/// The chip reset line
reset: PinReset<Reset>,
}
impl<Peripheral, Tx, Rx, Sck, Select, Reset> Rfm95<Peripheral, Tx, Rx, Sck, Select, Reset>
where
Peripheral: SpiDevice,
Tx: PinId + ValidPinIdTx<Peripheral>,
Rx: PinId + ValidPinIdRx<Peripheral>,
Sck: PinId + ValidPinIdSck<Peripheral>,
Select: PinId,
Reset: PinId,
{
/// The total FIFO size
const FIFO_SIZE: usize = 0xFF;
/// The register address to access the FIFO address pointer
const REGISTER_FIFO_ADDRESS_POINTER: u8 = 0x0D;
// ... implementation and member functions ...
} Now, as naive developer, I tried to create an array in a member function // Copy data into mutable buffer
let mut data_mut = [0; Self::FIFO_SIZE]; which raises this warning. I really don't understand why this restriction exists and this warning is emitted... the constant is fully constant; it's not dependent on any of the generic types, has no dynamic parts whatsoever, it's always Coming from a naive developer-UX-perspective, it's really not understandable why that's a problem at all. Now I'm sitting here without any reasonable workaround* (except free-floating constants or magic values), and that was so unsatisfying, I wrote this comment here 😅 *If I missed something, please tell me and I'll happily heat my own words 😅 |
I think the intended work-around is to move the |
I don't really understand this part. As far as I see it, in most cases I can declare and use constants within generic structs pretty fine. I don't get a warning if I use And that feels inconsistent.
Yup, it's the obvious fix, but that also feels more like a hack. Now I have to move this single const out of its associated context, while all other consts can stay in there and be used for constant operations (even compile-time assertions). At that point, I might as well hardcode the constant 😅 EDIT:It appears even more inconsistent once you realize that you can easily do stuff like impl<Peripheral, Tx, Rx, Sck, Select, Reset> Rfm95<Peripheral, Tx, Rx, Sck, Select, Reset>
where
Peripheral: SpiDevice,
Tx: PinId + ValidPinIdTx<Peripheral>,
Rx: PinId + ValidPinIdRx<Peripheral>,
Sck: PinId + ValidPinIdSck<Peripheral>,
Select: PinId,
Reset: PinId,
{
/// A default FIFO buffer "seed"
const FIFO_BUF_DEFAULT: [u8; 0xFF] = [0x00; 0xFF];
} and use that instead, which works again. Please note that I don't want to flame here; it's just that Rust makes great effort to be intuitive and developer-friendly, from error messages to 0-compromise correct APIs (e.g. |
Correct; using them as values is fine, but using them in types (like in an array size) is problematic. There's a big difference between these two ways of using something. That should hopefully be less surprising if you consider that runtime values are entirely forbidden as array sizes! Just because consts are allowed in both places, doesn't mean that suddenly these fundamental differences disappear. Consts are allowed in both places but they behave quite differently. Now, this is all preliminary, and I don't know the long-term plans for generic consts. But there is an underlying consistency here. The confusing stems from conflating runtime expressions and compile-time expressions even though those are completely different beasts. |
const_evaluatable_unchecked
ICU4X hits this here: We use This const is not dependent on the generic parameter. |
This is the summary issue for the
CONST_EVALUATABLE_UNCHECKED
future-compatibility warning. The goal of this page is to describe why this change was made and how you can fix code that is affected by it. It also provides a place to ask questionsor register a complaint if you feel the change should not be made. For more information on the policy around future-compatibility warnings, see our breaking change policy guidelines.
What is the warning for?
In version 1.43 we accidentally allowed some uses of generic parameters in repeat expressions. This has a few problems which are outlined in the following document for now.
When will this warning become a hard error?
Most probably after const well-formedness bounds get stabilized, which is currently not yet implemented. There might be a subset of cases here which we can allow without needing any changes, but these require further careful consideration.
How to fix this?
As we only allowed generic constants where the actual type did not matter, it should always be possible to replace the generic parameters with dummy types. For example
[0; std::mem::size_of::<*mut T>()]
can be changed to[0; std::mem::size_of::<*mut ()>()]
.Please report your case here so we may take it into consideration when deciding on how to proceed.
The text was updated successfully, but these errors were encountered: