Skip to content

Commit 3ab95ce

Browse files
committed
Detail transitive containment in E0588 diagnostic
1 parent ef92009 commit 3ab95ce

File tree

3 files changed

+174
-41
lines changed

3 files changed

+174
-41
lines changed

src/librustc_typeck/check/mod.rs

+62-25
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ use rustc_hir as hir;
118118
use rustc_hir::def::{CtorOf, DefKind, Res};
119119
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LOCAL_CRATE};
120120
use rustc_hir::itemlikevisit::ItemLikeVisitor;
121-
use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath};
121+
use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath};
122122
use rustc_index::vec::Idx;
123123
use rustc_span::hygiene::DesugaringKind;
124124
use rustc_span::source_map::{original_sp, DUMMY_SP};
@@ -2295,44 +2295,81 @@ fn check_packed(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
22952295
"type has conflicting packed and align representation hints"
22962296
)
22972297
.emit();
2298-
} else if check_packed_inner(tcx, def_id, &mut Vec::new()) {
2299-
struct_span_err!(
2300-
tcx.sess,
2301-
sp,
2302-
E0588,
2303-
"packed type cannot transitively contain a `[repr(align)]` type"
2304-
)
2305-
.emit();
2298+
} else {
2299+
if let Some(def_spans) = check_packed_inner(tcx, def_id, &mut vec![]) {
2300+
let mut err = struct_span_err!(
2301+
tcx.sess,
2302+
sp,
2303+
E0588,
2304+
"packed type cannot transitively contain a `#[repr(align)]` type"
2305+
);
2306+
2307+
let hir = tcx.hir();
2308+
if let Some(hir_id) = hir.as_local_hir_id(def_spans[0].0) {
2309+
if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
2310+
err.span_note(
2311+
tcx.def_span(def_spans[0].0),
2312+
&format!("`{}` has a `#[repr(align)]` attribute", ident),
2313+
);
2314+
}
2315+
}
2316+
2317+
if def_spans.len() > 2 {
2318+
let mut first = true;
2319+
for (adt_def, span) in def_spans.iter().skip(1).rev() {
2320+
if let Some(hir_id) = hir.as_local_hir_id(*adt_def) {
2321+
if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
2322+
err.span_note(
2323+
*span,
2324+
&if first {
2325+
format!(
2326+
"`{}` contains a field of type `{}`",
2327+
tcx.type_of(def_id),
2328+
ident
2329+
)
2330+
} else {
2331+
format!("...which contains a field of type `{}`", ident)
2332+
},
2333+
);
2334+
first = false;
2335+
}
2336+
}
2337+
}
2338+
}
2339+
2340+
err.emit();
2341+
}
23062342
}
23072343
}
23082344
}
23092345

2310-
fn check_packed_inner(tcx: TyCtxt<'_>, def_id: DefId, stack: &mut Vec<DefId>) -> bool {
2311-
let t = tcx.type_of(def_id);
2312-
if stack.contains(&def_id) {
2313-
debug!("check_packed_inner: {:?} is recursive", t);
2314-
return false;
2315-
}
2316-
if let ty::Adt(def, substs) = t.kind {
2346+
fn check_packed_inner(
2347+
tcx: TyCtxt<'_>,
2348+
def_id: DefId,
2349+
stack: &mut Vec<DefId>,
2350+
) -> Option<Vec<(DefId, Span)>> {
2351+
if let ty::Adt(def, substs) = tcx.type_of(def_id).kind {
23172352
if def.is_struct() || def.is_union() {
2318-
if tcx.adt_def(def.did).repr.align.is_some() {
2319-
return true;
2353+
if def.repr.align.is_some() {
2354+
return Some(vec![(def.did, DUMMY_SP)]);
23202355
}
2321-
// push struct def_id before checking fields
2356+
23222357
stack.push(def_id);
23232358
for field in &def.non_enum_variant().fields {
2324-
let f = field.ty(tcx, substs);
2325-
if let ty::Adt(def, _) = f.kind {
2326-
if check_packed_inner(tcx, def.did, stack) {
2327-
return true;
2359+
if let ty::Adt(def, _) = field.ty(tcx, substs).kind {
2360+
if !stack.contains(&def.did) {
2361+
if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) {
2362+
defs.push((def.did, field.ident.span));
2363+
return Some(defs);
2364+
}
23282365
}
23292366
}
23302367
}
2331-
// only need to pop if not early out
23322368
stack.pop();
23332369
}
23342370
}
2335-
false
2371+
2372+
None
23362373
}
23372374

23382375
/// Emit an error when encountering more or less than one variant in a transparent enum.

src/test/ui/repr/repr-packed-contains-align.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -16,34 +16,34 @@ union UB {
1616
}
1717

1818
#[repr(packed)]
19-
struct SC(SA); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
19+
struct SC(SA); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
2020

2121
#[repr(packed)]
22-
struct SD(SB); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
22+
struct SD(SB); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
2323

2424
#[repr(packed)]
25-
struct SE(UA); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
25+
struct SE(UA); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
2626

2727
#[repr(packed)]
28-
struct SF(UB); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
28+
struct SF(UB); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
2929

3030
#[repr(packed)]
31-
union UC { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
31+
union UC { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
3232
a: UA
3333
}
3434

3535
#[repr(packed)]
36-
union UD { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
36+
union UD { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
3737
n: UB
3838
}
3939

4040
#[repr(packed)]
41-
union UE { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
41+
union UE { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
4242
a: SA
4343
}
4444

4545
#[repr(packed)]
46-
union UF { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
46+
union UF { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
4747
n: SB
4848
}
4949

src/test/ui/repr/repr-packed-contains-align.stderr

+104-8
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,154 @@
1-
error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
1+
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
22
--> $DIR/repr-packed-contains-align.rs:19:1
33
|
44
LL | struct SC(SA);
55
| ^^^^^^^^^^^^^^
6+
|
7+
note: `SA` has a `#[repr(align)]` attribute
8+
--> $DIR/repr-packed-contains-align.rs:5:1
9+
|
10+
LL | struct SA(i32);
11+
| ^^^^^^^^^^^^^^^
612

7-
error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
13+
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
814
--> $DIR/repr-packed-contains-align.rs:22:1
915
|
1016
LL | struct SD(SB);
1117
| ^^^^^^^^^^^^^^
18+
|
19+
note: `SA` has a `#[repr(align)]` attribute
20+
--> $DIR/repr-packed-contains-align.rs:5:1
21+
|
22+
LL | struct SA(i32);
23+
| ^^^^^^^^^^^^^^^
24+
note: `SD` contains a field of type `SB`
25+
--> $DIR/repr-packed-contains-align.rs:22:11
26+
|
27+
LL | struct SD(SB);
28+
| ^^
29+
note: ...which contains a field of type `SA`
30+
--> $DIR/repr-packed-contains-align.rs:7:11
31+
|
32+
LL | struct SB(SA);
33+
| ^^
1234

13-
error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
35+
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
1436
--> $DIR/repr-packed-contains-align.rs:25:1
1537
|
1638
LL | struct SE(UA);
1739
| ^^^^^^^^^^^^^^
40+
|
41+
note: `UA` has a `#[repr(align)]` attribute
42+
--> $DIR/repr-packed-contains-align.rs:10:1
43+
|
44+
LL | / union UA {
45+
LL | | i: i32
46+
LL | | }
47+
| |_^
1848

19-
error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
49+
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
2050
--> $DIR/repr-packed-contains-align.rs:28:1
2151
|
2252
LL | struct SF(UB);
2353
| ^^^^^^^^^^^^^^
54+
|
55+
note: `UA` has a `#[repr(align)]` attribute
56+
--> $DIR/repr-packed-contains-align.rs:10:1
57+
|
58+
LL | / union UA {
59+
LL | | i: i32
60+
LL | | }
61+
| |_^
62+
note: `SF` contains a field of type `UB`
63+
--> $DIR/repr-packed-contains-align.rs:28:11
64+
|
65+
LL | struct SF(UB);
66+
| ^^
67+
note: ...which contains a field of type `UA`
68+
--> $DIR/repr-packed-contains-align.rs:15:5
69+
|
70+
LL | a: UA
71+
| ^
2472

25-
error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
73+
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
2674
--> $DIR/repr-packed-contains-align.rs:31:1
2775
|
2876
LL | / union UC {
2977
LL | | a: UA
78+
LL | | }
79+
| |_^
80+
|
81+
note: `UA` has a `#[repr(align)]` attribute
82+
--> $DIR/repr-packed-contains-align.rs:10:1
83+
|
84+
LL | / union UA {
85+
LL | | i: i32
3086
LL | | }
3187
| |_^
3288

33-
error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
89+
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
3490
--> $DIR/repr-packed-contains-align.rs:36:1
3591
|
3692
LL | / union UD {
3793
LL | | n: UB
3894
LL | | }
3995
| |_^
96+
|
97+
note: `UA` has a `#[repr(align)]` attribute
98+
--> $DIR/repr-packed-contains-align.rs:10:1
99+
|
100+
LL | / union UA {
101+
LL | | i: i32
102+
LL | | }
103+
| |_^
104+
note: `UD` contains a field of type `UB`
105+
--> $DIR/repr-packed-contains-align.rs:37:5
106+
|
107+
LL | n: UB
108+
| ^
109+
note: ...which contains a field of type `UA`
110+
--> $DIR/repr-packed-contains-align.rs:15:5
111+
|
112+
LL | a: UA
113+
| ^
40114

41-
error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
115+
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
42116
--> $DIR/repr-packed-contains-align.rs:41:1
43117
|
44118
LL | / union UE {
45119
LL | | a: SA
46120
LL | | }
47121
| |_^
122+
|
123+
note: `SA` has a `#[repr(align)]` attribute
124+
--> $DIR/repr-packed-contains-align.rs:5:1
125+
|
126+
LL | struct SA(i32);
127+
| ^^^^^^^^^^^^^^^
48128

49-
error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
129+
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
50130
--> $DIR/repr-packed-contains-align.rs:46:1
51131
|
52132
LL | / union UF {
53133
LL | | n: SB
54134
LL | | }
55135
| |_^
136+
|
137+
note: `SA` has a `#[repr(align)]` attribute
138+
--> $DIR/repr-packed-contains-align.rs:5:1
139+
|
140+
LL | struct SA(i32);
141+
| ^^^^^^^^^^^^^^^
142+
note: `UF` contains a field of type `SB`
143+
--> $DIR/repr-packed-contains-align.rs:47:5
144+
|
145+
LL | n: SB
146+
| ^
147+
note: ...which contains a field of type `SA`
148+
--> $DIR/repr-packed-contains-align.rs:7:11
149+
|
150+
LL | struct SB(SA);
151+
| ^^
56152

57153
error: aborting due to 8 previous errors
58154

0 commit comments

Comments
 (0)