--- /dev/null
+struct S {
+ int I;
+
+ void incr() __attribute__((always_inline)) { I++; }
+ void incr(int Add) __attribute__((always_inline)) { I += Add; }
+
+ typedef int SInt;
+
+ struct Nested {
+ double D;
+
+ template<typename T> void init(T Val) { D = double(Val); }
+ };
+
+ Nested D;
+
+public:
+ int foo() { return I; }
+};
+
+typedef S AliasForS;
+
+namespace N {
+class C {
+ AliasForS S;
+};
+}
+
+namespace N {
+namespace N {
+class C {
+ int S;
+};
+}
+}
+
+namespace {
+ class AnonC {
+ };
+}
+
+union U {
+ class C {} C;
+ struct S {} S;
+};
+
+inline int func() {
+ struct CInsideFunc { int i; };
+ auto functor = []() { CInsideFunc dummy; return dummy.i; };
+ return functor();
+}
--- /dev/null
+#include "odr-types.h"
+
+int foo() {
+ AliasForS s;
+ N::C nc;
+ N::N::C nnc;
+ AnonC ac;
+ U u;
+
+ return func();
+}
--- /dev/null
+; Generated from odr1.cpp and odr-types.h by running:
+; clang -emit-llvm -g -S -std=c++11 odr1.cpp
+; ModuleID = 'odr1.cpp'
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+%struct.S = type { i32, %"struct.S::Nested" }
+%"struct.S::Nested" = type { double }
+%"class.N::C" = type { %struct.S }
+%"class.N::N::C" = type { i32 }
+%"class.(anonymous namespace)::AnonC" = type { i8 }
+%union.U = type { %"class.U::C" }
+%"class.U::C" = type { i8 }
+%class.anon = type { i8 }
+%struct.CInsideFunc = type { i32 }
+
+; Function Attrs: ssp uwtable
+define i32 @_Z3foov() #0 {
+entry:
+ %s = alloca %struct.S, align 8
+ %nc = alloca %"class.N::C", align 8
+ %nnc = alloca %"class.N::N::C", align 4
+ %ac = alloca %"class.(anonymous namespace)::AnonC", align 1
+ %u = alloca %union.U, align 1
+ call void @llvm.dbg.declare(metadata %struct.S* %s, metadata !59, metadata !60), !dbg !61
+ call void @llvm.dbg.declare(metadata %"class.N::C"* %nc, metadata !62, metadata !60), !dbg !63
+ call void @llvm.dbg.declare(metadata %"class.N::N::C"* %nnc, metadata !64, metadata !60), !dbg !65
+ call void @llvm.dbg.declare(metadata %"class.(anonymous namespace)::AnonC"* %ac, metadata !66, metadata !60), !dbg !69
+ call void @llvm.dbg.declare(metadata %union.U* %u, metadata !70, metadata !60), !dbg !71
+ %call = call i32 @_Z4funcv(), !dbg !72
+ ret i32 %call, !dbg !73
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: inlinehint ssp uwtable
+define linkonce_odr i32 @_Z4funcv() #2 {
+entry:
+ %functor = alloca %class.anon, align 1
+ call void @llvm.dbg.declare(metadata %class.anon* %functor, metadata !74, metadata !60), !dbg !75
+ %call = call i32 @_ZZ4funcvENKUlvE_clEv(%class.anon* %functor), !dbg !76
+ ret i32 %call, !dbg !77
+}
+
+; Function Attrs: inlinehint nounwind ssp uwtable
+define linkonce_odr i32 @_ZZ4funcvENKUlvE_clEv(%class.anon* %this) #3 align 2 {
+entry:
+ %this.addr = alloca %class.anon*, align 8
+ %dummy = alloca %struct.CInsideFunc, align 4
+ store %class.anon* %this, %class.anon** %this.addr, align 8
+ call void @llvm.dbg.declare(metadata %class.anon** %this.addr, metadata !78, metadata !60), !dbg !80
+ %this1 = load %class.anon*, %class.anon** %this.addr
+ call void @llvm.dbg.declare(metadata %struct.CInsideFunc* %dummy, metadata !81, metadata !60), !dbg !82
+ %i = getelementptr inbounds %struct.CInsideFunc, %struct.CInsideFunc* %dummy, i32 0, i32 0, !dbg !83
+ %0 = load i32, i32* %i, align 4, !dbg !83
+ ret i32 %0, !dbg !84
+}
+
+attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { inlinehint ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { inlinehint nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!55, !56, !57}
+!llvm.ident = !{!58}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !52)
+!1 = !DIFile(filename: "odr1.cpp", directory: "/Inputs")
+!2 = !{}
+!3 = !{!4, !20, !24, !29, !33, !37, !38, !39, !49}
+!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
+!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
+!6 = !{!7, !9, !10, !14, !17}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32)
+!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64)
+!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null, !13}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !13, !8}
+!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!8, !13}
+!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE")
+!21 = !{!22}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
+!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float)
+!24 = !DICompositeType(tag: DW_TAG_class_type, name: "C", scope: !25, file: !5, line: 24, size: 128, align: 64, elements: !26, identifier: "_ZTSN1N1CE")
+!25 = !DINamespace(name: "N", scope: null, file: !5, line: 23)
+!26 = !{!27}
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "S", scope: !"_ZTSN1N1CE", file: !5, line: 25, baseType: !28, size: 128, align: 64)
+!28 = !DIDerivedType(tag: DW_TAG_typedef, name: "AliasForS", file: !5, line: 21, baseType: !"_ZTS1S")
+!29 = !DICompositeType(tag: DW_TAG_class_type, name: "C", scope: !30, file: !5, line: 31, size: 32, align: 32, elements: !31, identifier: "_ZTSN1N1N1CE")
+!30 = !DINamespace(name: "N", scope: !25, file: !5, line: 30)
+!31 = !{!32}
+!32 = !DIDerivedType(tag: DW_TAG_member, name: "S", scope: !"_ZTSN1N1N1CE", file: !5, line: 32, baseType: !8, size: 32, align: 32)
+!33 = !DICompositeType(tag: DW_TAG_union_type, name: "U", file: !5, line: 42, size: 8, align: 8, elements: !34, identifier: "_ZTS1U")
+!34 = !{!35, !36}
+!35 = !DIDerivedType(tag: DW_TAG_member, name: "C", scope: !"_ZTS1U", file: !5, line: 43, baseType: !"_ZTSN1U1CE", size: 8, align: 8)
+!36 = !DIDerivedType(tag: DW_TAG_member, name: "S", scope: !"_ZTS1U", file: !5, line: 44, baseType: !"_ZTSN1U1SE", size: 8, align: 8)
+!37 = !DICompositeType(tag: DW_TAG_class_type, name: "C", scope: !"_ZTS1U", file: !5, line: 43, size: 8, align: 8, elements: !2, identifier: "_ZTSN1U1CE")
+!38 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", scope: !"_ZTS1U", file: !5, line: 44, size: 8, align: 8, elements: !2, identifier: "_ZTSN1U1SE")
+!39 = !DICompositeType(tag: DW_TAG_class_type, scope: !40, file: !5, line: 49, size: 8, align: 8, elements: !43, identifier: "_ZTSZ4funcvEUlvE_")
+!40 = !DISubprogram(name: "func", linkageName: "_Z4funcv", scope: !5, file: !5, line: 47, type: !41, isLocal: false, isDefinition: true, scopeLine: 47, flags: DIFlagPrototyped, isOptimized: false, function: i32 ()* @_Z4funcv, variables: !2)
+!41 = !DISubroutineType(types: !42)
+!42 = !{!8}
+!43 = !{!44}
+!44 = !DISubprogram(name: "operator()", scope: !"_ZTSZ4funcvEUlvE_", file: !5, line: 49, type: !45, isLocal: false, isDefinition: false, scopeLine: 49, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: false)
+!45 = !DISubroutineType(types: !46)
+!46 = !{!8, !47}
+!47 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !48, size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!48 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !"_ZTSZ4funcvEUlvE_")
+!49 = !DICompositeType(tag: DW_TAG_structure_type, name: "CInsideFunc", scope: !40, file: !5, line: 48, size: 32, align: 32, elements: !50, identifier: "_ZTSZ4funcvE11CInsideFunc")
+!50 = !{!51}
+!51 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !"_ZTSZ4funcvE11CInsideFunc", file: !5, line: 48, baseType: !8, size: 32, align: 32)
+!52 = !{!53, !40, !54}
+!53 = !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 3, type: !41, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: i32 ()* @_Z3foov, variables: !2)
+!54 = !DISubprogram(name: "operator()", linkageName: "_ZZ4funcvENKUlvE_clEv", scope: !"_ZTSZ4funcvEUlvE_", file: !5, line: 49, type: !45, isLocal: false, isDefinition: true, scopeLine: 49, flags: DIFlagPrototyped, isOptimized: false, function: i32 (%class.anon*)* @_ZZ4funcvENKUlvE_clEv, declaration: !44, variables: !2)
+!55 = !{i32 2, !"Dwarf Version", i32 2}
+!56 = !{i32 2, !"Debug Info Version", i32 3}
+!57 = !{i32 1, !"PIC Level", i32 2}
+!58 = !{!"clang version 3.8.0 (trunk 242534)"}
+!59 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "s", scope: !53, file: !1, line: 4, type: !28)
+!60 = !DIExpression()
+!61 = !DILocation(line: 4, column: 12, scope: !53)
+!62 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "nc", scope: !53, file: !1, line: 5, type: !"_ZTSN1N1CE")
+!63 = !DILocation(line: 5, column: 7, scope: !53)
+!64 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "nnc", scope: !53, file: !1, line: 6, type: !"_ZTSN1N1N1CE")
+!65 = !DILocation(line: 6, column: 10, scope: !53)
+!66 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "ac", scope: !53, file: !1, line: 7, type: !67)
+!67 = !DICompositeType(tag: DW_TAG_class_type, name: "AnonC", scope: !68, file: !5, line: 38, size: 8, align: 8, elements: !2)
+!68 = !DINamespace(scope: null, file: !5, line: 37)
+!69 = !DILocation(line: 7, column: 8, scope: !53)
+!70 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "u", scope: !53, file: !1, line: 8, type: !"_ZTS1U")
+!71 = !DILocation(line: 8, column: 4, scope: !53)
+!72 = !DILocation(line: 10, column: 9, scope: !53)
+!73 = !DILocation(line: 10, column: 2, scope: !53)
+!74 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "functor", scope: !40, file: !5, line: 49, type: !"_ZTSZ4funcvEUlvE_")
+!75 = !DILocation(line: 49, column: 7, scope: !40)
+!76 = !DILocation(line: 50, column: 9, scope: !40)
+!77 = !DILocation(line: 50, column: 2, scope: !40)
+!78 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !54, type: !79, flags: DIFlagArtificial | DIFlagObjectPointer)
+!79 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !48, size: 64, align: 64)
+!80 = !DILocation(line: 0, scope: !54)
+!81 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "dummy", scope: !54, file: !5, line: 49, type: !"_ZTSZ4funcvE11CInsideFunc")
+!82 = !DILocation(line: 49, column: 36, scope: !54)
+!83 = !DILocation(line: 49, column: 56, scope: !54)
+!84 = !DILocation(line: 49, column: 43, scope: !54)
--- /dev/null
+#include "odr-types.h"
+
+int bar() {
+ S s;
+ s.incr();
+ return s.foo();
+}
--- /dev/null
+; Generated from odr2.cpp and odr-types.h by running:
+; clang -emit-llvm -g -S -std=c++11 odr2.cpp
+; ModuleID = 'odr2.cpp'
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+%struct.S = type { i32, %"struct.S::Nested" }
+%"struct.S::Nested" = type { double }
+
+; Function Attrs: ssp uwtable
+define i32 @_Z3barv() #0 {
+entry:
+ %this.addr.i = alloca %struct.S*, align 8
+ %s = alloca %struct.S, align 8
+ call void @llvm.dbg.declare(metadata %struct.S* %s, metadata !34, metadata !35), !dbg !36
+ store %struct.S* %s, %struct.S** %this.addr.i, align 8, !dbg !37
+ %this1.i = load %struct.S*, %struct.S** %this.addr.i, !dbg !37
+ %I.i = getelementptr inbounds %struct.S, %struct.S* %this1.i, i32 0, i32 0, !dbg !38
+ %0 = load i32, i32* %I.i, align 4, !dbg !40
+ %inc.i = add nsw i32 %0, 1, !dbg !40
+ store i32 %inc.i, i32* %I.i, align 4, !dbg !40
+ %call = call i32 @_ZN1S3fooEv(%struct.S* %s), !dbg !41
+ call void @llvm.dbg.declare(metadata %struct.S** %this.addr.i, metadata !42, metadata !35), !dbg !44
+ ret i32 %call, !dbg !45
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: nounwind ssp uwtable
+define linkonce_odr i32 @_ZN1S3fooEv(%struct.S* %this) #2 align 2 {
+entry:
+ %this.addr = alloca %struct.S*, align 8
+ store %struct.S* %this, %struct.S** %this.addr, align 8
+ call void @llvm.dbg.declare(metadata %struct.S** %this.addr, metadata !46, metadata !35), !dbg !47
+ %this1 = load %struct.S*, %struct.S** %this.addr
+ %I = getelementptr inbounds %struct.S, %struct.S* %this1, i32 0, i32 0, !dbg !48
+ %0 = load i32, i32* %I, align 4, !dbg !48
+ ret i32 %0, !dbg !49
+}
+
+attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!30, !31, !32}
+!llvm.ident = !{!33}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !24)
+!1 = !DIFile(filename: "odr2.cpp", directory: "/Inputs")
+!2 = !{}
+!3 = !{!4, !20}
+!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
+!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
+!6 = !{!7, !9, !10, !14, !17}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32)
+!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64)
+!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null, !13}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !13, !8}
+!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!8, !13}
+!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE")
+!21 = !{!22}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
+!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float)
+!24 = !{!25, !28, !29}
+!25 = !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 3, type: !26, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: i32 ()* @_Z3barv, variables: !2)
+!26 = !DISubroutineType(types: !27)
+!27 = !{!8}
+!28 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, declaration: !10, variables: !2)
+!29 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: true, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false, function: i32 (%struct.S*)* @_ZN1S3fooEv, declaration: !17, variables: !2)
+!30 = !{i32 2, !"Dwarf Version", i32 2}
+!31 = !{i32 2, !"Debug Info Version", i32 3}
+!32 = !{i32 1, !"PIC Level", i32 2}
+!33 = !{!"clang version 3.8.0 (trunk 242534)"}
+!34 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "s", scope: !25, file: !1, line: 4, type: !"_ZTS1S")
+!35 = !DIExpression()
+!36 = !DILocation(line: 4, column: 4, scope: !25)
+!37 = !DILocation(line: 5, column: 2, scope: !25)
+!38 = !DILocation(line: 4, column: 47, scope: !28, inlinedAt: !39)
+!39 = distinct !DILocation(line: 5, column: 2, scope: !25)
+!40 = !DILocation(line: 4, column: 48, scope: !28, inlinedAt: !39)
+!41 = !DILocation(line: 6, column: 9, scope: !25)
+!42 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !28, type: !43, flags: DIFlagArtificial | DIFlagObjectPointer)
+!43 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64)
+!44 = !DILocation(line: 0, scope: !28, inlinedAt: !39)
+!45 = !DILocation(line: 6, column: 2, scope: !25)
+!46 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !29, type: !43, flags: DIFlagArtificial | DIFlagObjectPointer)
+!47 = !DILocation(line: 0, scope: !29)
+!48 = !DILocation(line: 18, column: 21, scope: !29)
+!49 = !DILocation(line: 18, column: 14, scope: !29)
--- /dev/null
+#include "odr-types.h"
+
+int bar() {
+ S s;
+ s.incr(42);
+ return s.foo();
+}
--- /dev/null
+; Generated from odr3.cpp and odr-types.h by running:
+; clang -emit-llvm -g -S -std=c++11 odr3.cpp
+; ModuleID = 'odr3.cpp'
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+%struct.S = type { i32, %"struct.S::Nested" }
+%"struct.S::Nested" = type { double }
+
+; Function Attrs: ssp uwtable
+define i32 @_Z3barv() #0 {
+entry:
+ %this.addr.i = alloca %struct.S*, align 8
+ %Add.addr.i = alloca i32, align 4
+ %s = alloca %struct.S, align 8
+ call void @llvm.dbg.declare(metadata %struct.S* %s, metadata !34, metadata !35), !dbg !36
+ store %struct.S* %s, %struct.S** %this.addr.i, align 8, !dbg !37
+ store i32 42, i32* %Add.addr.i, align 4, !dbg !37
+ %this1.i = load %struct.S*, %struct.S** %this.addr.i, !dbg !37
+ %0 = load i32, i32* %Add.addr.i, align 4, !dbg !38
+ %I.i = getelementptr inbounds %struct.S, %struct.S* %this1.i, i32 0, i32 0, !dbg !40
+ %1 = load i32, i32* %I.i, align 4, !dbg !41
+ %add.i = add nsw i32 %1, %0, !dbg !41
+ store i32 %add.i, i32* %I.i, align 4, !dbg !41
+ %call = call i32 @_ZN1S3fooEv(%struct.S* %s), !dbg !42
+ call void @llvm.dbg.declare(metadata %struct.S** %this.addr.i, metadata !43, metadata !35), !dbg !45
+ call void @llvm.dbg.declare(metadata i32* %Add.addr.i, metadata !46, metadata !35), !dbg !47
+ ret i32 %call, !dbg !48
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: nounwind ssp uwtable
+define linkonce_odr i32 @_ZN1S3fooEv(%struct.S* %this) #2 align 2 {
+entry:
+ %this.addr = alloca %struct.S*, align 8
+ store %struct.S* %this, %struct.S** %this.addr, align 8
+ call void @llvm.dbg.declare(metadata %struct.S** %this.addr, metadata !49, metadata !35), !dbg !50
+ %this1 = load %struct.S*, %struct.S** %this.addr
+ %I = getelementptr inbounds %struct.S, %struct.S* %this1, i32 0, i32 0, !dbg !51
+ %0 = load i32, i32* %I, align 4, !dbg !51
+ ret i32 %0, !dbg !52
+}
+
+attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!30, !31, !32}
+!llvm.ident = !{!33}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !24)
+!1 = !DIFile(filename: "odr3.cpp", directory: "/Inputs")
+!2 = !{}
+!3 = !{!4, !20}
+!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
+!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
+!6 = !{!7, !9, !10, !14, !17}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32)
+!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64)
+!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null, !13}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !13, !8}
+!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!8, !13}
+!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE")
+!21 = !{!22}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
+!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float)
+!24 = !{!25, !28, !29}
+!25 = !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 3, type: !26, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: i32 ()* @_Z3barv, variables: !2)
+!26 = !DISubroutineType(types: !27)
+!27 = !{!8}
+!28 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, declaration: !14, variables: !2)
+!29 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: true, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false, function: i32 (%struct.S*)* @_ZN1S3fooEv, declaration: !17, variables: !2)
+!30 = !{i32 2, !"Dwarf Version", i32 2}
+!31 = !{i32 2, !"Debug Info Version", i32 3}
+!32 = !{i32 1, !"PIC Level", i32 2}
+!33 = !{!"clang version 3.8.0 (trunk 242534)"}
+!34 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "s", scope: !25, file: !1, line: 4, type: !"_ZTS1S")
+!35 = !DIExpression()
+!36 = !DILocation(line: 4, column: 4, scope: !25)
+!37 = !DILocation(line: 5, column: 2, scope: !25)
+!38 = !DILocation(line: 5, column: 59, scope: !28, inlinedAt: !39)
+!39 = distinct !DILocation(line: 5, column: 2, scope: !25)
+!40 = !DILocation(line: 5, column: 54, scope: !28, inlinedAt: !39)
+!41 = !DILocation(line: 5, column: 56, scope: !28, inlinedAt: !39)
+!42 = !DILocation(line: 6, column: 9, scope: !25)
+!43 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !28, type: !44, flags: DIFlagArtificial | DIFlagObjectPointer)
+!44 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64)
+!45 = !DILocation(line: 0, scope: !28, inlinedAt: !39)
+!46 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "Add", arg: 2, scope: !28, file: !5, line: 5, type: !8)
+!47 = !DILocation(line: 5, column: 16, scope: !28, inlinedAt: !39)
+!48 = !DILocation(line: 6, column: 2, scope: !25)
+!49 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !29, type: !44, flags: DIFlagArtificial | DIFlagObjectPointer)
+!50 = !DILocation(line: 0, scope: !29)
+!51 = !DILocation(line: 18, column: 21, scope: !29)
+!52 = !DILocation(line: 18, column: 14, scope: !29)
--- /dev/null
+namespace {
+ class AnonC {
+ };
+}
+
+void baz() {
+ AnonC ac;
+}
--- /dev/null
+; Generated from odr4.cpp and odr-types.h by running:
+; clang -emit-llvm -g -S -std=c++11 odr4.cpp
+; ModuleID = 'odr4.cpp'
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+%"class.(anonymous namespace)::AnonC" = type { i8 }
+
+; Function Attrs: nounwind ssp uwtable
+define void @_Z3bazv() #0 {
+entry:
+ %ac = alloca %"class.(anonymous namespace)::AnonC", align 1
+ call void @llvm.dbg.declare(metadata %"class.(anonymous namespace)::AnonC"* %ac, metadata !11, metadata !14), !dbg !15
+ ret void, !dbg !16
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3)
+!1 = !DIFile(filename: "odr4.cpp", directory: "/Inputs")
+!2 = !{}
+!3 = !{!4}
+!4 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1, file: !1, line: 6, type: !5, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @_Z3bazv, variables: !2)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null}
+!7 = !{i32 2, !"Dwarf Version", i32 2}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"PIC Level", i32 2}
+!10 = !{!"clang version 3.8.0 (trunk 242534)"}
+!11 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "ac", scope: !4, file: !1, line: 7, type: !12)
+!12 = !DICompositeType(tag: DW_TAG_class_type, name: "AnonC", scope: !13, file: !1, line: 2, size: 8, align: 8, elements: !2)
+!13 = !DINamespace(scope: null, file: !1, line: 1)
+!14 = !DIExpression()
+!15 = !DILocation(line: 7, column: 8, scope: !4)
+!16 = !DILocation(line: 8, column: 1, scope: !4)
--- /dev/null
+#include "odr-types.h"
+
+double baz() {
+ S::Nested d;
+ d.init(0);
+ return d.D;
+}
--- /dev/null
+; Generated from odr5.cpp and odr-types.h by running:
+; clang -emit-llvm -g -S -std=c++11 odr5.cpp
+; ModuleID = 'odr5.cpp'
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+%"struct.S::Nested" = type { double }
+
+; Function Attrs: ssp uwtable
+define double @_Z3bazv() #0 {
+entry:
+ %d = alloca %"struct.S::Nested", align 8
+ call void @llvm.dbg.declare(metadata %"struct.S::Nested"* %d, metadata !39, metadata !40), !dbg !41
+ call void @_ZN1S6Nested4initIiEEvT_(%"struct.S::Nested"* %d, i32 0), !dbg !42
+ %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"* %d, i32 0, i32 0, !dbg !43
+ %0 = load double, double* %D, align 8, !dbg !43
+ ret double %0, !dbg !44
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: nounwind ssp uwtable
+define linkonce_odr void @_ZN1S6Nested4initIiEEvT_(%"struct.S::Nested"* %this, i32 %Val) #2 align 2 {
+entry:
+ %this.addr = alloca %"struct.S::Nested"*, align 8
+ %Val.addr = alloca i32, align 4
+ store %"struct.S::Nested"* %this, %"struct.S::Nested"** %this.addr, align 8
+ call void @llvm.dbg.declare(metadata %"struct.S::Nested"** %this.addr, metadata !45, metadata !40), !dbg !47
+ store i32 %Val, i32* %Val.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %Val.addr, metadata !48, metadata !40), !dbg !49
+ %this1 = load %"struct.S::Nested"*, %"struct.S::Nested"** %this.addr
+ %0 = load i32, i32* %Val.addr, align 4, !dbg !50
+ %conv = sitofp i32 %0 to double, !dbg !50
+ %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"* %this1, i32 0, i32 0, !dbg !51
+ store double %conv, double* %D, align 8, !dbg !52
+ ret void, !dbg !53
+}
+
+attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!35, !36, !37}
+!llvm.ident = !{!38}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !24)
+!1 = !DIFile(filename: "odr5.cpp", directory: "/Inputs")
+!2 = !{}
+!3 = !{!4, !20, !23}
+!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
+!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
+!6 = !{!7, !9, !10, !14, !17}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32)
+!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64)
+!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null, !13}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !13, !8}
+!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!8, !13}
+!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE")
+!21 = !{!22}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
+!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float)
+!24 = !{!25, !28}
+!25 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1, file: !1, line: 3, type: !26, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: double ()* @_Z3bazv, variables: !2)
+!26 = !DISubroutineType(types: !27)
+!27 = !{!23}
+!28 = !DISubprogram(name: "init<int>", linkageName: "_ZN1S6Nested4initIiEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12, type: !29, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, function: void (%"struct.S::Nested"*, i32)* @_ZN1S6Nested4initIiEEvT_, templateParams: !32, declaration: !34, variables: !2)
+!29 = !DISubroutineType(types: !30)
+!30 = !{null, !31, !8}
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!32 = !{!33}
+!33 = !DITemplateTypeParameter(name: "T", type: !8)
+!34 = !DISubprogram(name: "init<int>", linkageName: "_ZN1S6Nested4initIiEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12, type: !29, isLocal: false, isDefinition: false, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, templateParams: !32)
+!35 = !{i32 2, !"Dwarf Version", i32 2}
+!36 = !{i32 2, !"Debug Info Version", i32 3}
+!37 = !{i32 1, !"PIC Level", i32 2}
+!38 = !{!"clang version 3.8.0 (trunk 242534)"}
+!39 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "d", scope: !25, file: !1, line: 4, type: !"_ZTSN1S6NestedE")
+!40 = !DIExpression()
+!41 = !DILocation(line: 4, column: 12, scope: !25)
+!42 = !DILocation(line: 5, column: 2, scope: !25)
+!43 = !DILocation(line: 6, column: 11, scope: !25)
+!44 = !DILocation(line: 6, column: 2, scope: !25)
+!45 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !28, type: !46, flags: DIFlagArtificial | DIFlagObjectPointer)
+!46 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64)
+!47 = !DILocation(line: 0, scope: !28)
+!48 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "Val", arg: 2, scope: !28, file: !5, line: 12, type: !8)
+!49 = !DILocation(line: 12, column: 36, scope: !28)
+!50 = !DILocation(line: 12, column: 54, scope: !28)
+!51 = !DILocation(line: 12, column: 43, scope: !28)
+!52 = !DILocation(line: 12, column: 45, scope: !28)
+!53 = !DILocation(line: 12, column: 60, scope: !28)
--- /dev/null
+#include "odr-types.h"
+
+double baz() {
+ S::Nested d;
+ d.init(0.0);
+ return d.D;
+}
--- /dev/null
+; Generated from odr6.cpp and odr-types.h by running:
+; clang -emit-llvm -g -S -std=c++11 odr6.cpp
+; ModuleID = 'odr6.cpp'
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+%"struct.S::Nested" = type { double }
+
+; Function Attrs: ssp uwtable
+define double @_Z3bazv() #0 {
+entry:
+ %d = alloca %"struct.S::Nested", align 8
+ call void @llvm.dbg.declare(metadata %"struct.S::Nested"* %d, metadata !39, metadata !40), !dbg !41
+ call void @_ZN1S6Nested4initIdEEvT_(%"struct.S::Nested"* %d, double 0.000000e+00), !dbg !42
+ %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"* %d, i32 0, i32 0, !dbg !43
+ %0 = load double, double* %D, align 8, !dbg !43
+ ret double %0, !dbg !44
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: nounwind ssp uwtable
+define linkonce_odr void @_ZN1S6Nested4initIdEEvT_(%"struct.S::Nested"* %this, double %Val) #2 align 2 {
+entry:
+ %this.addr = alloca %"struct.S::Nested"*, align 8
+ %Val.addr = alloca double, align 8
+ store %"struct.S::Nested"* %this, %"struct.S::Nested"** %this.addr, align 8
+ call void @llvm.dbg.declare(metadata %"struct.S::Nested"** %this.addr, metadata !45, metadata !40), !dbg !47
+ store double %Val, double* %Val.addr, align 8
+ call void @llvm.dbg.declare(metadata double* %Val.addr, metadata !48, metadata !40), !dbg !49
+ %this1 = load %"struct.S::Nested"*, %"struct.S::Nested"** %this.addr
+ %0 = load double, double* %Val.addr, align 8, !dbg !50
+ %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"* %this1, i32 0, i32 0, !dbg !51
+ store double %0, double* %D, align 8, !dbg !52
+ ret void, !dbg !53
+}
+
+attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!35, !36, !37}
+!llvm.ident = !{!38}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !24)
+!1 = !DIFile(filename: "odr6.cpp", directory: "/Inputs")
+!2 = !{}
+!3 = !{!4, !20, !23}
+!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
+!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
+!6 = !{!7, !9, !10, !14, !17}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32)
+!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64)
+!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null, !13}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !13, !8}
+!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!8, !13}
+!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE")
+!21 = !{!22}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
+!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float)
+!24 = !{!25, !28}
+!25 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1, file: !1, line: 3, type: !26, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: double ()* @_Z3bazv, variables: !2)
+!26 = !DISubroutineType(types: !27)
+!27 = !{!23}
+!28 = !DISubprogram(name: "init<double>", linkageName: "_ZN1S6Nested4initIdEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12, type: !29, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, function: void (%"struct.S::Nested"*, double)* @_ZN1S6Nested4initIdEEvT_, templateParams: !32, declaration: !34, variables: !2)
+!29 = !DISubroutineType(types: !30)
+!30 = !{null, !31, !23}
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!32 = !{!33}
+!33 = !DITemplateTypeParameter(name: "T", type: !23)
+!34 = !DISubprogram(name: "init<double>", linkageName: "_ZN1S6Nested4initIdEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12, type: !29, isLocal: false, isDefinition: false, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, templateParams: !32)
+!35 = !{i32 2, !"Dwarf Version", i32 2}
+!36 = !{i32 2, !"Debug Info Version", i32 3}
+!37 = !{i32 1, !"PIC Level", i32 2}
+!38 = !{!"clang version 3.8.0 (trunk 242534)"}
+!39 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "d", scope: !25, file: !1, line: 4, type: !"_ZTSN1S6NestedE")
+!40 = !DIExpression()
+!41 = !DILocation(line: 4, column: 12, scope: !25)
+!42 = !DILocation(line: 5, column: 2, scope: !25)
+!43 = !DILocation(line: 6, column: 11, scope: !25)
+!44 = !DILocation(line: 6, column: 2, scope: !25)
+!45 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !28, type: !46, flags: DIFlagArtificial | DIFlagObjectPointer)
+!46 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64)
+!47 = !DILocation(line: 0, scope: !28)
+!48 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "Val", arg: 2, scope: !28, file: !5, line: 12, type: !23)
+!49 = !DILocation(line: 12, column: 36, scope: !28)
+!50 = !DILocation(line: 12, column: 54, scope: !28)
+!51 = !DILocation(line: 12, column: 43, scope: !28)
+!52 = !DILocation(line: 12, column: 45, scope: !28)
+!53 = !DILocation(line: 12, column: 60, scope: !28)
--- /dev/null
+#include "odr-types.h"
+
+void foo() {
+ S::Nested N;
+}
--- /dev/null
+; Generated from odr7.cpp and odr-types.h by running:
+; clang -emit-llvm -g -S -std=c++11 odr7.cpp
+; ModuleID = 'odr7.cpp'
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+%"struct.S::Nested" = type { double }
+
+; Function Attrs: nounwind ssp uwtable
+define void @_Z3foov() #0 {
+entry:
+ %N = alloca %"struct.S::Nested", align 8
+ call void @llvm.dbg.declare(metadata %"struct.S::Nested"* %N, metadata !32, metadata !33), !dbg !34
+ ret void, !dbg !35
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!28, !29, !30}
+!llvm.ident = !{!31}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !24)
+!1 = !DIFile(filename: "odr7.cpp", directory: "/Inputs")
+!2 = !{}
+!3 = !{!4, !20}
+!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
+!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
+!6 = !{!7, !9, !10, !14, !17}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32)
+!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64)
+!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null, !13}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !13, !8}
+!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!8, !13}
+!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE")
+!21 = !{!22}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
+!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float)
+!24 = !{!25}
+!25 = !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 3, type: !26, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @_Z3foov, variables: !2)
+!26 = !DISubroutineType(types: !27)
+!27 = !{null}
+!28 = !{i32 2, !"Dwarf Version", i32 2}
+!29 = !{i32 2, !"Debug Info Version", i32 3}
+!30 = !{i32 1, !"PIC Level", i32 2}
+!31 = !{!"clang version 3.8.0 (trunk 242534)"}
+!32 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "N", scope: !25, file: !1, line: 4, type: !"_ZTSN1S6NestedE")
+!33 = !DIExpression()
+!34 = !DILocation(line: 4, column: 12, scope: !25)
+!35 = !DILocation(line: 5, column: 1, scope: !25)
--- /dev/null
+# REQUIRES: object-emission
+# RUN: rm -rf %t
+# RUN: mkdir -p %t
+# RUN: llc -filetype=obj %p/../Inputs/odr1.ll -o %t/odr1.o
+# RUN: llc -filetype=obj %p/../Inputs/odr2.ll -o %t/odr2.o
+# RUN: llc -filetype=obj %p/../Inputs/odr3.ll -o %t/odr3.o
+# RUN: llc -filetype=obj %p/../Inputs/odr4.ll -o %t/odr4.o
+# RUN: llc -filetype=obj %p/../Inputs/odr5.ll -o %t/odr5.o
+# RUN: llc -filetype=obj %p/../Inputs/odr6.ll -o %t/odr6.o
+# RUN: llc -filetype=obj %p/../Inputs/odr7.ll -o %t/odr7.o
+# RUN: llvm-dsymutil -oso-prepend-path=%t -y %s -o - | llvm-dwarfdump -debug-dump=info - | FileCheck -check-prefix=ODR -check-prefix=CHECK %s
+# RUN: llvm-dsymutil -oso-prepend-path=%t -y %s -no-odr -o - | llvm-dwarfdump -debug-dump=info - | FileCheck -check-prefix=NOODR -check-prefix=CHECK %s
+
+# Totally made up debug map to test ODR uniquing
+
+---
+triple: 'x86_64-unknown-unknown-macho'
+objects:
+ - filename: odr1.o
+ symbols:
+ - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x1000, size: 0x12 }
+ - { sym: __Z4funcv, objAddr: 0x0, binAddr: 0x2000, size: 0x12 }
+ - { sym: __ZZ4funcvENKUlvE_clEv, objAddr: 0x0, binAddr: 0x3000, size: 0x12 }
+
+# Check that all our types are in the first CU.
+
+# CHECK: TAG_compile_unit
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: AT_name{{.*}}"odr1.cpp"
+
+# This is "struct S"
+
+# CHECK: 0x[[S:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+# CHECK-NEXT: DW_AT_name{{.*}}"S"
+# CHECK-NOT: NULL
+# CHECK: 0x[[NESTED:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: DW_AT_name{{.*}}"Nested"
+# CHECK: NULL
+# CHECK: DW_TAG_subprogram
+# CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S4incrEv"
+# CHECK: NULL
+# CHECK: DW_TAG_subprogram
+# CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S4incrEi"
+# CHECK: NULL
+# CHECK: DW_TAG_subprogram
+# CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3fooEv"
+# CHECK: NULL
+# CHECK: NULL
+
+# This is "class N::C"
+
+# CHECK: DW_TAG_namespace
+# CHECK-NEXT: DW_AT_name{{.*}}"N"
+# CHECK-NOT: NULL
+# CHECK: 0x[[NC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
+# CHECK-NEXT: DW_AT_name{{.*}}"C"
+# CHECK: NULL
+
+# This is "class N::N::C"
+
+# CHECK: DW_TAG_namespace
+# CHECK-NEXT: DW_AT_name{{.*}}"N"
+# CHECK-NOT: NULL
+# CHECK: 0x[[NNC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
+# CHECK-NEXT: DW_AT_name{{.*}}"C"
+# CHECK: NULL
+# CHECK: NULL
+# CHECK: NULL
+
+# This is "AliasForS"
+# CHECK: 0x[[ALIASFORS:[0-9a-f]*]]:{{.*}}DW_TAG_typedef
+# CHECK-NEXT: DW_AT_type{{.*}}[[S]]
+# CHECK-NEXT: DW_AT_name{{.*}}"AliasForS"
+
+# This is "union U"
+
+# CHECK: 0x[[U:[0-9a-f]*]]:{{.*}}DW_TAG_union_type
+# CHECK-NEXT: DW_AT_name{{.*}}"U"
+# CHECK-NOT: NULL
+# CHECK: 0x[[UC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
+# CHECK-NOT: NULL
+# CHECK: 0x[[US:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+# CHECK: NULL
+
+# This is "func" free function
+
+# CHECK: DW_TAG_subprogram
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: DW_AT_name{{.*}}"func"
+# CHECK: 0x[[CINSIDEFUNC:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+# CHECK-NEXT: DW_AT_name{{.*}}"CInsideFunc"
+
+# This is "(anonymous namespace)::AnonC"
+
+# CHECK: DW_TAG_namespace
+# CHECK-NOT: {{DW_AT_name|NULL|DW_TAG}}
+# CHECK: 0x[[ANONC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
+# CHECK-NEXT: DW_AT_name{{.*}}"AnonC"
+
+ - filename: odr1.o
+ symbols:
+ - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x4000, size: 0x12 }
+ - { sym: __Z4funcv, objAddr: 0x0, binAddr: 0x5000, size: 0x12 }
+ - { sym: __ZZ4funcvENKUlvE_clEv, objAddr: 0x0, binAddr: 0x6000, size: 0x12 }
+
+# We relink the same file a second time. In the ODR case, everything (except for the
+# union for now) should be uniqued. In the non-ODR case, we should get every type
+# duplicated.
+
+# CHECK: TAG_compile_unit
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: AT_name{{.*}}"odr1.cpp"
+
+# ODR: DW_TAG_union_type
+# ODR-NEXT: DW_AT_name{{.*}}"U"
+# Types defined inside the union should be uniqued:
+# ODR: DW_TAG_member
+# ODR-NEXT: DW_AT_name{{.*}}"C"
+# ODR-NOT: {{NULL|DW_TAG}}
+# ODR: DW_AT_type{{.*}}[[UC]]
+# ODR: DW_TAG_member
+# ODR-NEXT: DW_AT_name{{.*}}"S"
+# ODR-NOT: {{NULL|DW_TAG}}
+# ODR: DW_AT_type{{.*}}[[US]]
+
+# Skip func
+# ODR: DW_TAG_subprogram
+# ODR-NOT: {{NULL|DW_TAG}}
+# ODR: DW_AT_name{{.*}}"func"
+# ODR: NULL
+
+# ODR: DW_TAG_subprogram
+# ODR-NOT: {{NULL|DW_TAG}}
+# ODR: DW_AT_name{{.*}}"foo"
+# ODR-NOT: NULL
+# ODR: DW_TAG_variable
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_name{{.*}}"s"
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_type{{.*}}[[ALIASFORS]]
+# ODR: DW_TAG_variable
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_name{{.*}}"nc"
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_type{{.*}}[[NC]]
+# ODR: DW_TAG_variable
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_name{{.*}}"nnc"
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_type{{.*}}[[NNC]]
+# ODR: DW_TAG_variable
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_name{{.*}}"ac"
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_type{{.*}}[[ANONC]]
+
+# ODR: DW_TAG_subprogram
+# ODR-NOT: {{NULL|DW_TAG}}
+# ODR: linkage_name{{.*}}"_ZZ4funcvENKUlvE_clEv"
+# ODR-NOT: NULL
+# ODR: DW_TAG_variable
+# ODR-NOT: DW_TAG
+# ODR: DW_AT_name{{.*}}"dummy"
+# ODR-NOT: NULL
+# ODR: DW_AT_type{{.*}}[[CINSIDEFUNC]]
+
+# With no ODR uniquing, we should get copies of all the types:
+
+# This is "struct S"
+# NOODR: 0x[[DUP_S:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+# NOODR-NEXT: DW_AT_name{{.*}}"S"
+
+# This is "class N::C"
+# NOODR: DW_TAG_namespace
+# NOODR-NEXT: DW_AT_name{{.*}}"N"
+# NOODR: 0x[[DUP_NC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
+# NOODR-NEXT: DW_AT_name{{.*}}"C"
+
+# This is "class N::N::C"
+# NOODR: DW_TAG_namespace
+# NOODR-NEXT: DW_AT_name{{.*}}"N"
+# NOODR: 0x[[DUP_NNC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
+# NOODR-NEXT: DW_AT_name{{.*}}"C"
+
+# This is "AliasForS"
+# NOODR: 0x[[DUP_ALIASFORS:[0-9a-f]*]]:{{.*}}DW_TAG_typedef
+# NOODR-NOT: {{NULL|DW_TAG}}
+# NOODR: DW_AT_name{{.*}}"AliasForS"
+
+# This is "union U"
+
+# NOODR: 0x[[U:[0-9a-f]*]]:{{.*}}DW_TAG_union_type
+# NOODR-NEXT: DW_AT_name{{.*}}"U"
+# NOODR-NOT: NULL
+# NOODR: 0x[[DUP_UC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
+# NOODR-NOT: NULL
+# NOODR: 0x[[DUP_US:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+# NOODR: NULL
+
+# This is "func" free function
+
+# NOODR: DW_TAG_subprogram
+# NOODR-NOT: {{DW_TAG|NULL}}
+# NOODR: DW_AT_name{{.*}}"func"
+# NOODR: 0x[[DUP_CINSIDEFUNC:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+# NOODR-NEXT: DW_AT_name{{.*}}"CInsideFunc"
+
+# NOODR: DW_TAG_subprogram
+# NOODR-NOT: {{NULL|DW_TAG}}
+# NOODR: DW_AT_name{{.*}}"foo"
+# NOODR-NOT: NULL
+# NOODR: DW_TAG_variable
+# NOODR-NOT: {{DW_TAG|NULL}}
+# NOODR: DW_AT_name{{.*}}"s"
+# NOODR-NOT: {{DW_TAG|NULL}}
+# NOODR: DW_AT_type{{.*}}[[DUP_ALIASFORS]]
+# NOODR: DW_TAG_variable
+# NOODR-NOT: {{DW_TAG|NULL}}
+# NOODR: DW_AT_name{{.*}}"nc"
+# NOODR-NOT: {{DW_TAG|NULL}}
+# NOODR: DW_AT_type{{.*}}[[DUP_NC]]
+# NOODR: DW_TAG_variable
+# NOODR-NOT: {{DW_TAG|NULL}}
+# NOODR: DW_AT_name{{.*}}"nnc"
+# NOODR-NOT: {{DW_TAG|NULL}}
+# NOODR: DW_AT_type{{.*}}[[DUP_NNC]]
+# NOODR: DW_TAG_variable
+# NOODR-NOT: {{DW_TAG|NULL}}
+# NOODR: DW_AT_name{{.*}}"ac"
+# NOODR-NOT: {{DW_TAG|NULL}}
+# NOODR: DW_AT_type{{.*}}0x[[DUP_ANONC:[0-9a-f]*]]
+
+# This is the lanbda inside func
+
+# NOODR: DW_TAG_subprogram
+# NOODR-NOT: {{NULL|DW_TAG}}
+# NOODR: linkage_name{{.*}}"_ZZ4funcvENKUlvE_clEv"
+# NOODR-NOT: NULL
+# NOODR: DW_TAG_variable
+# NOODR-NOT: DW_TAG
+# NOODR: DW_AT_name{{.*}}"dummy"
+# NOODR-NOT: NULL
+# NOODR: DW_AT_type{{.*}}[[DUP_CINSIDEFUNC]]
+
+# This is "(anonymous namespace)::AnonC"
+
+# NOODR: DW_TAG_namespace
+# NOODR-NOT: {{DW_AT_name|NULL|DW_TAG}}
+# NOODR: 0x[[DUP_ANONC]]:{{.*}}DW_TAG_class_type
+# NOODR-NEXT: DW_AT_name{{.*}}"AnonC"
+
+ - filename: odr2.o
+ symbols:
+ - { sym: __ZN1S3fooEv, objAddr: 0x0, binAddr: 0x7000, size: 0x12 }
+ - { sym: __Z3barv, objAddr: 0x0, binAddr: 0x8000, size: 0x12 }
+ - filename: odr3.o
+ symbols:
+ - { sym: __ZN1S3fooEv, objAddr: 0x0, binAddr: 0x8000, size: 0x12 }
+ - { sym: __Z3barv, objAddr: 0x0, binAddr: 0x9000, size: 0x12 }
+
+# odr2.cpp and odr3.cpp test that a simple overloaded function doesn't break the
+# uniquing (contrary to what we'll see with template/artificial) functions.
+
+# CHECK: TAG_compile_unit
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: AT_name{{.*}}"odr2.cpp"
+
+# NO-ODR: DW_TAG_structure_type
+# ODR-NOT: DW_TAG_structure_type
+
+# ODR: DW_TAG_subprogram
+# ODR: DW_AT_specification{{.*}}4incr
+# ODR: DW_TAG_formal_parameter
+# ODR-NEXT: DW_AT_name{{.*}}"this"
+# ODR-NEXT: DW_AT_type{{.*}}0x00000000[[S_PTR:[0-9a-f]*]]
+# ODR: 0x[[S_PTR]]:{{.*}}DW_TAG_pointer_type
+# ODR-NEXT: DW_AT_type{{.*}}[[S]]
+# ODR: DW_TAG_subprogram
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_name{{.*}}"bar"
+# ODR-NOT: NULL
+# ODR: DW_TAG_variable
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_type{{.*}}[[S]]
+# ODR-NOT NULL
+# DOR: DW_TAG_inlined_subroutine
+# ODR-NOT NULL
+# ODR: DW_TAG_formal_parameter
+# ODR-NOT {{NULL|DW_TAG}}
+# ODR: DW_AT_type{{.*}}[[S_PTR]]
+
+# CHECK: TAG_compile_unit
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: AT_name{{.*}}"odr3.cpp"
+
+# NO-ODR: DW_TAG_structure_type
+# ODR-NOT: DW_TAG_structure_type
+
+# ODR: DW_TAG_subprogram
+# ODR: DW_AT_specification{{.*}}4incr
+# ODR: DW_TAG_formal_parameter
+# ODR-NEXT: DW_AT_name{{.*}}"this"
+# ODR-NEXT: DW_AT_type{{.*}}0x00000000[[S_PTR2:[0-9a-f]*]]
+# ODR: 0x[[S_PTR2]]:{{.*}}DW_TAG_pointer_type
+# ODR-NEXT: DW_AT_type{{.*}}[[S]]
+# ODR: DW_TAG_subprogram
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_name{{.*}}"bar"
+# ODR-NOT: NULL
+# ODR: DW_TAG_variable
+# ODR-NOT: {{DW_TAG|NULL}}
+# ODR: DW_AT_type{{.*}}[[S]]
+# ODR-NOT NULL
+# DOR: DW_TAG_inlined_subroutine
+# ODR-NOT NULL
+# ODR: DW_TAG_formal_parameter
+# ODR-NOT {{NULL|DW_TAG}}
+# ODR: DW_AT_type{{.*}}[[S_PTR2]]
+
+ - filename: odr4.o
+ symbols:
+ - { sym: __Z3bazv, objAddr: 0x0, binAddr: 0xa000, size: 0x12 }
+
+# odr4.cpp helps check that anonymous namespaces with similarly named contents do
+# not get uniqued.
+
+# CHECK: TAG_compile_unit
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: AT_name{{.*}}"odr4.cpp"
+
+# CHECK: DW_TAG_subprogram
+# CHECK-NOT: NULL
+# CHECK: DW_TAG_variable
+# CHECK-NOT: DW_TAG
+# ODR: DW_AT_type{{.*}}[[LOCALANONC:........]])
+# NOODR: DW_AT_type{{.*}}[[LOCALANONC:........]]})
+
+# CHECK: DW_TAG_namespace
+# CHECK-NOT: DW_AT_name
+# CHECK: [[LOCALANONC]]{{.*}}DW_TAG_class_type
+# CHECK-NOT: {{NULL|DW_TAG}}
+# CHECK: DW_AT_name{{.*}}"AnonC"
+
+ - filename: odr5.o
+ symbols:
+ - { sym: __Z3bazv, objAddr: 0x0, binAddr: 0xb000, size: 0x12 }
+ - { sym: __ZN1S6Nested4initIiEEvT_, objAddr: 0x0, binAddr: 0xc000, size: 0x12 }
+ - filename: odr6.o
+ symbols:
+ - { sym: __Z3bazv, objAddr: 0x0, binAddr: 0xd000, size: 0x12 }
+ - { sym: __ZN1S6Nested4initIdEEvT_, objAddr: 0x0, binAddr: 0xe000, size: 0x12 }
+
+# odr5.cpp and odr6.cpp instanciate a template member function of the S class.
+# They instanciate it with different types. As DWARF only describes the actual
+# intances, these members aren't described in the uniqued class definition of
+# odr1.cpp. Both these files should contain a new copy of S' definition with
+# the template instance included.
+
+# CHECK: TAG_compile_unit
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: AT_name{{.*}}"odr5.cpp"
+
+# CHECK: 0x{{[0-9a-f]*}}:{{.*}}DW_TAG_structure_type
+# CHECK-NEXT: DW_AT_name{{.*}}"S"
+# CHECK-NOT: NULL
+# CHECK: 0x[[NESTED2:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: DW_AT_name{{.*}}"Nested"
+# CHECK-NOT: NULL
+# CHECK: 0x[[INITTEMPLATE:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+# CHECK-NEXT:{{.*}}"_ZN1S6Nested4init
+
+# CHECK: DW_AT_specification{{.*}}[[INITTEMPLATE]]
+# CHECK: DW_TAG_formal_parameter
+# CHECK-NOT: DW_TAG
+# CHECK: DW_AT_type{{.*}}[[NESTED_PTR:[0-9a-f]{8}]]{{[}]?}})
+
+# CHECK: 0x[[NESTED_PTR]]{{.*}}DW_TAG_pointer_type
+# ODR-NEXT: DW_AT_type{{.*}}[[NESTED]]
+# NOODR-NEXT: DW_AT_type{{.*}}[[NESTED2]]
+
+# CHECK: TAG_compile_unit
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: AT_name{{.*}}"odr6.cpp"
+
+# CHECK: 0x{{[0-9a-f]*}}:{{.*}}DW_TAG_structure_type
+# CHECK-NEXT: DW_AT_name{{.*}}"S"
+# CHECK-NOT: NULL
+# CHECK: 0x[[NESTED3:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: DW_AT_name{{.*}}"Nested"
+# CHECK-NOT: NULL
+# CHECK: 0x[[INITTEMPLATE2:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+# CHECK-NEXT:{{.*}}"_ZN1S6Nested4init
+
+# CHECK: DW_AT_specification{{.*}}[[INITTEMPLATE2]]
+# CHECK: DW_TAG_formal_parameter
+# CHECK-NOT: DW_TAG
+# CHECK: DW_AT_type{{.*}}[[NESTED_PTR2:[0-9a-f]{8}]]{{[}]?}})
+
+# CHECK: 0x[[NESTED_PTR2]]{{.*}}DW_TAG_pointer_type
+# ODR-NEXT: DW_AT_type{{.*}}[[NESTED]]
+# NOODR-NEXT: DW_AT_type{{.*}}[[NESTED3]]
+
+ - filename: odr7.o
+ symbols:
+ - { sym: __Z3foov, objAddr: 0x0, binAddr: 0xf000, size: 0x12 }
+
+# Check that a reference to a nested class correctly refers to the original
+# definition
+
+# CHECK: TAG_compile_unit
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK: AT_name{{.*}}"odr7.cpp"
+
+# ODR: DW_TAG_subprogram
+# ODR-NOT: NULL
+# ODR: DW_TAG_variable
+# ODR-NOT: DW_TAG
+# ODR: DW_AT_type{{.*}}[[NESTED]]
+...
+
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DIE.h"
+#include "llvm/Config/config.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
}
};
+class CompileUnit;
+struct DeclMapInfo;
+class NonRelocatableStringpool;
+
+/// A DeclContext is a named program scope that is used for ODR
+/// uniquing of types.
+/// The set of DeclContext for the ODR-subject parts of a Dwarf link
+/// is expanded (and uniqued) with each new object file processed. We
+/// need to determine the context of each DIE in an linked object file
+/// to see if the corresponding type has already been emitted.
+///
+/// The contexts are conceptually organised as a tree (eg. a function
+/// scope is contained in a namespace scope that contains other
+/// scopes), but storing/accessing them in an actual tree is too
+/// inefficient: we need to be able to very quickly query a context
+/// for a given child context by name. Storing a StringMap in each
+/// DeclContext would be too space inefficient.
+/// The solution here is to give each DeclContext a link to its parent
+/// (this allows to walk up the tree), but to query the existance of a
+/// specific DeclContext using a separate DenseMap keyed on the hash
+/// of the fully qualified name of the context.
+class DeclContext {
+ unsigned QualifiedNameHash;
+ uint32_t Line;
+ uint32_t ByteSize;
+ uint16_t Tag;
+ StringRef Name;
+ StringRef File;
+ const DeclContext &Parent;
+ const DWARFDebugInfoEntryMinimal *LastSeenDIE;
+ uint32_t LastSeenCompileUnitID;
+ uint32_t CanonicalDIEOffset;
+
+ friend DeclMapInfo;
+
+public:
+ typedef DenseSet<DeclContext *, DeclMapInfo> Map;
+
+ DeclContext()
+ : QualifiedNameHash(0), Line(0), ByteSize(0),
+ Tag(dwarf::DW_TAG_compile_unit), Name(), File(), Parent(*this),
+ LastSeenDIE(nullptr), LastSeenCompileUnitID(0), CanonicalDIEOffset(0) {}
+
+ DeclContext(unsigned Hash, uint32_t Line, uint32_t ByteSize, uint16_t Tag,
+ StringRef Name, StringRef File, const DeclContext &Parent,
+ const DWARFDebugInfoEntryMinimal *LastSeenDIE = nullptr,
+ unsigned CUId = 0)
+ : QualifiedNameHash(Hash), Line(Line), ByteSize(ByteSize), Tag(Tag),
+ Name(Name), File(File), Parent(Parent), LastSeenDIE(LastSeenDIE),
+ LastSeenCompileUnitID(CUId), CanonicalDIEOffset(0) {}
+
+ uint32_t getQualifiedNameHash() const { return QualifiedNameHash; }
+
+ bool setLastSeenDIE(CompileUnit &U, const DWARFDebugInfoEntryMinimal *Die);
+
+ uint32_t getCanonicalDIEOffset() const { return CanonicalDIEOffset; }
+ void setCanonicalDIEOffset(uint32_t Offset) { CanonicalDIEOffset = Offset; }
+
+ uint16_t getTag() const { return Tag; }
+ StringRef getName() const { return Name; }
+};
+
+/// Info type for the DenseMap storing the DeclContext pointers.
+struct DeclMapInfo : private DenseMapInfo<DeclContext *> {
+ using DenseMapInfo<DeclContext *>::getEmptyKey;
+ using DenseMapInfo<DeclContext *>::getTombstoneKey;
+
+ static unsigned getHashValue(const DeclContext *Ctxt) {
+ return Ctxt->QualifiedNameHash;
+ }
+
+ static bool isEqual(const DeclContext *LHS, const DeclContext *RHS) {
+ if (RHS == getEmptyKey() || RHS == getTombstoneKey())
+ return RHS == LHS;
+ return LHS->QualifiedNameHash == RHS->QualifiedNameHash &&
+ LHS->Line == RHS->Line && LHS->ByteSize == RHS->ByteSize &&
+ LHS->Name.data() == RHS->Name.data() &&
+ LHS->File.data() == RHS->File.data() &&
+ LHS->Parent.QualifiedNameHash == RHS->Parent.QualifiedNameHash;
+ }
+};
+
+/// This class gives a tree-like API to the DenseMap that stores the
+/// DeclContext objects. It also holds the BumpPtrAllocator where
+/// these objects will be allocated.
+class DeclContextTree {
+ BumpPtrAllocator Allocator;
+ DeclContext Root;
+ DeclContext::Map Contexts;
+
+public:
+ /// Get the child of \a Context described by \a DIE in \a Unit. The
+ /// required strings will be interned in \a StringPool.
+ /// \returns The child DeclContext along with one bit that is set if
+ /// this context is invalid.
+ /// FIXME: the invalid bit along the return value is to emulate some
+ /// dsymutil-classic functionality. See the fucntion definition for
+ /// a more thorough discussion of its use.
+ PointerIntPair<DeclContext *, 1>
+ getChildDeclContext(DeclContext &Context,
+ const DWARFDebugInfoEntryMinimal *DIE, CompileUnit &Unit,
+ NonRelocatableStringpool &StringPool);
+
+ DeclContext &getRoot() { return Root; }
+};
+
/// \brief Stores all information relating to a compile unit, be it in
/// its original instance in the object file to its brand new cloned
/// and linked DIE tree.
/// \brief Information gathered about a DIE in the object file.
struct DIEInfo {
int64_t AddrAdjust; ///< Address offset to apply to the described entity.
+ DeclContext *Ctxt; ///< ODR Declaration context.
DIE *Clone; ///< Cloned version of that DIE.
uint32_t ParentIdx; ///< The index of this DIE's parent.
bool Keep; ///< Is the DIE part of the linked output?
bool InDebugMap; ///< Was this DIE's entity found in the map?
};
- CompileUnit(DWARFUnit &OrigUnit, unsigned ID)
+ CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR)
: OrigUnit(OrigUnit), ID(ID), LowPc(UINT64_MAX), HighPc(0), RangeAlloc(),
Ranges(RangeAlloc) {
Info.resize(OrigUnit.getNumDIEs());
+
+ const auto *CUDie = OrigUnit.getUnitDIE(false);
+ unsigned Lang = CUDie->getAttributeValueAsUnsignedConstant(
+ &OrigUnit, dwarf::DW_AT_language, 0);
+ HasODR = CanUseODR && (Lang == dwarf::DW_LANG_C_plus_plus ||
+ Lang == dwarf::DW_LANG_C_plus_plus_03 ||
+ Lang == dwarf::DW_LANG_C_plus_plus_11 ||
+ Lang == dwarf::DW_LANG_C_plus_plus_14 ||
+ Lang == dwarf::DW_LANG_ObjC_plus_plus);
}
CompileUnit(CompileUnit &&RHS)
DIE *getOutputUnitDIE() const { return CUDie; }
void setOutputUnitDIE(DIE *Die) { CUDie = Die; }
+ bool hasODR() const { return HasODR; }
+
DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; }
/// \brief Keep track of a forward reference to DIE \p Die in \p
/// RefUnit by \p Attr. The attribute should be fixed up later to
- /// point to the absolute offset of \p Die in the debug_info section.
+ /// point to the absolute offset of \p Die in the debug_info section
+ /// or to the canonical offset of \p Ctxt if it is non-null.
void noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
- PatchLocation Attr);
+ DeclContext *Ctxt, PatchLocation Attr);
/// \brief Apply all fixups recored by noteForwardReference().
void fixupForwardReferences();
const std::vector<AccelInfo> &getPubnames() const { return Pubnames; }
const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; }
+ /// Get the full path for file \a FileNum in the line table
+ const char *getResolvedPath(unsigned FileNum) {
+ if (FileNum >= ResolvedPaths.size())
+ return nullptr;
+ return ResolvedPaths[FileNum].size() ? ResolvedPaths[FileNum].c_str()
+ : nullptr;
+ }
+
+ /// Set the fully resolved path for the line-table's file \a FileNum
+ /// to \a Path.
+ void setResolvedPath(unsigned FileNum, const std::string &Path) {
+ if (ResolvedPaths.size() <= FileNum)
+ ResolvedPaths.resize(FileNum + 1);
+ ResolvedPaths[FileNum] = Path;
+ }
+
private:
DWARFUnit &OrigUnit;
unsigned ID;
- std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
- DIE *CUDie; ///< Root of the linked DIE tree.
+ std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
+ DIE *CUDie; ///< Root of the linked DIE tree.
uint64_t StartOffset;
uint64_t NextUnitOffset;
/// The offsets for the attributes in this array couldn't be set while
/// cloning because for cross-cu forward refences the target DIE's
/// offset isn't known you emit the reference attribute.
- std::vector<std::tuple<DIE *, const CompileUnit *, PatchLocation>>
- ForwardDIEReferences;
+ std::vector<std::tuple<DIE *, const CompileUnit *, DeclContext *,
+ PatchLocation>> ForwardDIEReferences;
FunctionIntervals::Allocator RangeAlloc;
/// \brief The ranges in that interval map are the PC ranges for
std::vector<AccelInfo> Pubnames;
std::vector<AccelInfo> Pubtypes;
/// @}
+
+ /// Cached resolved paths from the line table.
+ std::vector<std::string> ResolvedPaths;
+
+ /// Is this unit subject to the ODR rule?
+ bool HasODR;
};
uint64_t CompileUnit::computeNextUnitOffset() {
/// \brief Keep track of a forward cross-cu reference from this unit
/// to \p Die that lives in \p RefUnit.
void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
- PatchLocation Attr) {
- ForwardDIEReferences.emplace_back(Die, RefUnit, Attr);
+ DeclContext *Ctxt, PatchLocation Attr) {
+ ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr);
}
/// \brief Apply all fixups recorded by noteForwardReference().
DIE *RefDie;
const CompileUnit *RefUnit;
PatchLocation Attr;
- std::tie(RefDie, RefUnit, Attr) = Ref;
- Attr.set(RefDie->getOffset() + RefUnit->getStartOffset());
+ DeclContext *Ctxt;
+ std::tie(RefDie, RefUnit, Ctxt, Attr) = Ref;
+ if (Ctxt && Ctxt->getCanonicalDIEOffset())
+ Attr.set(Ctxt->getCanonicalDIEOffset());
+ else
+ Attr.set(RefDie->getOffset() + RefUnit->getStartOffset());
}
}
/// one.
uint32_t getStringOffset(StringRef S);
+ /// \brief Get permanent storage for \p S (but do not necessarily
+ /// emit \p S in the output section).
+ /// \returns The StringRef that points to permanent storage to use
+ /// in place of \p S.
+ StringRef internString(StringRef S);
+
// \brief Return the first entry of the string table.
const MapTy::MapEntryTy *getFirstEntry() const {
return getNextEntry(&Sentinel);
return It->getValue().first;
}
+/// \brief Put \p S into the StringMap so that it gets permanent
+/// storage, but do not actually link it in the chain of elements
+/// that go into the output section. A latter call to
+/// getStringOffset() with the same string will chain it though.
+StringRef NonRelocatableStringpool::internString(StringRef S) {
+ std::pair<uint32_t, StringMapEntryBase *> Entry(0, nullptr);
+ auto InsertResult = Strings.insert(std::make_pair(S, Entry));
+ return InsertResult.first->getKey();
+};
+
/// \brief The Dwarf streaming logic
///
/// All interactions with the MC layer that is used to build the debug
TF_InFunctionScope = 1 << 1, ///< Current scope is a fucntion scope.
TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE.
TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE.
+ TF_ODR = 1 << 4, ///< Use the ODR whhile keeping dependants.
};
/// \brief Mark the passed DIE as well as all the ones it depends on
void keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE,
CompileUnit::DIEInfo &MyInfo,
const DebugMapObject &DMO, CompileUnit &CU,
- unsigned Flags);
+ bool UseODR);
unsigned shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE,
CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo,
BumpPtrAllocator DIEAlloc;
/// @}
+ /// ODR Contexts for that link.
+ DeclContextTree ODRContexts;
+
/// \defgroup Helpers Various helper methods.
///
/// @{
const DWARFDebugInfoEntryMinimal *
- resolveDIEReference(DWARFFormValue &RefValue, const DWARFUnit &Unit,
+ resolveDIEReference(const DWARFFormValue &RefValue, const DWARFUnit &Unit,
const DWARFDebugInfoEntryMinimal &DIE,
CompileUnit *&ReferencedCU);
/// CompileUnit which is stored into \p ReferencedCU.
/// \returns null if resolving fails for any reason.
const DWARFDebugInfoEntryMinimal *DwarfLinker::resolveDIEReference(
- DWARFFormValue &RefValue, const DWARFUnit &Unit,
+ const DWARFFormValue &RefValue, const DWARFUnit &Unit,
const DWARFDebugInfoEntryMinimal &DIE, CompileUnit *&RefCU) {
assert(RefValue.isFormClass(DWARFFormValue::FC_Reference));
uint64_t RefOffset = *RefValue.getAsReference(&Unit);
return nullptr;
}
+/// \returns whether the passed \a Attr type might contain a DIE
+/// reference suitable for ODR uniquing.
+static bool isODRAttribute(uint16_t Attr) {
+ switch (Attr) {
+ default:
+ return false;
+ case dwarf::DW_AT_type:
+ case dwarf::DW_AT_containing_type:
+ case dwarf::DW_AT_specification:
+ case dwarf::DW_AT_abstract_origin:
+ case dwarf::DW_AT_import:
+ return true;
+ }
+ llvm_unreachable("Improper attribute.");
+}
+
+/// Set the last DIE/CU a context was seen in and, possibly invalidate
+/// the context if it is ambiguous.
+///
+/// In the current implementation, we don't handle overloaded
+/// functions well, because the argument types are not taken into
+/// account when computing the DeclContext tree.
+///
+/// Some of this is mitigated byt using mangled names that do contain
+/// the arguments types, but sometimes (eg. with function templates)
+/// we don't have that. In that case, just do not unique anything that
+/// refers to the contexts we are not able to distinguish.
+///
+/// If a context that is not a namespace appears twice in the same CU,
+/// we know it is ambiguous. Make it invalid.
+bool DeclContext::setLastSeenDIE(CompileUnit &U,
+ const DWARFDebugInfoEntryMinimal *Die) {
+ if (LastSeenCompileUnitID == U.getUniqueID()) {
+ DWARFUnit &OrigUnit = U.getOrigUnit();
+ uint32_t FirstIdx = OrigUnit.getDIEIndex(LastSeenDIE);
+ U.getInfo(FirstIdx).Ctxt = nullptr;
+ return false;
+ }
+
+ LastSeenCompileUnitID = U.getUniqueID();
+ LastSeenDIE = Die;
+ return true;
+}
+
+/// Get the child context of \a Context corresponding to \a DIE.
+///
+/// \returns the child context or null if we shouldn't track children
+/// contexts. It also returns an additional bit meaning 'invalid'. An
+/// invalid context means it shouldn't be considered for uniquing, but
+/// its not returning null, because some children of that context
+/// might be uniquing candidates.
+/// FIXME: this is for dsymutil-classic compatibility, I don't think
+/// it buys us much.
+PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
+ DeclContext &Context, const DWARFDebugInfoEntryMinimal *DIE, CompileUnit &U,
+ NonRelocatableStringpool &StringPool) {
+ unsigned Tag = DIE->getTag();
+
+ // FIXME: dsymutil-classic compat: We should bail out here if we
+ // have a specification or an abstract_origin. We will get the
+ // parent context wrong here.
+
+ switch (Tag) {
+ default:
+ // By default stop gathering child contexts.
+ return PointerIntPair<DeclContext *, 1>(nullptr);
+ case dwarf::DW_TAG_compile_unit:
+ // FIXME: Add support for DW_TAG_module.
+ return PointerIntPair<DeclContext *, 1>(&Context);
+ case dwarf::DW_TAG_subprogram:
+ // Do not unique anything inside CU local functions.
+ if ((Context.getTag() == dwarf::DW_TAG_namespace ||
+ Context.getTag() == dwarf::DW_TAG_compile_unit) &&
+ !DIE->getAttributeValueAsUnsignedConstant(&U.getOrigUnit(),
+ dwarf::DW_AT_external, 0))
+ return PointerIntPair<DeclContext *, 1>(nullptr);
+ // Fallthrough
+ case dwarf::DW_TAG_member:
+ case dwarf::DW_TAG_namespace:
+ case dwarf::DW_TAG_structure_type:
+ case dwarf::DW_TAG_class_type:
+ case dwarf::DW_TAG_union_type:
+ case dwarf::DW_TAG_enumeration_type:
+ case dwarf::DW_TAG_typedef:
+ // Artificial things might be ambiguous, because they might be
+ // created on demand. For example implicitely defined constructors
+ // are ambiguous because of the way we identify contexts, and they
+ // won't be generated everytime everywhere.
+ if (DIE->getAttributeValueAsUnsignedConstant(&U.getOrigUnit(),
+ dwarf::DW_AT_artificial, 0))
+ return PointerIntPair<DeclContext *, 1>(nullptr);
+ break;
+ }
+
+ const char *Name = DIE->getName(&U.getOrigUnit(), DINameKind::LinkageName);
+ const char *ShortName = DIE->getName(&U.getOrigUnit(), DINameKind::ShortName);
+ StringRef NameRef;
+ StringRef ShortNameRef;
+ StringRef FileRef;
+
+ if (Name)
+ NameRef = StringPool.internString(Name);
+ else if (Tag == dwarf::DW_TAG_namespace)
+ // FIXME: For dsymutil-classic compatibility. I think uniquing
+ // within anonymous namespaces is wrong. There is no ODR guarantee
+ // there.
+ NameRef = StringPool.internString("(anonymous namespace)");
+
+ if (ShortName && ShortName != Name)
+ ShortNameRef = StringPool.internString(ShortName);
+ else
+ ShortNameRef = NameRef;
+
+ if (Tag != dwarf::DW_TAG_class_type && Tag != dwarf::DW_TAG_structure_type &&
+ Tag != dwarf::DW_TAG_union_type &&
+ Tag != dwarf::DW_TAG_enumeration_type && NameRef.empty())
+ return PointerIntPair<DeclContext *, 1>(nullptr);
+
+ std::string File;
+ unsigned Line = 0;
+ unsigned ByteSize = 0;
+
+ // Gather some discriminating data about the DeclContext we will be
+ // creating: File, line number and byte size. This shouldn't be
+ // necessary, because the ODR is just about names, but given that we
+ // do some approximations with overloaded functions and anonymous
+ // namespaces, use these additional data points to make the process safer.
+ ByteSize = DIE->getAttributeValueAsUnsignedConstant(
+ &U.getOrigUnit(), dwarf::DW_AT_byte_size, UINT64_MAX);
+ if (Tag != dwarf::DW_TAG_namespace || !Name) {
+ if (unsigned FileNum = DIE->getAttributeValueAsUnsignedConstant(
+ &U.getOrigUnit(), dwarf::DW_AT_decl_file, 0)) {
+ if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit(
+ &U.getOrigUnit())) {
+ // FIXME: dsymutil-classic compatibility. I'd rather not
+ // unique anything in anonymous namespaces, but if we do, then
+ // verify that the file and line correspond.
+ if (!Name && Tag == dwarf::DW_TAG_namespace)
+ FileNum = 1;
+
+ // FIXME: Passing U.getOrigUnit().getCompilationDir()
+ // instead of "" would allow more uniquing, but for now, do
+ // it this way to match dsymutil-classic.
+ if (LT->getFileNameByIndex(
+ FileNum, "",
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
+ File)) {
+ Line = DIE->getAttributeValueAsUnsignedConstant(
+ &U.getOrigUnit(), dwarf::DW_AT_decl_line, 0);
+#ifdef HAVE_REALPATH
+ // Cache the resolved paths, because calling realpath is expansive.
+ if (const char *ResolvedPath = U.getResolvedPath(FileNum)) {
+ File = ResolvedPath;
+ } else {
+ char RealPath[PATH_MAX + 1];
+ RealPath[PATH_MAX] = 0;
+ if (::realpath(File.c_str(), RealPath))
+ File = RealPath;
+ U.setResolvedPath(FileNum, File);
+ }
+#endif
+ FileRef = StringPool.internString(File);
+ }
+ }
+ }
+ }
+
+ if (!Line && NameRef.empty())
+ return PointerIntPair<DeclContext *, 1>(nullptr);
+
+ // FIXME: dsymutil-classic compat won't unique the same type
+ // presented once as a struct and once as a class. Use the Tag in
+ // the fully qualified name hash to get the same effect.
+ // We hash NameRef, which is the mangled name, in order to get most
+ // overloaded functions resolvec correctly.
+ unsigned Hash = hash_combine(Context.getQualifiedNameHash(), Tag, NameRef);
+
+ // FIXME: dsymutil-classic compatibility: when we don't have a name,
+ // use the filename.
+ if (Tag == dwarf::DW_TAG_namespace && NameRef == "(anonymous namespace)")
+ Hash = hash_combine(Hash, FileRef);
+
+ // Now look if this context already exists.
+ DeclContext Key(Hash, Line, ByteSize, Tag, NameRef, FileRef, Context);
+ auto ContextIter = Contexts.find(&Key);
+
+ if (ContextIter == Contexts.end()) {
+ // The context wasn't found.
+ bool Inserted;
+ DeclContext *NewContext =
+ new (Allocator) DeclContext(Hash, Line, ByteSize, Tag, NameRef, FileRef,
+ Context, DIE, U.getUniqueID());
+ std::tie(ContextIter, Inserted) = Contexts.insert(NewContext);
+ assert(Inserted && "Failed to insert DeclContext");
+ (void)Inserted;
+ } else if (Tag != dwarf::DW_TAG_namespace &&
+ !(*ContextIter)->setLastSeenDIE(U, DIE)) {
+ // The context was found, but it is ambiguous with another context
+ // in the same file. Mark it invalid.
+ return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1);
+ }
+
+ assert(ContextIter != Contexts.end());
+ // FIXME: dsymutil-classic compatibility. Union types aren't
+ // uniques, but their children might be.
+ if ((Tag == dwarf::DW_TAG_subprogram &&
+ Context.getTag() != dwarf::DW_TAG_structure_type &&
+ Context.getTag() != dwarf::DW_TAG_class_type) ||
+ (Tag == dwarf::DW_TAG_union_type))
+ return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1);
+
+ return PointerIntPair<DeclContext *, 1>(*ContextIter);
+}
+
/// \brief Get the potential name and mangled name for the entity
/// described by \p Die and store them in \Info if they are not
/// already there.
/// \brief Recursive helper to gather the child->parent relationships in the
/// original compile unit.
static void gatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE,
- unsigned ParentIdx, CompileUnit &CU) {
+ unsigned ParentIdx, CompileUnit &CU,
+ DeclContext *CurrentDeclContext,
+ NonRelocatableStringpool &StringPool,
+ DeclContextTree &Contexts) {
unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE);
- CU.getInfo(MyIdx).ParentIdx = ParentIdx;
+ CompileUnit::DIEInfo &Info = CU.getInfo(MyIdx);
+
+ Info.ParentIdx = ParentIdx;
+ if (CU.hasODR()) {
+ if (CurrentDeclContext) {
+ auto PtrInvalidPair = Contexts.getChildDeclContext(*CurrentDeclContext,
+ DIE, CU, StringPool);
+ CurrentDeclContext = PtrInvalidPair.getPointer();
+ Info.Ctxt =
+ PtrInvalidPair.getInt() ? nullptr : PtrInvalidPair.getPointer();
+ } else
+ Info.Ctxt = CurrentDeclContext = nullptr;
+ }
if (DIE->hasChildren())
for (auto *Child = DIE->getFirstChild(); Child && !Child->isNULL();
Child = Child->getSibling())
- gatherDIEParents(Child, MyIdx, CU);
+ gatherDIEParents(Child, MyIdx, CU, CurrentDeclContext, StringPool,
+ Contexts);
}
static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) {
llvm_unreachable("Invalid Tag");
}
+static unsigned getRefAddrSize(const DWARFUnit &U) {
+ if (U.getVersion() == 2)
+ return U.getAddressByteSize();
+ return 4;
+}
+
void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject &Obj) {
Units.reserve(Dwarf.getNumCompileUnits());
NextValidReloc = 0;
void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE,
CompileUnit::DIEInfo &MyInfo,
const DebugMapObject &DMO,
- CompileUnit &CU, unsigned Flags) {
+ CompileUnit &CU, bool UseODR) {
const DWARFUnit &Unit = CU.getOrigUnit();
MyInfo.Keep = true;
// First mark all the parent chain as kept.
unsigned AncestorIdx = MyInfo.ParentIdx;
while (!CU.getInfo(AncestorIdx).Keep) {
+ unsigned ODRFlag = UseODR ? TF_ODR : 0;
lookForDIEsToKeep(*Unit.getDIEAtIndex(AncestorIdx), DMO, CU,
- TF_ParentWalk | TF_Keep | TF_DependencyWalk);
+ TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag);
AncestorIdx = CU.getInfo(AncestorIdx).ParentIdx;
}
Val.extractValue(Data, &Offset, &Unit);
CompileUnit *ReferencedCU;
- if (const auto *RefDIE = resolveDIEReference(Val, Unit, DIE, ReferencedCU))
+ if (const auto *RefDIE =
+ resolveDIEReference(Val, Unit, DIE, ReferencedCU)) {
+ uint32_t RefIdx = ReferencedCU->getOrigUnit().getDIEIndex(RefDIE);
+ CompileUnit::DIEInfo &Info = ReferencedCU->getInfo(RefIdx);
+ // If the referenced DIE has a DeclContext that has already been
+ // emitted, then do not keep the one in this CU. We'll link to
+ // the canonical DIE in cloneDieReferenceAttribute.
+ // FIXME: compatibility with dsymutil-classic. UseODR shouldn't
+ // be necessary and could be advantageously replaced by
+ // ReferencedCU->hasODR() && CU.hasODR().
+ // FIXME: compatibility with dsymutil-classic. There is no
+ // reason not to unique ref_addr references.
+ if (AttrSpec.Form != dwarf::DW_FORM_ref_addr && UseODR && Info.Ctxt &&
+ Info.Ctxt != ReferencedCU->getInfo(Info.ParentIdx).Ctxt &&
+ Info.Ctxt->getCanonicalDIEOffset() && isODRAttribute(AttrSpec.Attr))
+ continue;
+
+ unsigned ODRFlag = UseODR ? TF_ODR : 0;
lookForDIEsToKeep(*RefDIE, DMO, *ReferencedCU,
- TF_Keep | TF_DependencyWalk);
+ TF_Keep | TF_DependencyWalk | ODRFlag);
+ }
}
}
Flags = shouldKeepDIE(DIE, CU, MyInfo, Flags);
// If it is a newly kept DIE mark it as well as all its dependencies as kept.
- if (!AlreadyKept && (Flags & TF_Keep))
- keepDIEAndDenpendencies(DIE, MyInfo, DMO, CU, Flags);
-
+ if (!AlreadyKept && (Flags & TF_Keep)) {
+ bool UseOdr = (Flags & TF_DependencyWalk) ? (Flags & TF_ODR) : CU.hasODR();
+ keepDIEAndDenpendencies(DIE, MyInfo, DMO, CU, UseOdr);
+ }
// The TF_ParentWalk flag tells us that we are currently walking up
// the parent chain of a required DIE, and we don't want to mark all
// the children of the parents as kept (consider for example a
DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE,
AttributeSpec AttrSpec, unsigned AttrSize, const DWARFFormValue &Val,
CompileUnit &Unit) {
- uint32_t Ref = *Val.getAsReference(&Unit.getOrigUnit());
+ const DWARFUnit &U = Unit.getOrigUnit();
+ uint32_t Ref = *Val.getAsReference(&U);
DIE *NewRefDie = nullptr;
CompileUnit *RefUnit = nullptr;
- const DWARFDebugInfoEntryMinimal *RefDie = nullptr;
-
- if (!(RefUnit = getUnitForOffset(Ref)) ||
- !(RefDie = RefUnit->getOrigUnit().getDIEForOffset(Ref))) {
- const char *AttributeString = dwarf::AttributeString(AttrSpec.Attr);
- if (!AttributeString)
- AttributeString = "DW_AT_???";
- reportWarning(Twine("Missing DIE for ref in attribute ") + AttributeString +
- ". Dropping.",
- &Unit.getOrigUnit(), &InputDIE);
+ DeclContext *Ctxt = nullptr;
+
+ const DWARFDebugInfoEntryMinimal *RefDie =
+ resolveDIEReference(Val, U, InputDIE, RefUnit);
+
+ // If the referenced DIE is not found, drop the attribute.
+ if (!RefDie)
return 0;
- }
unsigned Idx = RefUnit->getOrigUnit().getDIEIndex(RefDie);
CompileUnit::DIEInfo &RefInfo = RefUnit->getInfo(Idx);
+
+ // If we already have emitted an equivalent DeclContext, just point
+ // at it.
+ if (isODRAttribute(AttrSpec.Attr)) {
+ Ctxt = RefInfo.Ctxt;
+ if (Ctxt && Ctxt->getCanonicalDIEOffset()) {
+ DIEInteger Attr(Ctxt->getCanonicalDIEOffset());
+ Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
+ dwarf::DW_FORM_ref_addr, Attr);
+ return getRefAddrSize(U);
+ }
+ }
+
if (!RefInfo.Clone) {
assert(Ref > InputDIE.getOffset());
// We haven't cloned this DIE yet. Just create an empty one and
}
NewRefDie = RefInfo.Clone;
- if (AttrSpec.Form == dwarf::DW_FORM_ref_addr) {
+ if (AttrSpec.Form == dwarf::DW_FORM_ref_addr ||
+ (Unit.hasODR() && isODRAttribute(AttrSpec.Attr))) {
// We cannot currently rely on a DIEEntry to emit ref_addr
// references, because the implementation calls back to DwarfDebug
// to find the unit offset. (We don't have a DwarfDebug)
// A forward reference. Note and fixup later.
Attr = 0xBADDEF;
Unit.noteForwardReference(
- NewRefDie, RefUnit,
+ NewRefDie, RefUnit, Ctxt,
Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
dwarf::DW_FORM_ref_addr, DIEInteger(Attr)));
}
- return AttrSize;
+ return getRefAddrSize(U);
}
Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
Die = Info.Clone = DIE::get(DIEAlloc, dwarf::Tag(InputDIE.getTag()));
assert(Die->getTag() == InputDIE.getTag());
Die->setOffset(OutOffset);
+ if (Unit.hasODR() && Die->getTag() != dwarf::DW_TAG_namespace && Info.Ctxt &&
+ Info.Ctxt != Unit.getInfo(Info.ParentIdx).Ctxt &&
+ !Info.Ctxt->getCanonicalDIEOffset()) {
+ // We are about to emit a DIE that is the root of its own valid
+ // DeclContext tree. Make the current offset the canonical offset
+ // for this context.
+ Info.Ctxt->setCanonicalDIEOffset(OutOffset + Unit.getStartOffset());
+ }
// Extract and clone every attribute.
DataExtractor Data = U.getDebugInfoExtractor();
outs() << "Input compilation unit:";
CUDie->dump(outs(), CU.get(), 0);
}
- Units.emplace_back(*CU, UnitID++);
- gatherDIEParents(CUDie, 0, Units.back());
+ Units.emplace_back(*CU, UnitID++, !Options.NoODR);
+ gatherDIEParents(CUDie, 0, Units.back(), &ODRContexts.getRoot(),
+ StringPool, ODRContexts);
}
// Then mark all the DIEs that need to be present in the linked
desc("Do the link in memory, but do not emit the result file."),
init(false));
+static opt<bool>
+ NoODR("no-odr",
+ desc("Do not use ODR (One Definition Rule) for type uniquing."),
+ init(false));
+
static opt<bool> DumpDebugMap(
"dump-debug-map",
desc("Parse and dump the debug map to standard output. Not DWARF link "
Options.Verbose = Verbose;
Options.NoOutput = NoOutput;
+ Options.NoODR = NoODR;
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
struct LinkOptions {
bool Verbose; ///< Verbosity
bool NoOutput; ///< Skip emitting output
+ bool NoODR; ///< Do not unique types according to ODR
LinkOptions() : Verbose(false), NoOutput(false) {}
};