Skip to content

Detail transitive containment in E0588 diagnostic #67956

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 62 additions & 25 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath};
use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath};
use rustc_index::vec::Idx;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{original_sp, DUMMY_SP};
Expand Down Expand Up @@ -2295,44 +2295,81 @@ fn check_packed(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
"type has conflicting packed and align representation hints"
)
.emit();
} else if check_packed_inner(tcx, def_id, &mut Vec::new()) {
struct_span_err!(
tcx.sess,
sp,
E0588,
"packed type cannot transitively contain a `[repr(align)]` type"
)
.emit();
} else {
if let Some(def_spans) = check_packed_inner(tcx, def_id, &mut vec![]) {
let mut err = struct_span_err!(
tcx.sess,
sp,
E0588,
"packed type cannot transitively contain a `#[repr(align)]` type"
);

let hir = tcx.hir();
if let Some(hir_id) = hir.as_local_hir_id(def_spans[0].0) {
if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
err.span_note(
tcx.def_span(def_spans[0].0),
&format!("`{}` has a `#[repr(align)]` attribute", ident),
);
}
}

if def_spans.len() > 2 {
let mut first = true;
for (adt_def, span) in def_spans.iter().skip(1).rev() {
if let Some(hir_id) = hir.as_local_hir_id(*adt_def) {
if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
err.span_note(
*span,
&if first {
format!(
"`{}` contains a field of type `{}`",
tcx.type_of(def_id),
ident
)
} else {
format!("...which contains a field of type `{}`", ident)
},
);
first = false;
}
}
}
}

err.emit();
}
}
}
}

fn check_packed_inner(tcx: TyCtxt<'_>, def_id: DefId, stack: &mut Vec<DefId>) -> bool {
let t = tcx.type_of(def_id);
if stack.contains(&def_id) {
debug!("check_packed_inner: {:?} is recursive", t);
return false;
}
if let ty::Adt(def, substs) = t.kind {
fn check_packed_inner(
tcx: TyCtxt<'_>,
def_id: DefId,
stack: &mut Vec<DefId>,
) -> Option<Vec<(DefId, Span)>> {
if let ty::Adt(def, substs) = tcx.type_of(def_id).kind {
if def.is_struct() || def.is_union() {
if tcx.adt_def(def.did).repr.align.is_some() {
return true;
if def.repr.align.is_some() {
return Some(vec![(def.did, DUMMY_SP)]);
}
// push struct def_id before checking fields

stack.push(def_id);
for field in &def.non_enum_variant().fields {
let f = field.ty(tcx, substs);
if let ty::Adt(def, _) = f.kind {
if check_packed_inner(tcx, def.did, stack) {
return true;
if let ty::Adt(def, _) = field.ty(tcx, substs).kind {
if !stack.contains(&def.did) {
if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) {
defs.push((def.did, field.ident.span));
return Some(defs);
}
}
}
}
// only need to pop if not early out
stack.pop();
}
}
false

None
}

/// Emit an error when encountering more or less than one variant in a transparent enum.
Expand Down
16 changes: 8 additions & 8 deletions src/test/ui/repr/repr-packed-contains-align.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,34 @@ union UB {
}

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

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

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

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

#[repr(packed)]
union UC { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
union UC { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
a: UA
}

#[repr(packed)]
union UD { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
union UD { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
n: UB
}

#[repr(packed)]
union UE { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
union UE { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
a: SA
}

#[repr(packed)]
union UF { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
union UF { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
n: SB
}

Expand Down
112 changes: 104 additions & 8 deletions src/test/ui/repr/repr-packed-contains-align.stderr
Original file line number Diff line number Diff line change
@@ -1,58 +1,154 @@
error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
--> $DIR/repr-packed-contains-align.rs:19:1
|
LL | struct SC(SA);
| ^^^^^^^^^^^^^^
|
note: `SA` has a `#[repr(align)]` attribute
--> $DIR/repr-packed-contains-align.rs:5:1
|
LL | struct SA(i32);
| ^^^^^^^^^^^^^^^

error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
--> $DIR/repr-packed-contains-align.rs:22:1
|
LL | struct SD(SB);
| ^^^^^^^^^^^^^^
|
note: `SA` has a `#[repr(align)]` attribute
--> $DIR/repr-packed-contains-align.rs:5:1
|
LL | struct SA(i32);
| ^^^^^^^^^^^^^^^
note: `SD` contains a field of type `SB`
--> $DIR/repr-packed-contains-align.rs:22:11
|
LL | struct SD(SB);
| ^^
note: ...which contains a field of type `SA`
--> $DIR/repr-packed-contains-align.rs:7:11
|
LL | struct SB(SA);
| ^^

error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
--> $DIR/repr-packed-contains-align.rs:25:1
|
LL | struct SE(UA);
| ^^^^^^^^^^^^^^
|
note: `UA` has a `#[repr(align)]` attribute
--> $DIR/repr-packed-contains-align.rs:10:1
|
LL | / union UA {
LL | | i: i32
LL | | }
| |_^

error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
--> $DIR/repr-packed-contains-align.rs:28:1
|
LL | struct SF(UB);
| ^^^^^^^^^^^^^^
|
note: `UA` has a `#[repr(align)]` attribute
--> $DIR/repr-packed-contains-align.rs:10:1
|
LL | / union UA {
LL | | i: i32
LL | | }
| |_^
note: `SF` contains a field of type `UB`
--> $DIR/repr-packed-contains-align.rs:28:11
|
LL | struct SF(UB);
| ^^
note: ...which contains a field of type `UA`
--> $DIR/repr-packed-contains-align.rs:15:5
|
LL | a: UA
| ^

error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
--> $DIR/repr-packed-contains-align.rs:31:1
|
LL | / union UC {
LL | | a: UA
LL | | }
| |_^
|
note: `UA` has a `#[repr(align)]` attribute
--> $DIR/repr-packed-contains-align.rs:10:1
|
LL | / union UA {
LL | | i: i32
LL | | }
| |_^

error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
--> $DIR/repr-packed-contains-align.rs:36:1
|
LL | / union UD {
LL | | n: UB
LL | | }
| |_^
|
note: `UA` has a `#[repr(align)]` attribute
--> $DIR/repr-packed-contains-align.rs:10:1
|
LL | / union UA {
LL | | i: i32
LL | | }
| |_^
note: `UD` contains a field of type `UB`
--> $DIR/repr-packed-contains-align.rs:37:5
|
LL | n: UB
| ^
note: ...which contains a field of type `UA`
--> $DIR/repr-packed-contains-align.rs:15:5
|
LL | a: UA
| ^

error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
--> $DIR/repr-packed-contains-align.rs:41:1
|
LL | / union UE {
LL | | a: SA
LL | | }
| |_^
|
note: `SA` has a `#[repr(align)]` attribute
--> $DIR/repr-packed-contains-align.rs:5:1
|
LL | struct SA(i32);
| ^^^^^^^^^^^^^^^

error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
--> $DIR/repr-packed-contains-align.rs:46:1
|
LL | / union UF {
LL | | n: SB
LL | | }
| |_^
|
note: `SA` has a `#[repr(align)]` attribute
--> $DIR/repr-packed-contains-align.rs:5:1
|
LL | struct SA(i32);
| ^^^^^^^^^^^^^^^
note: `UF` contains a field of type `SB`
--> $DIR/repr-packed-contains-align.rs:47:5
|
LL | n: SB
| ^
note: ...which contains a field of type `SA`
--> $DIR/repr-packed-contains-align.rs:7:11
|
LL | struct SB(SA);
| ^^

error: aborting due to 8 previous errors

Expand Down