-
Notifications
You must be signed in to change notification settings - Fork 12.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #106281 - JulianKnodt:transmute_const_generics, r=b-naber
Add ability to transmute (somewhat) with generic consts in arrays Previously if the expression contained generic consts and did not have a directly equivalent type, transmuting the type in this way was forbidden, despite the two sizes being identical. Instead, we should be able to lazily tell if the two consts are identical, and if so allow them to be transmuted. This is done by normalizing the forms of expressions into sorted order of multiplied terms, which is not generic over all expressions, but should handle most cases. This allows for some _basic_ transmutations between types that are equivalent in size without requiring additional stack space at runtime. I only see one other location at which `SizeSkeleton` is being used, and it checks for equality so this shouldn't affect anywhere else that I can tell. See [this Stackoverflow post](https://stackoverflow.com/questions/73085012/transmute-nested-const-generic-array-rust) for what was previously necessary to convert between types. This PR makes converting nested `T -> [T; 1]` transmutes possible, and `[uB*2; N] -> [uB; N * 2]` possible as well. I'm not sure whether this is something that would be wanted, and if it is it definitely should not be insta-stable, so I'd add a feature gate.
- Loading branch information
Showing
9 changed files
with
450 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#![feature(transmute_generic_consts)] | ||
#![feature(generic_const_exprs)] | ||
#![allow(incomplete_features)] | ||
|
||
fn foo<const W: usize, const H: usize>(v: [[u32;H+1]; W]) -> [[u32; W+1]; H] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
//~^ ERROR cannot transmute | ||
} | ||
} | ||
|
||
fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { | ||
//~^ ERROR mismatched types | ||
//~| ERROR mismatched types | ||
unsafe { | ||
std::mem::transmute(v) | ||
//~^ ERROR cannot transmute between types | ||
} | ||
} | ||
|
||
fn baz<const W: usize, const H: usize>(v: [[u32; H]; W]) -> [u32; W * H * H] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
//~^ ERROR cannot transmute | ||
} | ||
} | ||
|
||
fn overflow(v: [[[u32; 8888888]; 9999999]; 777777777]) -> [[[u32; 9999999]; 777777777]; 8888888] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
//~^ ERROR cannot transmute | ||
} | ||
} | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types | ||
--> $DIR/transmute-fail.rs:7:5 | ||
| | ||
LL | std::mem::transmute(v) | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
| | ||
= note: source type: `[[u32; H+1]; W]` (generic size [const expr]) | ||
= note: target type: `[[u32; W+1]; H]` (generic size [const expr]) | ||
|
||
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types | ||
--> $DIR/transmute-fail.rs:16:5 | ||
| | ||
LL | std::mem::transmute(v) | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
| | ||
= note: source type: `[[u32; H]; W]` (this type does not have a fixed size) | ||
= note: target type: `[[u32; W]; H]` (size can vary because of [u32; W]) | ||
|
||
error[E0308]: mismatched types | ||
--> $DIR/transmute-fail.rs:12:53 | ||
| | ||
LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { | ||
| ^ expected `usize`, found `bool` | ||
|
||
error[E0308]: mismatched types | ||
--> $DIR/transmute-fail.rs:12:67 | ||
| | ||
LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { | ||
| ^ expected `usize`, found `bool` | ||
|
||
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types | ||
--> $DIR/transmute-fail.rs:23:5 | ||
| | ||
LL | std::mem::transmute(v) | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
| | ||
= note: source type: `[[u32; H]; W]` (generic size [const expr]) | ||
= note: target type: `[u32; W * H * H]` (generic size [const expr]) | ||
|
||
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types | ||
--> $DIR/transmute-fail.rs:30:5 | ||
| | ||
LL | std::mem::transmute(v) | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
| | ||
= note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[[u32; 8888888]; 9999999]; 777777777]` are too big for the current architecture) | ||
= note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[[u32; 9999999]; 777777777]; 8888888]` are too big for the current architecture) | ||
|
||
error: aborting due to 6 previous errors | ||
|
||
Some errors have detailed explanations: E0308, E0512. | ||
For more information about an error, try `rustc --explain E0308`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// run-pass | ||
#![feature(generic_const_exprs)] | ||
#![feature(transmute_generic_consts)] | ||
#![allow(incomplete_features)] | ||
|
||
fn transpose<const W: usize, const H: usize>(v: [[u32;H]; W]) -> [[u32; W]; H] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
} | ||
} | ||
|
||
fn ident<const W: usize, const H: usize>(v: [[u32; H]; W]) -> [[u32; H]; W] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
} | ||
} | ||
|
||
fn flatten<const W: usize, const H: usize>(v: [[u32; H]; W]) -> [u32; W * H] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
} | ||
} | ||
|
||
fn coagulate<const W: usize, const H: usize>(v: [u32; H*W]) -> [[u32; W];H] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
} | ||
} | ||
|
||
fn flatten_3d<const W: usize, const H: usize, const D: usize>( | ||
v: [[[u32; D]; H]; W] | ||
) -> [u32; D * W * H] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
} | ||
} | ||
|
||
fn flatten_somewhat<const W: usize, const H: usize, const D: usize>( | ||
v: [[[u32; D]; H]; W] | ||
) -> [[u32; D * W]; H] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
} | ||
} | ||
|
||
fn known_size<const L: usize>(v: [u16; L]) -> [u8; L * 2] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
} | ||
} | ||
|
||
fn condense_bytes<const L: usize>(v: [u8; L * 2]) -> [u16; L] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
} | ||
} | ||
|
||
fn singleton_each<const L: usize>(v: [u8; L]) -> [[u8;1]; L] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
} | ||
} | ||
|
||
fn transpose_with_const<const W: usize, const H: usize>( | ||
v: [[u32; 2 * H]; W + W] | ||
) -> [[u32; W + W]; 2 * H] { | ||
unsafe { | ||
std::mem::transmute(v) | ||
} | ||
} | ||
|
||
fn main() { | ||
let _ = transpose([[0; 8]; 16]); | ||
let _ = transpose_with_const::<8,4>([[0; 8]; 16]); | ||
let _ = ident([[0; 8]; 16]); | ||
let _ = flatten([[0; 13]; 5]); | ||
let _: [[_; 5]; 13] = coagulate([0; 65]); | ||
let _ = flatten_3d([[[0; 3]; 13]; 5]); | ||
let _ = flatten_somewhat([[[0; 3]; 13]; 5]); | ||
let _ = known_size([16; 13]); | ||
let _: [u16; 5] = condense_bytes([16u8; 10]); | ||
let _ = singleton_each([16; 10]); | ||
} |
Oops, something went wrong.