From 3ab95ceb12b60c1564d037e8d8d6e2406fad44b3 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 7 Jan 2020 00:00:16 +0000 Subject: [PATCH] Detail transitive containment in E0588 diagnostic --- src/librustc_typeck/check/mod.rs | 87 ++++++++++---- .../ui/repr/repr-packed-contains-align.rs | 16 +-- .../ui/repr/repr-packed-contains-align.stderr | 112 ++++++++++++++++-- 3 files changed, 174 insertions(+), 41 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index eacd94f7da7f7..6b9b28a0fa622 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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}; @@ -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) -> 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, +) -> Option> { + 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. diff --git a/src/test/ui/repr/repr-packed-contains-align.rs b/src/test/ui/repr/repr-packed-contains-align.rs index a3610345173a7..67d87eb5cd520 100644 --- a/src/test/ui/repr/repr-packed-contains-align.rs +++ b/src/test/ui/repr/repr-packed-contains-align.rs @@ -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 } diff --git a/src/test/ui/repr/repr-packed-contains-align.stderr b/src/test/ui/repr/repr-packed-contains-align.stderr index df001d6b5f2a4..32f9bb8bf33d9 100644 --- a/src/test/ui/repr/repr-packed-contains-align.stderr +++ b/src/test/ui/repr/repr-packed-contains-align.stderr @@ -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