Skip to content

Commit 95c58be

Browse files
committed
Crude impl of a more strict transmute check
1 parent edae1cc commit 95c58be

12 files changed

+212
-34
lines changed

src/librustc/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2139,6 +2139,6 @@ register_diagnostics! {
21392139
E0657, // `impl Trait` can only capture lifetimes bound at the fn level
21402140
E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
21412141
E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
2142-
21432142
E0906, // closures cannot be static
2143+
E0912, // transmutation between types of unspecified layout
21442144
}

src/librustc/middle/intrinsicck.rs

+17
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,23 @@ impl<'a, 'tcx> ExprVisitor<'a, 'tcx> {
116116
}
117117
};
118118

119+
let unspecified_layout = |msg, ty| {
120+
struct_span_err!(self.tcx.sess, span, E0912, "{}", msg)
121+
.note(&format!("{} has an unspecified layout", ty))
122+
.note("this will become a hard error in the future")
123+
.emit();
124+
};
125+
126+
// Check that types have specified layout
127+
if from.has_specified_layout(self.tcx) == Some(false) {
128+
unspecified_layout("transmutation from a type with an unspecified layout", from);
129+
}
130+
131+
if to.has_specified_layout(self.tcx) == Some(false) {
132+
unspecified_layout("transmutation to a type with an unspecified layout", to);
133+
}
134+
135+
119136
struct_span_err!(self.tcx.sess, span, E0512,
120137
"transmute called with types of different sizes")
121138
.note(&format!("source type: {} ({})", from, skeleton_string(from, sk_from)))

src/librustc/ty/sty.rs

+73-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use middle::region;
1717
use polonius_engine::Atom;
1818
use rustc_data_structures::indexed_vec::Idx;
1919
use ty::subst::{Substs, Subst, Kind, UnpackedKind};
20-
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
20+
use ty::{self, AdtDef, AdtKind, TypeFlags, Ty, TyCtxt, TypeFoldable};
2121
use ty::{Slice, TyS, ParamEnvAnd, ParamEnv};
2222
use util::captures::Captures;
2323
use mir::interpret::{Scalar, Pointer, Value, ConstValue};
@@ -1848,6 +1848,78 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
18481848
_ => bug!("cannot convert type `{:?}` to a closure kind", self),
18491849
}
18501850
}
1851+
1852+
//
1853+
pub fn has_specified_layout(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<bool> {
1854+
match self.sty {
1855+
// Not concrete, cannot say anything
1856+
TyInfer(_) | TyError | TyParam(_) | TyProjection(_) | TyAnon(_, _) | TyDynamic(_, _) =>
1857+
None,
1858+
// Outright unspecified to be anything in particular
1859+
TyClosure(_, _) | TyGenerator(_, _, _) | TyGeneratorWitness(_) => Some(false),
1860+
TyFnDef(_, _) => Some(false),
1861+
TyTuple(_) => Some(false),
1862+
TyForeign(_) => Some(false),
1863+
// Unsized types
1864+
TyNever | TyStr | TySlice(_) => Some(false),
1865+
1866+
1867+
// Definitely specified layout
1868+
TyFnPtr(_) |
1869+
TyBool |
1870+
TyChar |
1871+
TyInt(_) |
1872+
TyUint(_) |
1873+
TyFloat(_) |
1874+
// FIXME: not for fat pointers.
1875+
TyRawPtr(_) => Some(true),
1876+
1877+
// FIXME: Properly handle sizedness check
1878+
TyRef(_, &ty::TyS { sty: TyNever, .. }, _) => Some(false),
1879+
TyRef(_, &ty::TyS { sty: TyStr, .. }, _) => Some(false),
1880+
TyRef(_, &ty::TyS { sty: TySlice(_), .. }, _) => Some(false),
1881+
TyRef(_, _, _) => Some(true),
1882+
1883+
// Layout specification depends on inner types
1884+
TyArray(ty, _) => {
1885+
ty.has_specified_layout(tcx)
1886+
},
1887+
TyAdt(def, substs) => {
1888+
// Documentation guarantees 0-sizedness.
1889+
if def.is_phantom_data() {
1890+
return Some(true);
1891+
}
1892+
match def.adt_kind() {
1893+
AdtKind::Struct | AdtKind::Union => {
1894+
if !def.repr.c() && !def.repr.transparent() {
1895+
return Some(false);
1896+
}
1897+
// FIXME: do we guarantee 0-sizedness for structs with 0 fields?
1898+
// If not, they should cause Some(false) here.
1899+
let mut seen_none = false;
1900+
for field in &def.non_enum_variant().fields {
1901+
let field_ty = field.ty(tcx, substs);
1902+
match field_ty.has_specified_layout(tcx) {
1903+
Some(true) => continue,
1904+
None => {
1905+
seen_none = true;
1906+
continue;
1907+
}
1908+
x => return x,
1909+
}
1910+
}
1911+
return if seen_none { None } else { Some(true) };
1912+
}
1913+
AdtKind::Enum => {
1914+
if !def.repr.c() {
1915+
return Some(false);
1916+
}
1917+
return Some(true);
1918+
}
1919+
}
1920+
},
1921+
}
1922+
}
18511923
}
18521924

18531925
/// Typed constant value.

src/test/compile-fail/issue-28625.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ struct ArrayPeano<T: Bar> {
1717
}
1818

1919
fn foo<T>(a: &ArrayPeano<T>) -> &[T] where T: Bar {
20-
unsafe { std::mem::transmute(a) } //~ ERROR transmute called with types of different sizes
20+
unsafe { std::mem::transmute(a) }
21+
//~^ ERROR transmutation to a type with an unspecified layout
22+
//~| ERROR transmute called with types of different sizes
2123
}
2224

2325
impl Bar for () {

src/test/compile-fail/issue-32377.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ struct Bar<U: Foo> {
2121

2222
fn foo<U: Foo>(x: [usize; 2]) -> Bar<U> {
2323
unsafe { mem::transmute(x) }
24-
//~^ ERROR transmute called with types of different sizes
24+
//~^ ERROR transmutation to a type with an unspecified layout
25+
//~| ERROR transmute called with types of different sizes
2526
}
2627

2728
fn main() {}

src/test/compile-fail/transmute-fat-pointers.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
use std::mem::transmute;
1616

1717
fn a<T, U: ?Sized>(x: &[T]) -> &U {
18-
unsafe { transmute(x) } //~ ERROR transmute called with types of different sizes
18+
unsafe { transmute(x) }
19+
//~^ ERROR transmutation from a type with an unspecified layout
20+
//~| ERROR transmute called with types of different sizes
1921
}
2022

2123
fn b<T: ?Sized, U: ?Sized>(x: &T) -> &U {

src/test/ui/transmute/main.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,16 @@ unsafe fn sizes() {
3131
}
3232

3333
unsafe fn ptrs() {
34-
let x: u8 = transmute("test"); //~ ERROR transmute called with types of different sizes
34+
let x: u8 = transmute("test");
35+
//~^ ERROR transmutation from a type with an unspecified layout
36+
//~| ERROR transmute called with types of different sizes
3537
}
3638

3739
union Foo { x: () }
3840
unsafe fn vary() {
39-
let x: Foo = transmute(10); //~ ERROR transmute called with types of different sizes
41+
let x: Foo = transmute(10);
42+
//~^ ERROR transmutation to a type with an unspecified layout
43+
//~| ERROR transmute called with types of different sizes
4044
}
4145

4246
fn main() {}

src/test/ui/transmute/main.stderr

+24-5
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,43 @@ LL | let x: u8 = transmute(10u16); //~ ERROR transmute called with types of
1616
= note: source type: u16 (16 bits)
1717
= note: target type: u8 (8 bits)
1818

19+
error[E0912]: transmutation from a type with an unspecified layout
20+
--> $DIR/main.rs:34:17
21+
|
22+
LL | let x: u8 = transmute("test");
23+
| ^^^^^^^^^
24+
|
25+
= note: &str has an unspecified layout
26+
= note: this will become a hard error in the future
27+
1928
error[E0512]: transmute called with types of different sizes
2029
--> $DIR/main.rs:34:17
2130
|
22-
LL | let x: u8 = transmute("test"); //~ ERROR transmute called with types of different sizes
31+
LL | let x: u8 = transmute("test");
2332
| ^^^^^^^^^
2433
|
2534
= note: source type: &str ($STR bits)
2635
= note: target type: u8 (8 bits)
2736

37+
error[E0912]: transmutation to a type with an unspecified layout
38+
--> $DIR/main.rs:41:18
39+
|
40+
LL | let x: Foo = transmute(10);
41+
| ^^^^^^^^^
42+
|
43+
= note: Foo has an unspecified layout
44+
= note: this will become a hard error in the future
45+
2846
error[E0512]: transmute called with types of different sizes
29-
--> $DIR/main.rs:39:18
47+
--> $DIR/main.rs:41:18
3048
|
31-
LL | let x: Foo = transmute(10); //~ ERROR transmute called with types of different sizes
49+
LL | let x: Foo = transmute(10);
3250
| ^^^^^^^^^
3351
|
3452
= note: source type: i32 (32 bits)
3553
= note: target type: Foo (0 bits)
3654

37-
error: aborting due to 4 previous errors
55+
error: aborting due to 6 previous errors
3856

39-
For more information about this error, try `rustc --explain E0512`.
57+
Some errors occurred: E0512, E0912.
58+
For more information about an error, try `rustc --explain E0512`.

src/test/ui/transmute/transmute-from-fn-item-types-error.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use std::mem;
1212

1313
unsafe fn foo() -> (i8, *const (), Option<fn()>) {
1414
let i = mem::transmute(bar);
15-
//~^ ERROR transmute called with types of different sizes
15+
//~^ ERROR transmutation from a type with an unspecified layout
16+
//~| ERROR transmute called with types of different sizes
1617

1718

1819
let p = mem::transmute(foo);
@@ -29,7 +30,8 @@ unsafe fn foo() -> (i8, *const (), Option<fn()>) {
2930
unsafe fn bar() {
3031
// Error as usual if the resulting type is not pointer-sized.
3132
mem::transmute::<_, u8>(main);
32-
//~^ ERROR transmute called with types of different sizes
33+
//~^ ERROR transmutation from a type with an unspecified layout
34+
//~| ERROR transmute called with types of different sizes
3335

3436

3537
mem::transmute::<_, *mut ()>(foo);

src/test/ui/transmute/transmute-from-fn-item-types-error.stderr

+28-10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
error[E0912]: transmutation from a type with an unspecified layout
2+
--> $DIR/transmute-from-fn-item-types-error.rs:14:13
3+
|
4+
LL | let i = mem::transmute(bar);
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: unsafe fn() {bar} has an unspecified layout
8+
= note: this will become a hard error in the future
9+
110
error[E0512]: transmute called with types of different sizes
211
--> $DIR/transmute-from-fn-item-types-error.rs:14:13
312
|
@@ -8,7 +17,7 @@ LL | let i = mem::transmute(bar);
817
= note: target type: i8 (8 bits)
918

1019
error[E0591]: can't transmute zero-sized type
11-
--> $DIR/transmute-from-fn-item-types-error.rs:18:13
20+
--> $DIR/transmute-from-fn-item-types-error.rs:19:13
1221
|
1322
LL | let p = mem::transmute(foo);
1423
| ^^^^^^^^^^^^^^
@@ -18,7 +27,7 @@ LL | let p = mem::transmute(foo);
1827
= help: cast with `as` to a pointer instead
1928

2029
error[E0591]: can't transmute zero-sized type
21-
--> $DIR/transmute-from-fn-item-types-error.rs:22:14
30+
--> $DIR/transmute-from-fn-item-types-error.rs:23:14
2231
|
2332
LL | let of = mem::transmute(main);
2433
| ^^^^^^^^^^^^^^
@@ -27,8 +36,17 @@ LL | let of = mem::transmute(main);
2736
= note: target type: std::option::Option<fn()>
2837
= help: cast with `as` to a pointer instead
2938

39+
error[E0912]: transmutation from a type with an unspecified layout
40+
--> $DIR/transmute-from-fn-item-types-error.rs:32:5
41+
|
42+
LL | mem::transmute::<_, u8>(main);
43+
| ^^^^^^^^^^^^^^^^^^^^^^^
44+
|
45+
= note: fn() {main} has an unspecified layout
46+
= note: this will become a hard error in the future
47+
3048
error[E0512]: transmute called with types of different sizes
31-
--> $DIR/transmute-from-fn-item-types-error.rs:31:5
49+
--> $DIR/transmute-from-fn-item-types-error.rs:32:5
3250
|
3351
LL | mem::transmute::<_, u8>(main);
3452
| ^^^^^^^^^^^^^^^^^^^^^^^
@@ -37,7 +55,7 @@ LL | mem::transmute::<_, u8>(main);
3755
= note: target type: u8 (8 bits)
3856

3957
error[E0591]: can't transmute zero-sized type
40-
--> $DIR/transmute-from-fn-item-types-error.rs:35:5
58+
--> $DIR/transmute-from-fn-item-types-error.rs:37:5
4159
|
4260
LL | mem::transmute::<_, *mut ()>(foo);
4361
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -47,7 +65,7 @@ LL | mem::transmute::<_, *mut ()>(foo);
4765
= help: cast with `as` to a pointer instead
4866

4967
error[E0591]: can't transmute zero-sized type
50-
--> $DIR/transmute-from-fn-item-types-error.rs:39:5
68+
--> $DIR/transmute-from-fn-item-types-error.rs:41:5
5169
|
5270
LL | mem::transmute::<_, fn()>(bar);
5371
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +75,7 @@ LL | mem::transmute::<_, fn()>(bar);
5775
= help: cast with `as` to a pointer instead
5876

5977
error[E0591]: can't transmute zero-sized type
60-
--> $DIR/transmute-from-fn-item-types-error.rs:48:5
78+
--> $DIR/transmute-from-fn-item-types-error.rs:50:5
6179
|
6280
LL | mem::transmute::<_, *mut ()>(Some(foo));
6381
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -67,7 +85,7 @@ LL | mem::transmute::<_, *mut ()>(Some(foo));
6785
= help: cast with `as` to a pointer instead
6886

6987
error[E0591]: can't transmute zero-sized type
70-
--> $DIR/transmute-from-fn-item-types-error.rs:52:5
88+
--> $DIR/transmute-from-fn-item-types-error.rs:54:5
7189
|
7290
LL | mem::transmute::<_, fn()>(Some(bar));
7391
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +95,7 @@ LL | mem::transmute::<_, fn()>(Some(bar));
7795
= help: cast with `as` to a pointer instead
7896

7997
error[E0591]: can't transmute zero-sized type
80-
--> $DIR/transmute-from-fn-item-types-error.rs:56:5
98+
--> $DIR/transmute-from-fn-item-types-error.rs:58:5
8199
|
82100
LL | mem::transmute::<_, Option<fn()>>(Some(baz));
83101
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -86,7 +104,7 @@ LL | mem::transmute::<_, Option<fn()>>(Some(baz));
86104
= note: target type: std::option::Option<fn()>
87105
= help: cast with `as` to a pointer instead
88106

89-
error: aborting due to 9 previous errors
107+
error: aborting due to 11 previous errors
90108

91-
Some errors occurred: E0512, E0591.
109+
Some errors occurred: E0512, E0591, E0912.
92110
For more information about an error, try `rustc --explain E0512`.

src/test/ui/transmute/transmute-type-parameters.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ unsafe fn f<T>(x: T) {
2424

2525
unsafe fn g<T>(x: (T, i32)) {
2626
let _: i32 = transmute(x);
27-
//~^ ERROR transmute called with types of different sizes
27+
//~^ ERROR transmutation from a type with an unspecified layout
28+
//~| ERROR transmute called with types of different sizes
2829
}
2930

3031
unsafe fn h<T>(x: [T; 10]) {
@@ -38,7 +39,8 @@ struct Bad<T> {
3839

3940
unsafe fn i<T>(x: Bad<T>) {
4041
let _: i32 = transmute(x);
41-
//~^ ERROR transmute called with types of different sizes
42+
//~^ ERROR transmutation from a type with an unspecified layout
43+
//~| ERROR transmute called with types of different sizes
4244
}
4345

4446
enum Worse<T> {
@@ -48,12 +50,14 @@ enum Worse<T> {
4850

4951
unsafe fn j<T>(x: Worse<T>) {
5052
let _: i32 = transmute(x);
51-
//~^ ERROR transmute called with types of different sizes
53+
//~^ ERROR transmutation from a type with an unspecified layout
54+
//~| ERROR transmute called with types of different sizes
5255
}
5356

5457
unsafe fn k<T>(x: Option<T>) {
5558
let _: i32 = transmute(x);
56-
//~^ ERROR transmute called with types of different sizes
59+
//~^ ERROR transmutation from a type with an unspecified layout
60+
//~| ERROR transmute called with types of different sizes
5761
}
5862

5963
fn main() {}

0 commit comments

Comments
 (0)