Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1439,15 +1439,14 @@ } } - while (true) { - if (!T || T->isForwardDecl()) - return false; + // Look through nested typedefs. + while (T->getTag() == dwarf::DW_TAG_typedef) + T = cast(T)->getBaseType().resolve(); + + // Don't emit a UDT if we only have a forward declaration. + if (T && T->isForwardDecl()) + return false; - const DIDerivedType *DT = dyn_cast(T); - if (!DT) - return true; - T = DT->getBaseType().resolve(); - } return true; } Index: llvm/test/DebugInfo/COFF/udts-fwd.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/COFF/udts-fwd.ll @@ -0,0 +1,49 @@ +; RUN: llc -filetype=obj %s -o %t.obj +; RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s + +; Foo is forward declared here. Check that we emit the typedef for the pointer, +; but not for the incomplete type. We adopted this behavior to make +; /debug:fastlink more efficient, but it's not clear if it's still the right +; behavior. This test just encodes it. + +; C++ source: +; struct Foo; +; typedef Foo TypedefFwd; +; typedef TypedefFwd *TypedefFwdPtr; +; TypedefFwdPtr global_ptr; + +; CHECK: Symbols +; CHECK-NEXT: ============================================================ +; CHECK-NOT: S_UDT {{.*}} `TypedefFwd` +; CHECK: S_UDT [size = {{.*}}] `TypedefFwdPtr` +; CHECK-NOT: S_UDT {{.*}} `TypedefFwd` + + +; ModuleID = 't.cpp' +source_filename = "t.cpp" +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.14.26433" + +%struct.Foo = type opaque + +@"?global_ptr@@3PEAUFoo@@EA" = dso_local global %struct.Foo* null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!10, !11, !12, !13} +!llvm.ident = !{!14} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "global_ptr", linkageName: "?global_ptr@@3PEAUFoo@@EA", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 8.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.cpp", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "eda0a32edcbd7e1d7b0220b9ef0192c7") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "TypedefFwdPtr", file: !3, line: 3, baseType: !7) +!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64) +!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "TypedefFwd", file: !3, line: 2, baseType: !9) +!9 = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !3, line: 1, flags: DIFlagFwdDecl, identifier: ".?AUFoo@@") +!10 = !{i32 2, !"CodeView", i32 1} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 2} +!13 = !{i32 7, !"PIC Level", i32 2} +!14 = !{!"clang version 8.0.0 "}