Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -1791,8 +1791,17 @@ switch (TA.getKind()) { case TemplateArgument::Type: { llvm::DIType *TTy = getOrCreateType(TA.getAsType(), Unit); - TemplateParams.push_back( - DBuilder.createTemplateTypeParameter(TheCU, Name, TTy)); + bool defaultParameter = false; + if (TPList) + if (auto *templateType = + dyn_cast_or_null(TPList->getParam(i))) + if (templateType->hasDefaultArgument()) + defaultParameter = + templateType->getDefaultArgument() == TA.getAsType(); + + TemplateParams.push_back(DBuilder.createTemplateTypeParameter( + TheCU, Name, TTy, defaultParameter)); + } break; case TemplateArgument::Integral: { llvm::DIType *TTy = getOrCreateType(TA.getIntegralType(), Unit); Index: clang/test/CodeGenCXX/debug-info-template-parameter.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/debug-info-template-parameter.cpp @@ -0,0 +1,34 @@ +// Test for DebugInfo for Defaulted parameters for C++ templates +// Supported: -O0, standalone DI + +// RUN: %clang_cc1 -dwarf-version=5 -emit-llvm -triple x86_64-linux-gnu %s -o - \ +// RUN: -O0 -disable-llvm-passes \ +// RUN: -debug-info-kind=standalone \ +// RUN: | FileCheck %s + +// CHECK: DILocalVariable(name: "f1", {{.*}}, type: ![[TEMPLATE_TYPE:[0-9]+]] +// CHECK: [[TEMPLATE_TYPE]] = {{.*}}!DICompositeType({{.*}}, templateParams: ![[F1_TYPE:[0-9]+]] +// CHECK: [[F1_TYPE]] = !{![[FIRST:[0-9]+]], ![[SECOND:[0-9]+]]} +// CHECK: [[FIRST]] = !DITemplateTypeParameter({{.*}}, defaultValue: false +// CHECK: [[SECOND]] = !DITemplateTypeParameter({{.*}}, defaultValue: true + +// CHECK: DILocalVariable(name: "f2", {{.*}}, type: ![[TEMPLATE_TYPE:[0-9]+]] +// CHECK: [[TEMPLATE_TYPE]] = {{.*}}!DICompositeType({{.*}}, templateParams: ![[F2_TYPE:[0-9]+]] +// CHECK: [[F2_TYPE]] = !{![[FIRST:[0-9]+]], ![[SECOND]]} +// CHECK: [[FIRST]] = !DITemplateTypeParameter({{.*}}, defaultValue: false + +// CHECK: DILocalVariable(name: "f3", {{.*}}, type: ![[TEMPLATE_TYPE:[0-9]+]] +// CHECK: [[TEMPLATE_TYPE]] = {{.*}}!DICompositeType({{.*}}, templateParams: ![[F3_TYPE:[0-9]+]] +// CHECK: [[F3_TYPE]] = !{![[FIRST:[0-9]+]], ![[SECOND]]} +// CHECK: [[FIRST]] = !DITemplateTypeParameter({{.*}}, defaultValue: true + +template +class foo { +}; + +int main() { + foo f1; + foo f2; + foo<> f3; + return 0; +} Index: llvm/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/include/llvm/IR/DIBuilder.h +++ llvm/include/llvm/IR/DIBuilder.h @@ -443,8 +443,11 @@ /// \param Scope Scope in which this type is defined. /// \param Name Type parameter name. /// \param Ty Parameter type. - DITemplateTypeParameter * - createTemplateTypeParameter(DIScope *Scope, StringRef Name, DIType *Ty); + /// \param isDefault Parameter is default or not + DITemplateTypeParameter *createTemplateTypeParameter(DIScope *Scope, + StringRef Name, + DIType *Ty, + bool isDefault); /// Create debugging information for template /// value parameter. Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2152,32 +2152,39 @@ class DITemplateTypeParameter : public DITemplateParameter { friend class LLVMContextImpl; friend class MDNode; + bool isDefault; DITemplateTypeParameter(LLVMContext &Context, StorageType Storage, - ArrayRef Ops) + bool isDefault, ArrayRef Ops) : DITemplateParameter(Context, DITemplateTypeParameterKind, Storage, - dwarf::DW_TAG_template_type_parameter, Ops) {} + dwarf::DW_TAG_template_type_parameter, Ops), + isDefault(isDefault) {} ~DITemplateTypeParameter() = default; static DITemplateTypeParameter *getImpl(LLVMContext &Context, StringRef Name, - DIType *Type, StorageType Storage, + DIType *Type, bool isDefault, + StorageType Storage, bool ShouldCreate = true) { - return getImpl(Context, getCanonicalMDString(Context, Name), Type, Storage, - ShouldCreate); + return getImpl(Context, getCanonicalMDString(Context, Name), Type, + isDefault, Storage, ShouldCreate); } static DITemplateTypeParameter *getImpl(LLVMContext &Context, MDString *Name, - Metadata *Type, StorageType Storage, + Metadata *Type, bool isDefault, + StorageType Storage, bool ShouldCreate = true); TempDITemplateTypeParameter cloneImpl() const { - return getTemporary(getContext(), getName(), getType()); + return getTemporary(getContext(), getName(), getType(), getDefault()); } public: - DEFINE_MDNODE_GET(DITemplateTypeParameter, (StringRef Name, DIType *Type), - (Name, Type)) - DEFINE_MDNODE_GET(DITemplateTypeParameter, (MDString * Name, Metadata *Type), - (Name, Type)) + bool getDefault() const { return isDefault; } + DEFINE_MDNODE_GET(DITemplateTypeParameter, + (StringRef Name, DIType *Type, bool isDefault), + (Name, Type, isDefault)) + DEFINE_MDNODE_GET(DITemplateTypeParameter, + (MDString * Name, Metadata *Type, bool isDefault), + (Name, Type, isDefault)) TempDITemplateTypeParameter clone() const { return cloneImpl(); } Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -4839,16 +4839,17 @@ } /// ParseDITemplateTypeParameter: -/// ::= !DITemplateTypeParameter(name: "Ty", type: !1) +/// ::= !DITemplateTypeParameter(name: "Ty", type: !1, defaultValue: "false") bool LLParser::ParseDITemplateTypeParameter(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ OPTIONAL(name, MDStringField, ); \ - REQUIRED(type, MDField, ); + REQUIRED(type, MDField, ); \ + OPTIONAL(defaultValue, MDBoolField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = - GET_OR_DISTINCT(DITemplateTypeParameter, (Context, name.Val, type.Val)); + Result = GET_OR_DISTINCT(DITemplateTypeParameter, + (Context, name.Val, type.Val, defaultValue.Val)); return false; } Index: llvm/lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1672,10 +1672,11 @@ return error("Invalid record"); IsDistinct = Record[0]; - MetadataList.assignValue(GET_OR_DISTINCT(DITemplateTypeParameter, - (Context, getMDString(Record[1]), - getDITypeRefOrNull(Record[2]))), - NextMetadataNo); + MetadataList.assignValue( + GET_OR_DISTINCT(DITemplateTypeParameter, + (Context, getMDString(Record[1]), + getDITypeRefOrNull(Record[2]), false)), + NextMetadataNo); NextMetadataNo++; break; } Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1791,6 +1791,9 @@ Record.push_back(VE.getMetadataOrNullID(N->getRawName())); Record.push_back(VE.getMetadataOrNullID(N->getType())); + if (M.getDwarfVersion() >= 5) + Record.push_back(N->getDefault()); + Stream.EmitRecord(bitc::METADATA_TEMPLATE_TYPE, Record, Abbrev); Record.clear(); } Index: llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1046,6 +1046,8 @@ addType(ParamDIE, TP->getType()); if (!TP->getName().empty()) addString(ParamDIE, dwarf::DW_AT_name, TP->getName()); + if (TP->getDefault() && (DD->getDwarfVersion() >= 5)) + addFlag(ParamDIE, dwarf::DW_AT_default_value); } void DwarfUnit::constructTemplateValueParameterDIE( Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -2071,6 +2071,8 @@ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); Printer.printString("name", N->getName()); Printer.printMetadata("type", N->getRawType(), /* ShouldSkipNull */ false); + if (Context->getDwarfVersion() >= 5) + Printer.printBool("defaultValue", N->getDefault()); Out << ")"; } Index: llvm/lib/IR/DIBuilder.cpp =================================================================== --- llvm/lib/IR/DIBuilder.cpp +++ llvm/lib/IR/DIBuilder.cpp @@ -406,9 +406,9 @@ DITemplateTypeParameter * DIBuilder::createTemplateTypeParameter(DIScope *Context, StringRef Name, - DIType *Ty) { + DIType *Ty, bool isDefault) { assert((!Context || isa(Context)) && "Expected compile unit"); - return DITemplateTypeParameter::get(VMContext, Name, Ty); + return DITemplateTypeParameter::get(VMContext, Name, Ty, isDefault); } static DITemplateValueParameter * Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -724,15 +724,14 @@ DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DIModule, Ops); } -DITemplateTypeParameter *DITemplateTypeParameter::getImpl(LLVMContext &Context, - MDString *Name, - Metadata *Type, - StorageType Storage, - bool ShouldCreate) { +DITemplateTypeParameter * +DITemplateTypeParameter::getImpl(LLVMContext &Context, MDString *Name, + Metadata *Type, bool isDefault, + StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DITemplateTypeParameter, (Name, Type)); + DEFINE_GETIMPL_LOOKUP(DITemplateTypeParameter, (Name, Type, isDefault)); Metadata *Ops[] = {Name, Type}; - DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DITemplateTypeParameter, Ops); + DEFINE_GETIMPL_STORE(DITemplateTypeParameter, (isDefault), Ops); } DITemplateValueParameter *DITemplateValueParameter::getImpl( Index: llvm/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/lib/IR/LLVMContextImpl.h +++ llvm/lib/IR/LLVMContextImpl.h @@ -843,16 +843,20 @@ template <> struct MDNodeKeyImpl { MDString *Name; Metadata *Type; + bool isDefault; - MDNodeKeyImpl(MDString *Name, Metadata *Type) : Name(Name), Type(Type) {} + MDNodeKeyImpl(MDString *Name, Metadata *Type, bool isDefault) + : Name(Name), Type(Type), isDefault(isDefault) {} MDNodeKeyImpl(const DITemplateTypeParameter *N) - : Name(N->getRawName()), Type(N->getRawType()) {} + : Name(N->getRawName()), Type(N->getRawType()), + isDefault(N->getDefault()) {} bool isKeyOf(const DITemplateTypeParameter *RHS) const { - return Name == RHS->getRawName() && Type == RHS->getRawType(); + return Name == RHS->getRawName() && Type == RHS->getRawType() && + isDefault == RHS->getDefault(); } - unsigned getHashValue() const { return hash_combine(Name, Type); } + unsigned getHashValue() const { return hash_combine(Name, Type, isDefault); } }; template <> struct MDNodeKeyImpl { Index: llvm/test/DebugInfo/X86/debug-info-template-parameter.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/debug-info-template-parameter.ll @@ -0,0 +1,106 @@ +; RUN: %llc_dwarf %s -filetype=obj -o - | llvm-dwarfdump -v - | FileCheck %s + +; C++ source to regenerate: + +;template +;class foo { +;}; +; +;int main() { +; foo f1; +; foo f2; +; foo<> f3; +; return 0; +;} + +; $ clang++ -O0 -g -gdwarf-5 debug-info-template-align.cpp -c + +; CHECK: .debug_abbrev contents: +; CHECK: DW_AT_default_value DW_FORM_flag_present + +; CHECK: DW_AT_name {{.*}} "foo" +; CHECK: DW_AT_type {{.*}} "int" +; CHECK-NEXT: DW_AT_name {{.*}} "T" +; CHECK-NOT: DW_AT_default_value +; CHECK: DW_AT_type {{.*}} "int" +; CHECK-NEXT: DW_AT_name {{.*}} "T1" +; CHECK-NEXT: DW_AT_default_value {{.*}} (true) + +; CHECK: DW_AT_name {{.*}} "foo" +; CHECK: DW_AT_type {{.*}} "float" +; CHECK-NEXT: DW_AT_name {{.*}} "T" +; CHECK-NOT: DW_AT_default_value +; CHECK: DW_AT_type {{.*}} "int" +; CHECK-NEXT: DW_AT_name {{.*}} "T1" +; CHECK-NEXT: DW_AT_default_value {{.*}} (true) + +; CHECK: DW_AT_name {{.*}} "foo" +; CHECK: DW_AT_type {{.*}} "char" +; CHECK-NEXT: DW_AT_name {{.*}} "T" +; CHECK-NEXT: DW_AT_default_value {{.*}} (true) +; CHECK: DW_AT_type {{.*}} "int" +; CHECK-NEXT: DW_AT_name {{.*}} "T1" +; CHECK-NEXT: DW_AT_default_value {{.*}} (true) +; ModuleID = '/dir/test.cpp' +source_filename = "/dir/test.cpp" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%class.foo = type { i8 } +%class.foo.0 = type { i8 } +%class.foo.1 = type { i8 } + +; Function Attrs: noinline norecurse nounwind optnone uwtable +define dso_local i32 @main() #0 !dbg !7 { +entry: + %retval = alloca i32, align 4 + %f1 = alloca %class.foo, align 1 + %f2 = alloca %class.foo.0, align 1 + %f3 = alloca %class.foo.1, align 1 + store i32 0, i32* %retval, align 4 + call void @llvm.dbg.declare(metadata %class.foo* %f1, metadata !11, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.declare(metadata %class.foo.0* %f2, metadata !17, metadata !DIExpression()), !dbg !22 + call void @llvm.dbg.declare(metadata %class.foo.1* %f3, metadata !23, metadata !DIExpression()), !dbg !28 + ret i32 0, !dbg !29 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline norecurse nounwind optnone uwtable } +attributes #1 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 10.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "/dir/test.cpp", directory: "/dir", checksumkind: CSK_MD5, checksum: "11533ce33efb90b452039ec33aaba3dd") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 5} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0"} +!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 15, type: !8, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocalVariable(name: "f1", scope: !7, file: !1, line: 16, type: !12) +!12 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "foo", file: !1, line: 12, size: 8, flags: DIFlagTypePassByValue, elements: !2, templateParams: !13, identifier: "_ZTS3fooIiiE") +!13 = !{!14, !15} +!14 = !DITemplateTypeParameter(name: "T", type: !10, default_value: false) +!15 = !DITemplateTypeParameter(name: "T1", type: !10, default_value: true) +!16 = !DILocation(line: 16, column: 12, scope: !7) +!17 = !DILocalVariable(name: "f2", scope: !7, file: !1, line: 17, type: !18) +!18 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "foo", file: !1, line: 12, size: 8, flags: DIFlagTypePassByValue, elements: !2, templateParams: !19, identifier: "_ZTS3fooIfiE") +!19 = !{!20, !15} +!20 = !DITemplateTypeParameter(name: "T", type: !21, default_value: false) +!21 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!22 = !DILocation(line: 17, column: 14, scope: !7) +!23 = !DILocalVariable(name: "f3", scope: !7, file: !1, line: 18, type: !24) +!24 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "foo", file: !1, line: 12, size: 8, flags: DIFlagTypePassByValue, elements: !2, templateParams: !25, identifier: "_ZTS3fooIciE") +!25 = !{!26, !15} +!26 = !DITemplateTypeParameter(name: "T", type: !27, default_value: true) +!27 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!28 = !DILocation(line: 18, column: 9, scope: !7) +!29 = !DILocation(line: 19, column: 3, scope: !7) Index: llvm/unittests/IR/MetadataTest.cpp =================================================================== --- llvm/unittests/IR/MetadataTest.cpp +++ llvm/unittests/IR/MetadataTest.cpp @@ -2077,16 +2077,16 @@ StringRef Name = "template"; DIType *Type = getBasicType("basic"); - auto *N = DITemplateTypeParameter::get(Context, Name, Type); + auto *N = DITemplateTypeParameter::get(Context, Name, Type, false); EXPECT_EQ(dwarf::DW_TAG_template_type_parameter, N->getTag()); EXPECT_EQ(Name, N->getName()); EXPECT_EQ(Type, N->getType()); - EXPECT_EQ(N, DITemplateTypeParameter::get(Context, Name, Type)); + EXPECT_EQ(N, DITemplateTypeParameter::get(Context, Name, Type, false)); - EXPECT_NE(N, DITemplateTypeParameter::get(Context, "other", Type)); - EXPECT_NE(N, - DITemplateTypeParameter::get(Context, Name, getBasicType("other"))); + EXPECT_NE(N, DITemplateTypeParameter::get(Context, "other", Type, false)); + EXPECT_NE(N, DITemplateTypeParameter::get(Context, Name, + getBasicType("other"), false)); TempDITemplateTypeParameter Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));