Skip to content

Commit 09c6c54

Browse files
author
Lukas Markeffsky
committed
Improve diagnostic for E0691
1 parent 083721a commit 09c6c54

File tree

3 files changed

+97
-20
lines changed

3 files changed

+97
-20
lines changed

compiler/rustc_typeck/src/check/check.rs

+39-12
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ use rustc_middle::hir::nested_filter;
2020
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
2121
use rustc_middle::ty::subst::GenericArgKind;
2222
use rustc_middle::ty::util::{Discr, IntTypeExt};
23-
use rustc_middle::ty::{self, ParamEnv, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
23+
use rustc_middle::ty::{
24+
self, ParamEnv, ToPredicate, Ty, TyCtxt, TyKind, TypeFoldable, TypeSuperFoldable,
25+
};
2426
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
2527
use rustc_span::symbol::sym;
2628
use rustc_span::{self, Span};
@@ -1327,28 +1329,53 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
13271329
let layout = tcx.layout_of(param_env.and(ty));
13281330
// We are currently checking the type this field came from, so it must be local
13291331
let span = tcx.hir().span_if_local(field.did).unwrap();
1330-
let zst = layout.map_or(false, |layout| layout.is_zst());
1331-
let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1);
1332-
(span, zst, align1)
1332+
let array_len = match ty.kind() {
1333+
TyKind::Array(_, len) => len.try_eval_usize(tcx, param_env),
1334+
_ => None,
1335+
};
1336+
let zst = array_len == Some(0) || layout.map_or(false, |layout| layout.is_zst());
1337+
let align = layout.ok().map(|layout| layout.align.abi.bytes());
1338+
(span, zst, align)
13331339
});
13341340

13351341
let non_zst_fields =
1336-
field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
1342+
field_infos.clone().filter_map(|(span, zst, _align)| if !zst { Some(span) } else { None });
13371343
let non_zst_count = non_zst_fields.clone().count();
13381344
if non_zst_count >= 2 {
13391345
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
13401346
}
1341-
for (span, zst, align1) in field_infos {
1342-
if zst && !align1 {
1343-
struct_span_err!(
1347+
for (span, zst, align) in field_infos {
1348+
if zst && align != Some(1) {
1349+
let mut err = struct_span_err!(
13441350
tcx.sess,
13451351
span,
13461352
E0691,
13471353
"zero-sized field in transparent {} has alignment larger than 1",
13481354
adt.descr(),
1349-
)
1350-
.span_label(span, "has alignment larger than 1")
1351-
.emit();
1355+
);
1356+
1357+
if align.is_none() {
1358+
err.span_label(span, "may have alignment larger than 1");
1359+
} else {
1360+
err.span_label(span, "has alignment larger than 1");
1361+
};
1362+
1363+
if let Some(item_list) =
1364+
tcx.get_attr(adt.did(), sym::repr).and_then(|attr| attr.meta_item_list())
1365+
{
1366+
for item in item_list {
1367+
if item.name_or_empty() == sym::transparent {
1368+
err.span_suggestion_verbose(
1369+
item.span(),
1370+
"Try using `#[repc(C)]` instead",
1371+
"C",
1372+
Applicability::MachineApplicable,
1373+
);
1374+
}
1375+
}
1376+
}
1377+
1378+
err.emit();
13521379
}
13531380
}
13541381
}
@@ -1475,7 +1502,7 @@ fn format_discriminant_overflow<'tcx>(
14751502
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
14761503
&& dis.val != *lit_value
14771504
{
1478-
return format!("`{dis}` (overflowed from `{lit_value}`)");
1505+
return format!("`{dis}` (overflowed from `{lit_value}`)");
14791506
}
14801507
}
14811508

src/test/ui/repr/repr-transparent.rs

+8
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ struct ZstAlign32<T>(PhantomData<T>);
4141
#[repr(transparent)]
4242
struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR alignment larger than 1
4343

44+
#[repr(transparent)]
45+
struct GenericAlignZeroArray<T>([T; 0], u32); //~ ERROR alignment larger than 1
46+
4447
#[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum
4548
enum Void {} //~ ERROR transparent enum needs exactly one variant, but has 0
4649

@@ -76,6 +79,11 @@ enum GenericAlignEnum<T> {
7679
Foo { bar: ZstAlign32<T>, baz: u32 } //~ ERROR alignment larger than 1
7780
}
7881

82+
#[repr(transparent)]
83+
enum GenericAlignEnumZeroArray<T> {
84+
Foo { bar: [T; 0], baz: u32 } //~ ERROR alignment larger than 1
85+
}
86+
7987
#[repr(transparent)]
8088
union UnitUnion {
8189
u: (),

src/test/ui/repr/repr-transparent.stderr

+50-8
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,50 @@ error[E0691]: zero-sized field in transparent struct has alignment larger than 1
2323
|
2424
LL | struct NontrivialAlignZst(u32, [u16; 0]);
2525
| ^^^^^^^^ has alignment larger than 1
26+
|
27+
help: Try using `#[repc(C)]` instead
28+
|
29+
LL | #[repr(C)]
30+
| ~
2631

2732
error[E0691]: zero-sized field in transparent struct has alignment larger than 1
2833
--> $DIR/repr-transparent.rs:42:24
2934
|
3035
LL | struct GenericAlign<T>(ZstAlign32<T>, u32);
3136
| ^^^^^^^^^^^^^ has alignment larger than 1
37+
|
38+
help: Try using `#[repc(C)]` instead
39+
|
40+
LL | #[repr(C)]
41+
| ~
42+
43+
error[E0691]: zero-sized field in transparent struct has alignment larger than 1
44+
--> $DIR/repr-transparent.rs:45:33
45+
|
46+
LL | struct GenericAlignZeroArray<T>([T; 0], u32);
47+
| ^^^^^^ may have alignment larger than 1
48+
|
49+
help: Try using `#[repc(C)]` instead
50+
|
51+
LL | #[repr(C)]
52+
| ~
3253

3354
error[E0084]: unsupported representation for zero-variant enum
34-
--> $DIR/repr-transparent.rs:44:1
55+
--> $DIR/repr-transparent.rs:47:1
3556
|
3657
LL | #[repr(transparent)]
3758
| ^^^^^^^^^^^^^^^^^^^^
3859
LL | enum Void {}
3960
| ------------ zero-variant enum
4061

4162
error[E0731]: transparent enum needs exactly one variant, but has 0
42-
--> $DIR/repr-transparent.rs:45:1
63+
--> $DIR/repr-transparent.rs:48:1
4364
|
4465
LL | enum Void {}
4566
| ^^^^^^^^^ needs exactly one variant, but has 0
4667

4768
error[E0690]: the variant of a transparent enum needs at most one non-zero-sized field, but has 2
48-
--> $DIR/repr-transparent.rs:58:1
69+
--> $DIR/repr-transparent.rs:61:1
4970
|
5071
LL | enum TooManyFieldsEnum {
5172
| ^^^^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
@@ -55,7 +76,7 @@ LL | Foo(u32, String),
5576
| this field is non-zero-sized
5677

5778
error[E0731]: transparent enum needs exactly one variant, but has 2
58-
--> $DIR/repr-transparent.rs:64:1
79+
--> $DIR/repr-transparent.rs:67:1
5980
|
6081
LL | enum MultipleVariants {
6182
| ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
@@ -65,19 +86,40 @@ LL | Bar,
6586
| --- too many variants in `MultipleVariants`
6687

6788
error[E0691]: zero-sized field in transparent enum has alignment larger than 1
68-
--> $DIR/repr-transparent.rs:71:14
89+
--> $DIR/repr-transparent.rs:74:14
6990
|
7091
LL | Foo(u32, [u16; 0]),
7192
| ^^^^^^^^ has alignment larger than 1
93+
|
94+
help: Try using `#[repc(C)]` instead
95+
|
96+
LL | #[repr(C)]
97+
| ~
7298

7399
error[E0691]: zero-sized field in transparent enum has alignment larger than 1
74-
--> $DIR/repr-transparent.rs:76:11
100+
--> $DIR/repr-transparent.rs:79:11
75101
|
76102
LL | Foo { bar: ZstAlign32<T>, baz: u32 }
77103
| ^^^^^^^^^^^^^^^^^^ has alignment larger than 1
104+
|
105+
help: Try using `#[repc(C)]` instead
106+
|
107+
LL | #[repr(C)]
108+
| ~
109+
110+
error[E0691]: zero-sized field in transparent enum has alignment larger than 1
111+
--> $DIR/repr-transparent.rs:84:11
112+
|
113+
LL | Foo { bar: [T; 0], baz: u32 }
114+
| ^^^^^^^^^^^ may have alignment larger than 1
115+
|
116+
help: Try using `#[repc(C)]` instead
117+
|
118+
LL | #[repr(C)]
119+
| ~
78120

79121
error[E0690]: transparent union needs at most one non-zero-sized field, but has 2
80-
--> $DIR/repr-transparent.rs:85:1
122+
--> $DIR/repr-transparent.rs:93:1
81123
|
82124
LL | union TooManyFields {
83125
| ^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
@@ -86,7 +128,7 @@ LL | u: u32,
86128
LL | s: i32
87129
| ------ this field is non-zero-sized
88130

89-
error: aborting due to 11 previous errors
131+
error: aborting due to 13 previous errors
90132

91133
Some errors have detailed explanations: E0084, E0690, E0691, E0731.
92134
For more information about an error, try `rustc --explain E0084`.

0 commit comments

Comments
 (0)