rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.68k stars 12.75k forks source link

mem::size_of::<T> not const - use of type variable from outer function #56794

Open frehberg opened 5 years ago

frehberg commented 5 years ago

The following CDR-serde implementation defines functions to serialize data-types such as u16, u32 etc. It is using an abstract function to align write-position, to match with multiple of mem::size_of(), where T is a primitive int or float type.

As the bytesize is known at compile time, I would like to declare the value as const, using the following patch ://github.com/frehberg/cdr-rs/pull/1

impl<W, E> Serializer<W, E>
where
    W: Write,
    E: ByteOrder,
{
....
  fn write_padding_of<T>(&mut self) -> Result<()> {
        // Calculate the required padding to align with 1-byte, 2-byte, 4-byte, 8-byte boundaries
        // Instead of using the slow modulo operation '%', the faster bit-masking is used
        const PADDING: [u8; 8] = [0; 8];
        const ALIGNMENT: usize = std::mem::size_of::<T>();
        const MASK = ALIGNMENT - 1; // mask like 0x0, 0x1, 0x3, 0x7
        match (self.pos as usize) & MASK {
            0 => Ok(()),
            n @ 1...7 => {
                let amt = ALIGNMENT - n;
                self.pos += amt as u64;
                self.writer.write_all(&PADDING[..amt]).map_err(Into::into)
            }
            _ => unreachable!(),
        }
    }

but compiler yields with error

error: Could not compile `cdr`.
warning: build failed, waiting for other jobs to finish...
error[E0401]: can't use type parameters from outer function
  --> src/ser.rs:51:54
47 |     fn write_padding_of<T>(&mut self) -> Result<()> {
   |        ---------------- - type variable from outer function
   |        |
   |        try adding a local type parameter in this method instead
...
51 |         const ALIGNMENT: usize = std::mem::size_of::<T>();
   |                                                      ^ use of type variable from outer function
For more information about this error, try `rustc --explain E0401`.
error: Could not compile `cdr`.

As the generic function is not exported by lib, and it is instanciated only from inside the crate, I am wondering why the compiler is not able to derive the type of parameter T.

Any idea?

EDIT the explanation of E0401 does not fit to this code

KamilaBorowska commented 5 years ago

I would say that E0401 explains it fairly well, in the first sentence.

Inner items do not inherit type parameters from the functions they are embedded in.

And E0401 further explains it.

Items inside functions are basically just like top-level items, except that they can only be used from the function they are in.

const is an item, so it cannot use a type parameter. As you don't require const in this example, you may want to use let instead.

That said, the hint is wrong, you cannot add a local type parameter in const/static, unlike pretty much any other item. It's possible that it will be possible to add a local type parameter to const in the future, but it's not the future yet.

frehberg commented 5 years ago

Sorry, but E0401 doesn't fit, as there is no such scoping or inner/outer present EDITED Maybe there is another hint, that could be presented instead.

It is interesting to see, how much effort it takes to cover with the compiler all different use cases. Thanks for the good work with Rust.

KamilaBorowska commented 5 years ago

That seems like a duplicate of #45447, unless there is something I'm not understanding.

jonas-schievink commented 5 years ago

45447 is now fixed. @frehberg can you check whether the diagnostics are better on the current nightly?