Reland "[codeview] Reference types in type parent scopes"

Summary:
Original description (https://reviews.llvm/org/D69924)
Without this change, when a nested tag type of any kind (enum, class,
struct, union) is used as a variable type, it is emitted without
emitting the parent type. In CodeView, parent types point to their inner
types, and inner types do not point back to their parents. We already
walk over all of the parent scopes to build the fully qualified name.
This change simply requests their type indices as we go along to enusre
they are all emitted.

Now, while walking over the parent scopes, add the types to
DeferredCompleteTypes, since they might already be in the process of
being emitted.

Fixes PR43905

Reviewers: rnk, amccarth

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D78249
This commit is contained in:
Amy Huang 2020-04-13 11:06:37 -07:00
parent 548d501082
commit 2b8c6acc39
4 changed files with 214 additions and 13 deletions

View File

@ -310,12 +310,19 @@ static StringRef getPrettyScopeName(const DIScope *Scope) {
return StringRef();
}
static const DISubprogram *getQualifiedNameComponents(
const DISubprogram *CodeViewDebug::collectParentScopeNames(
const DIScope *Scope, SmallVectorImpl<StringRef> &QualifiedNameComponents) {
const DISubprogram *ClosestSubprogram = nullptr;
while (Scope != nullptr) {
if (ClosestSubprogram == nullptr)
ClosestSubprogram = dyn_cast<DISubprogram>(Scope);
// If a type appears in a scope chain, make sure it gets emitted. The
// frontend will be responsible for deciding if this should be a forward
// declaration or a complete type.
if (const auto *Ty = dyn_cast<DICompositeType>(Scope))
DeferredCompleteTypes.push_back(Ty);
StringRef ScopeName = getPrettyScopeName(Scope);
if (!ScopeName.empty())
QualifiedNameComponents.push_back(ScopeName);
@ -324,7 +331,7 @@ static const DISubprogram *getQualifiedNameComponents(
return ClosestSubprogram;
}
static std::string getQualifiedName(ArrayRef<StringRef> QualifiedNameComponents,
static std::string formatNestedName(ArrayRef<StringRef> QualifiedNameComponents,
StringRef TypeName) {
std::string FullyQualifiedName;
for (StringRef QualifiedNameComponent :
@ -336,10 +343,16 @@ static std::string getQualifiedName(ArrayRef<StringRef> QualifiedNameComponents,
return FullyQualifiedName;
}
static std::string getFullyQualifiedName(const DIScope *Scope, StringRef Name) {
std::string CodeViewDebug::getFullyQualifiedName(const DIScope *Scope,
StringRef Name) {
SmallVector<StringRef, 5> QualifiedNameComponents;
getQualifiedNameComponents(Scope, QualifiedNameComponents);
return getQualifiedName(QualifiedNameComponents, Name);
collectParentScopeNames(Scope, QualifiedNameComponents);
return formatNestedName(QualifiedNameComponents, Name);
}
std::string CodeViewDebug::getFullyQualifiedName(const DIScope *Ty) {
const DIScope *Scope = Ty->getScope();
return getFullyQualifiedName(Scope, getPrettyScopeName(Ty));
}
struct CodeViewDebug::TypeLoweringScope {
@ -354,11 +367,6 @@ struct CodeViewDebug::TypeLoweringScope {
CodeViewDebug &CVD;
};
static std::string getFullyQualifiedName(const DIScope *Ty) {
const DIScope *Scope = Ty->getScope();
return getFullyQualifiedName(Scope, getPrettyScopeName(Ty));
}
TypeIndex CodeViewDebug::getScopeIndex(const DIScope *Scope) {
// No scope means global scope and that uses the zero index.
if (!Scope || isa<DIFile>(Scope))
@ -1477,12 +1485,12 @@ void CodeViewDebug::addToUDTs(const DIType *Ty) {
if (!shouldEmitUdt(Ty))
return;
SmallVector<StringRef, 5> QualifiedNameComponents;
SmallVector<StringRef, 5> ParentScopeNames;
const DISubprogram *ClosestSubprogram =
getQualifiedNameComponents(Ty->getScope(), QualifiedNameComponents);
collectParentScopeNames(Ty->getScope(), ParentScopeNames);
std::string FullyQualifiedName =
getQualifiedName(QualifiedNameComponents, getPrettyScopeName(Ty));
formatNestedName(ParentScopeNames, getPrettyScopeName(Ty));
if (ClosestSubprogram == nullptr) {
GlobalUDTs.emplace_back(std::move(FullyQualifiedName), Ty);

View File

@ -443,6 +443,15 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
codeview::TypeIndex TI,
const DIType *ClassTy = nullptr);
/// Collect the names of parent scopes, innermost to outermost. Return the
/// innermost subprogram scope if present. Ensure that parent type scopes are
/// inserted into the type table.
const DISubprogram *
collectParentScopeNames(const DIScope *Scope,
SmallVectorImpl<StringRef> &ParentScopeNames);
std::string getFullyQualifiedName(const DIScope *Scope, StringRef Name);
std::string getFullyQualifiedName(const DIScope *Scope);
unsigned getPointerSizeInBytes();
protected:

View File

@ -0,0 +1,133 @@
; RUN: llc < %s -filetype=obj -o %t.o
; RUN: llvm-pdbutil dump -types %t.o | FileCheck %s
; C++ source:
; // Note that MSVC doesn't emit anything about WrapTypedef or WrapTypedef::Inner!
; struct WrapTypedef {
; typedef int Inner;
; };
; struct WrapStruct {
; struct Inner { int x; };
; };
; struct WrapClass {
; class Inner { public: int x; };
; };
; struct WrapEnum {
; enum Inner { One, Two };
; };
; struct WrapUnion {
; union Inner { int x; float y; };
; };
; void useInnerTypes() {
; WrapTypedef::Inner v1;
; WrapStruct::Inner v2;
; WrapClass::Inner v3;
; WrapEnum::Inner v4;
; WrapUnion::Inner v5;
; }
; There should be two LF_STRUCTURE records for each wrapped type, forward decl
; and complete type. For every inner record type, there should be two. Enums
; don't get forward decls.
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapStruct`
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapStruct`
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapStruct::Inner`
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapStruct::Inner`
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapClass`
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapClass`
; CHECK-DAG: | LF_CLASS {{.*}} `WrapClass::Inner`
; CHECK-DAG: | LF_CLASS {{.*}} `WrapClass::Inner`
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapEnum`
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapEnum`
; CHECK-DAG: | LF_ENUM {{.*}} `WrapEnum::Inner`
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapUnion`
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapUnion`
; CHECK-DAG: | LF_UNION {{.*}} `WrapUnion::Inner`
; CHECK-DAG: | LF_UNION {{.*}} `WrapUnion::Inner`
; ModuleID = 't.cpp'
source_filename = "t.cpp"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc19.23.28106"
%"struct.WrapStruct::Inner" = type { i32 }
%"class.WrapClass::Inner" = type { i32 }
%"union.WrapUnion::Inner" = type { i32 }
; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @"?useInnerTypes@@YAXXZ"() #0 !dbg !15 {
entry:
%v1 = alloca i32, align 4
%v2 = alloca %"struct.WrapStruct::Inner", align 4
%v3 = alloca %"class.WrapClass::Inner", align 4
%v4 = alloca i32, align 4
%v5 = alloca %"union.WrapUnion::Inner", align 4
call void @llvm.dbg.declare(metadata i32* %v1, metadata !19, metadata !DIExpression()), !dbg !23
call void @llvm.dbg.declare(metadata %"struct.WrapStruct::Inner"* %v2, metadata !24, metadata !DIExpression()), !dbg !30
call void @llvm.dbg.declare(metadata %"class.WrapClass::Inner"* %v3, metadata !31, metadata !DIExpression()), !dbg !37
call void @llvm.dbg.declare(metadata i32* %v4, metadata !38, metadata !DIExpression()), !dbg !39
call void @llvm.dbg.declare(metadata %"union.WrapUnion::Inner"* %v5, metadata !40, metadata !DIExpression()), !dbg !48
ret void, !dbg !49
}
; Function Attrs: nounwind readnone speculatable willreturn
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone speculatable willreturn }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!10, !11, !12, !13}
!llvm.ident = !{!14}
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 10.0.0 (git@github.com:llvm/llvm-project.git a8ccb48f697d3fbe85c593248ff1053fdf522a6e)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
!1 = !DIFile(filename: "t.cpp", directory: "C:\\src\\llvm-project\\build", checksumkind: CSK_MD5, checksum: "4228f12f516cd3d6dd76462be09ec111")
!2 = !{!3, !3}
!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Inner", scope: !4, file: !1, line: 11, baseType: !6, size: 32, elements: !7, identifier: ".?AW4Inner@WrapEnum@@")
!4 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "WrapEnum", file: !1, line: 10, size: 8, flags: DIFlagTypePassByValue, elements: !5, identifier: ".?AUWrapEnum@@")
!5 = !{!3}
!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!7 = !{!8, !9}
!8 = !DIEnumerator(name: "One", value: 0)
!9 = !DIEnumerator(name: "Two", value: 1)
!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 10.0.0 (git@github.com:llvm/llvm-project.git a8ccb48f697d3fbe85c593248ff1053fdf522a6e)"}
!15 = distinct !DISubprogram(name: "useInnerTypes", linkageName: "?useInnerTypes@@YAXXZ", scope: !1, file: !1, line: 16, type: !16, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !18)
!16 = !DISubroutineType(types: !17)
!17 = !{null}
!18 = !{}
!19 = !DILocalVariable(name: "v1", scope: !15, file: !1, line: 17, type: !20)
!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "Inner", scope: !21, file: !1, line: 2, baseType: !6)
!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "WrapTypedef", file: !1, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !22, identifier: ".?AUWrapTypedef@@")
!22 = !{!20}
!23 = !DILocation(line: 17, scope: !15)
!24 = !DILocalVariable(name: "v2", scope: !15, file: !1, line: 18, type: !25)
!25 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Inner", scope: !26, file: !1, line: 5, size: 32, flags: DIFlagTypePassByValue, elements: !28, identifier: ".?AUInner@WrapStruct@@")
!26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "WrapStruct", file: !1, line: 4, size: 8, flags: DIFlagTypePassByValue, elements: !27, identifier: ".?AUWrapStruct@@")
!27 = !{!25}
!28 = !{!29}
!29 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !25, file: !1, line: 5, baseType: !6, size: 32)
!30 = !DILocation(line: 18, scope: !15)
!31 = !DILocalVariable(name: "v3", scope: !15, file: !1, line: 19, type: !32)
!32 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Inner", scope: !33, file: !1, line: 8, size: 32, flags: DIFlagTypePassByValue, elements: !35, identifier: ".?AVInner@WrapClass@@")
!33 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "WrapClass", file: !1, line: 7, size: 8, flags: DIFlagTypePassByValue, elements: !34, identifier: ".?AUWrapClass@@")
!34 = !{!32}
!35 = !{!36}
!36 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !32, file: !1, line: 8, baseType: !6, size: 32, flags: DIFlagPublic)
!37 = !DILocation(line: 19, scope: !15)
!38 = !DILocalVariable(name: "v4", scope: !15, file: !1, line: 20, type: !3)
!39 = !DILocation(line: 20, scope: !15)
!40 = !DILocalVariable(name: "v5", scope: !15, file: !1, line: 21, type: !41)
!41 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "Inner", scope: !42, file: !1, line: 14, size: 32, flags: DIFlagTypePassByValue, elements: !44, identifier: ".?ATInner@WrapUnion@@")
!42 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "WrapUnion", file: !1, line: 13, size: 8, flags: DIFlagTypePassByValue, elements: !43, identifier: ".?AUWrapUnion@@")
!43 = !{!41}
!44 = !{!45, !46}
!45 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !41, file: !1, line: 14, baseType: !6, size: 32)
!46 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !41, file: !1, line: 14, baseType: !47, size: 32)
!47 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
!48 = !DILocation(line: 21, scope: !15)
!49 = !DILocation(line: 22, scope: !15)

View File

@ -0,0 +1,51 @@
; RUN: llc < %s -filetype=obj -o %t.o
; RUN: llvm-pdbutil dump -types %t.o | FileCheck %s
; C source to regenerate:
; $ clang -g -gcodeview -S -emit-llvm t.c
; $ cat t.c
; struct {
; union {
; struct {};
; };
; } S;
; Test that this compiles without errors.
; CHECK: LF_STRUCTURE{{.*}}<unnamed-tag>::<unnamed-tag>::<unnamed-tag>
; CHECK: LF_UNION{{.*}}<unnamed-tag>::<unnamed-tag>
; CHECK: LF_STRUCTURE{{.*}}<unnamed-tag>
; ModuleID = 't.c'
source_filename = "t.c"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc19.24.28316"
%struct.anon = type { %union.anon }
%union.anon = type { %struct.anon.0 }
%struct.anon.0 = type { [4 x i8] }
@S = dso_local global %struct.anon zeroinitializer, align 1, !dbg !0
!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!13, !14, !15, !16}
!llvm.ident = !{!17}
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "S", scope: !2, file: !3, line: 5, type: !6, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 60d09bec7f8699728d38057430422d955d32a904)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None)
!3 = !DIFile(filename: "t.c", directory: "C:\\src\\llvm-build", checksumkind: CSK_MD5, checksum: "c31fe86676dd2fb56f847f926c0f2c71")
!4 = !{}
!5 = !{!0}
!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 1, size: 32, elements: !7)
!7 = !{!8, !12}
!8 = distinct !DICompositeType(tag: DW_TAG_union_type, scope: !6, file: !3, line: 2, size: 32, elements: !9)
!9 = !{!10, !11}
!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !8, file: !3, line: 3, size: 32, elements: !4)
!11 = !DIDerivedType(tag: DW_TAG_member, scope: !8, file: !3, line: 3, baseType: !10, size: 32)
!12 = !DIDerivedType(tag: DW_TAG_member, scope: !6, file: !3, line: 2, baseType: !8, size: 32)
!13 = !{i32 2, !"CodeView", i32 1}
!14 = !{i32 2, !"Debug Info Version", i32 3}
!15 = !{i32 1, !"wchar_size", i32 2}
!16 = !{i32 7, !"PIC Level", i32 2}
!17 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 60d09bec7f8699728d38057430422d955d32a904)"}