Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -1786,18 +1786,36 @@ for (unsigned i = 0, e = TAList.size(); i != e; ++i) { const TemplateArgument &TA = TAList[i]; StringRef Name; + bool defaultParameter = false; if (TPList) Name = TPList->getParam(i)->getName(); switch (TA.getKind()) { case TemplateArgument::Type: { llvm::DIType *TTy = getOrCreateType(TA.getAsType(), Unit); - TemplateParams.push_back( - DBuilder.createTemplateTypeParameter(TheCU, Name, TTy)); + + 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); + if (TPList) + if (auto *templateType = + dyn_cast_or_null(TPList->getParam(i))) + if (templateType->hasDefaultArgument()) + defaultParameter = + templateType->getDefaultArgument()->EvaluateKnownConstInt( + CGM.getContext()) == TA.getAsIntegral(); + TemplateParams.push_back(DBuilder.createTemplateValueParameter( - TheCU, Name, TTy, + TheCU, Name, TTy, defaultParameter, llvm::ConstantInt::get(CGM.getLLVMContext(), TA.getAsIntegral()))); } break; case TemplateArgument::Declaration: { @@ -1836,7 +1854,7 @@ V = V->stripPointerCasts(); } TemplateParams.push_back(DBuilder.createTemplateValueParameter( - TheCU, Name, TTy, cast_or_null(V))); + TheCU, Name, TTy, defaultParameter, cast_or_null(V))); } break; case TemplateArgument::NullPtr: { QualType T = TA.getNullPtrType(); @@ -1854,8 +1872,8 @@ V = CGM.getCXXABI().EmitNullMemberPointer(MPT); if (!V) V = llvm::ConstantInt::get(CGM.Int8Ty, 0); - TemplateParams.push_back( - DBuilder.createTemplateValueParameter(TheCU, Name, TTy, V)); + TemplateParams.push_back(DBuilder.createTemplateValueParameter( + TheCU, Name, TTy, defaultParameter, V)); } break; case TemplateArgument::Template: TemplateParams.push_back(DBuilder.createTemplateTemplateParameter( @@ -1876,7 +1894,7 @@ assert(V && "Expression in template argument isn't constant"); llvm::DIType *TTy = getOrCreateType(T, Unit); TemplateParams.push_back(DBuilder.createTemplateValueParameter( - TheCU, Name, TTy, V->stripPointerCasts())); + TheCU, Name, TTy, defaultParameter, V->stripPointerCasts())); } break; // And the following should never occur: case TemplateArgument::TemplateExpansion: Index: clang/test/CodeGenCXX/debug-info-template-parameter.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/debug-info-template-parameter.cpp @@ -0,0 +1,30 @@ +// 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(name: "T", type: !{{[0-9]*}}) +// CHECK: [[SECOND]] = !DITemplateValueParameter(name: "i", type: !{{[0-9]*}}, value: i32 6) + +// 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:[0-9]+]]} +// CHECK: [[FIRST]] = !DITemplateTypeParameter(name: "T", type: !{{[0-9]*}}, defaulted: true) +// CHECK: [[SECOND]] = !DITemplateValueParameter(name: "i", type: !{{[0-9]*}}, defaulted: true, value: i32 3) + + +template +class foo { +}; + +int main() { + foo f1; + foo<> f2; + return 0; +} Index: llvm/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/include/llvm/IR/DIBuilder.h +++ llvm/include/llvm/IR/DIBuilder.h @@ -443,19 +443,22 @@ /// \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. /// \param Scope Scope in which this type is defined. /// \param Name Value parameter name. /// \param Ty Parameter type. + /// \param IsDefault Parameter is default or not /// \param Val Constant parameter value. - DITemplateValueParameter *createTemplateValueParameter(DIScope *Scope, - StringRef Name, - DIType *Ty, - Constant *Val); + DITemplateValueParameter * + createTemplateValueParameter(DIScope *Scope, StringRef Name, DIType *Ty, + bool IsDefault, Constant *Val); /// Create debugging information for a template template parameter. /// \param Scope Scope in which this type is defined. Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2131,9 +2131,11 @@ /// Base class for template parameters. class DITemplateParameter : public DINode { protected: + bool IsDefault; + DITemplateParameter(LLVMContext &Context, unsigned ID, StorageType Storage, - unsigned Tag, ArrayRef Ops) - : DINode(Context, ID, Storage, Tag, Ops) {} + unsigned Tag, bool IsDefault, ArrayRef Ops) + : DINode(Context, ID, Storage, Tag, Ops), IsDefault(IsDefault) {} ~DITemplateParameter() = default; public: @@ -2142,6 +2144,7 @@ MDString *getRawName() const { return getOperandAs(0); } Metadata *getRawType() const { return getOperand(1); } + bool isDefault() const { return IsDefault; } static bool classof(const Metadata *MD) { return MD->getMetadataID() == DITemplateTypeParameterKind || @@ -2154,30 +2157,35 @@ friend class MDNode; 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, IsDefault, + Ops) {} ~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(), isDefault()); } public: - DEFINE_MDNODE_GET(DITemplateTypeParameter, (StringRef Name, DIType *Type), - (Name, Type)) - DEFINE_MDNODE_GET(DITemplateTypeParameter, (MDString * Name, Metadata *Type), - (Name, Type)) + 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(); } @@ -2191,36 +2199,40 @@ friend class MDNode; DITemplateValueParameter(LLVMContext &Context, StorageType Storage, - unsigned Tag, ArrayRef Ops) + unsigned Tag, bool IsDefault, + ArrayRef Ops) : DITemplateParameter(Context, DITemplateValueParameterKind, Storage, Tag, - Ops) {} + IsDefault, Ops) {} ~DITemplateValueParameter() = default; static DITemplateValueParameter *getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, DIType *Type, - Metadata *Value, StorageType Storage, + bool IsDefault, Metadata *Value, + StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Tag, getCanonicalMDString(Context, Name), Type, - Value, Storage, ShouldCreate); + IsDefault, Value, Storage, ShouldCreate); } static DITemplateValueParameter *getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *Type, - Metadata *Value, StorageType Storage, + bool IsDefault, Metadata *Value, + StorageType Storage, bool ShouldCreate = true); TempDITemplateValueParameter cloneImpl() const { return getTemporary(getContext(), getTag(), getName(), getType(), - getValue()); + isDefault(), getValue()); } public: DEFINE_MDNODE_GET(DITemplateValueParameter, - (unsigned Tag, StringRef Name, DIType *Type, + (unsigned Tag, StringRef Name, DIType *Type, bool IsDefault, Metadata *Value), - (Tag, Name, Type, Value)) - DEFINE_MDNODE_GET(DITemplateValueParameter, (unsigned Tag, MDString *Name, - Metadata *Type, Metadata *Value), - (Tag, Name, Type, Value)) + (Tag, Name, Type, IsDefault, Value)) + DEFINE_MDNODE_GET(DITemplateValueParameter, + (unsigned Tag, MDString *Name, Metadata *Type, + bool IsDefault, Metadata *Value), + (Tag, Name, Type, IsDefault, Value)) TempDITemplateValueParameter clone() const { return cloneImpl(); } Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -4839,33 +4839,38 @@ } /// ParseDITemplateTypeParameter: -/// ::= !DITemplateTypeParameter(name: "Ty", type: !1) +/// ::= !DITemplateTypeParameter(name: "Ty", type: !1, defaulted: false) bool LLParser::ParseDITemplateTypeParameter(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ OPTIONAL(name, MDStringField, ); \ - REQUIRED(type, MDField, ); + REQUIRED(type, MDField, ); \ + OPTIONAL(defaulted, 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, defaulted.Val)); return false; } /// ParseDITemplateValueParameter: /// ::= !DITemplateValueParameter(tag: DW_TAG_template_value_parameter, -/// name: "V", type: !1, value: i32 7) +/// name: "V", type: !1, defaulted: false, +/// value: i32 7) bool LLParser::ParseDITemplateValueParameter(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ OPTIONAL(tag, DwarfTagField, (dwarf::DW_TAG_template_value_parameter)); \ OPTIONAL(name, MDStringField, ); \ OPTIONAL(type, MDField, ); \ + OPTIONAL(defaulted, MDBoolField, ); \ REQUIRED(value, MDField, ); + PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = GET_OR_DISTINCT(DITemplateValueParameter, - (Context, tag.Val, name.Val, type.Val, value.Val)); + Result = GET_OR_DISTINCT( + DITemplateValueParameter, + (Context, tag.Val, name.Val, type.Val, defaulted.Val, value.Val)); return false; } Index: llvm/lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1668,28 +1668,46 @@ break; } case bitc::METADATA_TEMPLATE_TYPE: { - if (Record.size() != 3) + if (Record.size() < 3 || Record.size() > 4) return error("Invalid record"); IsDistinct = Record[0]; - MetadataList.assignValue(GET_OR_DISTINCT(DITemplateTypeParameter, + if (Record.size() == 4) + MetadataList.assignValue(GET_OR_DISTINCT(DITemplateTypeParameter, + (Context, getMDString(Record[1]), + getDITypeRefOrNull(Record[2]), + getMDOrNull(Record[3]))), + NextMetadataNo); + else + MetadataList.assignValue(GET_OR_DISTINCT(DITemplateTypeParameter, (Context, getMDString(Record[1]), - getDITypeRefOrNull(Record[2]))), + getDITypeRefOrNull(Record[2]), + false)), NextMetadataNo); NextMetadataNo++; break; } case bitc::METADATA_TEMPLATE_VALUE: { - if (Record.size() != 5) + if (Record.size() < 5 || Record.size() > 6) return error("Invalid record"); IsDistinct = Record[0]; - MetadataList.assignValue( - GET_OR_DISTINCT(DITemplateValueParameter, + + if (Record.size() == 6) + MetadataList.assignValue( + GET_OR_DISTINCT(DITemplateValueParameter, (Context, Record[1], getMDString(Record[2]), - getDITypeRefOrNull(Record[3]), + getDITypeRefOrNull(Record[3]), getMDOrNull(Record[4]), + getMDOrNull(Record[5]))), + NextMetadataNo); + else + MetadataList.assignValue( + GET_OR_DISTINCT(DITemplateValueParameter, + (Context, Record[1], getMDString(Record[2]), + getDITypeRefOrNull(Record[3]), false, getMDOrNull(Record[4]))), NextMetadataNo); + NextMetadataNo++; break; } Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1790,6 +1790,7 @@ Record.push_back(N->isDistinct()); Record.push_back(VE.getMetadataOrNullID(N->getRawName())); Record.push_back(VE.getMetadataOrNullID(N->getType())); + Record.push_back(N->isDefault()); Stream.EmitRecord(bitc::METADATA_TEMPLATE_TYPE, Record, Abbrev); Record.clear(); @@ -1802,6 +1803,7 @@ Record.push_back(N->getTag()); Record.push_back(VE.getMetadataOrNullID(N->getRawName())); Record.push_back(VE.getMetadataOrNullID(N->getType())); + Record.push_back(N->isDefault()); Record.push_back(VE.getMetadataOrNullID(N->getValue())); Stream.EmitRecord(bitc::METADATA_TEMPLATE_VALUE, Record, Abbrev); 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->isDefault() && (DD->getDwarfVersion() >= 5)) + addFlag(ParamDIE, dwarf::DW_AT_default_value); } void DwarfUnit::constructTemplateValueParameterDIE( @@ -1058,6 +1060,8 @@ addType(ParamDIE, VP->getType()); if (!VP->getName().empty()) addString(ParamDIE, dwarf::DW_AT_name, VP->getName()); + if (VP->isDefault() && (DD->getDwarfVersion() >= 5)) + addFlag(ParamDIE, dwarf::DW_AT_default_value); if (Metadata *Val = VP->getValue()) { if (ConstantInt *CI = mdconst::dyn_extract(Val)) addConstantValue(ParamDIE, CI, VP->getType()); Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -2071,6 +2071,7 @@ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); Printer.printString("name", N->getName()); Printer.printMetadata("type", N->getRawType(), /* ShouldSkipNull */ false); + Printer.printBool("defaulted", N->isDefault(), /* Default= */ false); Out << ")"; } @@ -2085,6 +2086,7 @@ Printer.printTag(N); Printer.printString("name", N->getName()); Printer.printMetadata("type", N->getRawType()); + Printer.printBool("defaulted", N->isDefault(), /* Default= */ false); Printer.printMetadata("value", N->getValue(), /* ShouldSkipNull */ false); Out << ")"; } Index: llvm/lib/IR/DIBuilder.cpp =================================================================== --- llvm/lib/IR/DIBuilder.cpp +++ llvm/lib/IR/DIBuilder.cpp @@ -406,25 +406,26 @@ 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 * createTemplateValueParameterHelper(LLVMContext &VMContext, unsigned Tag, DIScope *Context, StringRef Name, DIType *Ty, - Metadata *MD) { + bool IsDefault, Metadata *MD) { assert((!Context || isa(Context)) && "Expected compile unit"); - return DITemplateValueParameter::get(VMContext, Tag, Name, Ty, MD); + return DITemplateValueParameter::get(VMContext, Tag, Name, Ty, IsDefault, MD); } DITemplateValueParameter * DIBuilder::createTemplateValueParameter(DIScope *Context, StringRef Name, - DIType *Ty, Constant *Val) { + DIType *Ty, bool isDefault, + Constant *Val) { return createTemplateValueParameterHelper( VMContext, dwarf::DW_TAG_template_value_parameter, Context, Name, Ty, - getConstantOrNull(Val)); + isDefault, getConstantOrNull(Val)); } DITemplateValueParameter * @@ -432,7 +433,7 @@ DIType *Ty, StringRef Val) { return createTemplateValueParameterHelper( VMContext, dwarf::DW_TAG_GNU_template_template_param, Context, Name, Ty, - MDString::get(VMContext, Val)); + false, MDString::get(VMContext, Val)); } DITemplateValueParameter * @@ -440,7 +441,7 @@ DIType *Ty, DINodeArray Val) { return createTemplateValueParameterHelper( VMContext, dwarf::DW_TAG_GNU_template_parameter_pack, Context, Name, Ty, - Val.get()); + false, Val.get()); } DICompositeType *DIBuilder::createClassType( Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -724,24 +724,24 @@ 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( LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *Type, - Metadata *Value, StorageType Storage, bool ShouldCreate) { + bool isDefault, Metadata *Value, StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DITemplateValueParameter, (Tag, Name, Type, Value)); + DEFINE_GETIMPL_LOOKUP(DITemplateValueParameter, + (Tag, Name, Type, isDefault, Value)); Metadata *Ops[] = {Name, Type, Value}; - DEFINE_GETIMPL_STORE(DITemplateValueParameter, (Tag), Ops); + DEFINE_GETIMPL_STORE(DITemplateValueParameter, (Tag, isDefault), Ops); } DIGlobalVariable * Index: llvm/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/lib/IR/LLVMContextImpl.h +++ llvm/lib/IR/LLVMContextImpl.h @@ -843,36 +843,45 @@ 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->isDefault()) {} bool isKeyOf(const DITemplateTypeParameter *RHS) const { - return Name == RHS->getRawName() && Type == RHS->getRawType(); + return Name == RHS->getRawName() && Type == RHS->getRawType() && + IsDefault == RHS->isDefault(); } - unsigned getHashValue() const { return hash_combine(Name, Type); } + unsigned getHashValue() const { return hash_combine(Name, Type, IsDefault); } }; template <> struct MDNodeKeyImpl { unsigned Tag; MDString *Name; Metadata *Type; + bool IsDefault; Metadata *Value; - MDNodeKeyImpl(unsigned Tag, MDString *Name, Metadata *Type, Metadata *Value) - : Tag(Tag), Name(Name), Type(Type), Value(Value) {} + MDNodeKeyImpl(unsigned Tag, MDString *Name, Metadata *Type, bool IsDefault, + Metadata *Value) + : Tag(Tag), Name(Name), Type(Type), IsDefault(IsDefault), Value(Value) {} MDNodeKeyImpl(const DITemplateValueParameter *N) : Tag(N->getTag()), Name(N->getRawName()), Type(N->getRawType()), - Value(N->getValue()) {} + IsDefault(N->isDefault()), Value(N->getValue()) {} bool isKeyOf(const DITemplateValueParameter *RHS) const { return Tag == RHS->getTag() && Name == RHS->getRawName() && - Type == RHS->getRawType() && Value == RHS->getValue(); + Type == RHS->getRawType() && IsDefault == RHS->isDefault() && + Value == RHS->getValue(); } - unsigned getHashValue() const { return hash_combine(Tag, Name, Type, Value); } + unsigned getHashValue() const { + return hash_combine(Tag, Name, Type, IsDefault, Value); + } }; template <> struct MDNodeKeyImpl { Index: llvm/test/Assembler/DITemplateParameter.ll =================================================================== --- /dev/null +++ llvm/test/Assembler/DITemplateParameter.ll @@ -0,0 +1,65 @@ +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s +; RUN: verify-uselistorder %s + +; ModuleID = '/dir/test.cpp' +source_filename = "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 } +; 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 + 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 !23 + ret i32 0, !dbg !24 +} +; 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 11.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/dir/", checksumkind: CSK_MD5, checksum: "863d08522c2300490dea873efc4b2369") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 5} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0"} +!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 29, type: !8, scopeLine: 29, 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: 30, type: !12) +!12 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "foo", file: !1, line: 26, size: 8, flags: DIFlagTypePassByValue, elements: !2, templateParams: !13, identifier: "_ZTS3fooIiLi6EE") +!13 = !{!14, !15} + +; CHECK: 14 = !DITemplateTypeParameter(name: "T", type: !{{[0-9]*}}) +!14 = !DITemplateTypeParameter(name: "T", type: !10) + +; CHECK: 15 = !DITemplateValueParameter(name: "i", type: !{{[0-9]*}}, value: i32 6) +!15 = !DITemplateValueParameter(name: "i", type: !10, value: i32 6) + +!16 = !DILocation(line: 30, column: 14, scope: !7) +!17 = !DILocalVariable(name: "f2", scope: !7, file: !1, line: 31, type: !18) +!18 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "foo", file: !1, line: 26, size: 8, flags: DIFlagTypePassByValue, elements: !2, templateParams: !19, identifier: "_ZTS3fooIcLi3EE") +!19 = !{!20, !22} + +; CHECK: 20 = !DITemplateTypeParameter({{.*}}, defaulted: true +!20 = !DITemplateTypeParameter(name: "T", type: !21, defaulted: true) +!21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) + +; CHECK: 22 = !DITemplateValueParameter({{.*}}, defaulted: true +!22 = !DITemplateValueParameter(name: "i", type: !10, defaulted: true, value: i32 3) +!23 = !DILocation(line: 31, column: 9, scope: !7) +!24 = !DILocation(line: 32, column: 3, scope: !7) Index: llvm/test/Bitcode/DITemplateParameter-5.0.ll =================================================================== --- /dev/null +++ llvm/test/Bitcode/DITemplateParameter-5.0.ll @@ -0,0 +1,69 @@ +; RUN: llvm-dis -o - %s.bc | FileCheck %s + +; ModuleID = '/dir/test.cpp' +source_filename = "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 } +; 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 + 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 !23 + ret i32 0, !dbg !24 +} +; 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 11.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/dir/", checksumkind: CSK_MD5, checksum: "863d08522c2300490dea873efc4b2369") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 5} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0"} +!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 29, type: !8, scopeLine: 29, 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: 30, type: !12) +!12 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "foo", file: !1, line: 26, size: 8, flags: DIFlagTypePassByValue, elements: !2, templateParams: !13, identifier: "_ZTS3fooIiLi6EE") +!13 = !{!14, !15} + +; Old-style DITemplateTypeParameter and DITemplateValueParameter should be +; upgraded to include defaulted flag. + +; CHECK: !DITemplateTypeParameter({{.*}} +!14 = !DITemplateTypeParameter(name: "T", type: !10) + +; CHECK: !DITemplateValueParameter({{.*}} +!15 = !DITemplateValueParameter(name: "i", type: !10, value: i32 6) + +!16 = !DILocation(line: 30, column: 14, scope: !7) +!17 = !DILocalVariable(name: "f2", scope: !7, file: !1, line: 31, type: !18) +!18 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "foo", file: !1, line: 26, size: 8, flags: DIFlagTypePassByValue, elements: !2, templateParams: !19, identifier: "_ZTS3fooIcLi3EE") +!19 = !{!20, !22} + +; CHECK: !DITemplateTypeParameter({{.*}} defaulted: true +!20 = !DITemplateTypeParameter(name: "T", type: !21, defaulted: true) + +!21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) + +; CHECK: !DITemplateValueParameter({{.*}} defaulted: true +!22 = !DITemplateValueParameter(name: "i", type: !10, defaulted: true, value: i32 3) + +!23 = !DILocation(line: 31, column: 9, scope: !7) +!24 = !DILocation(line: 32, column: 3, scope: !7) Index: llvm/test/DebugInfo/X86/debug-info-template-parameter.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/debug-info-template-parameter.ll @@ -0,0 +1,90 @@ +; 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; +; return 0; +;} + +; $ clang++ -O0 -gdwarf-5 -S -gdwarf-5 test.cpp + +; CHECK: .debug_abbrev contents: +; CHECK: DW_AT_default_value DW_FORM_flag_present + +; CHECK: debug_info contents: + +; 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 {{.*}} "i" +; CHECK-NOT: DW_AT_default_value + +; 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 {{.*}} "i" +; CHECK_NEXT: DW_AT_default_value {{.*}} true + +; ModuleID = '/dir/test.cpp' +source_filename = "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 } +; 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 + 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 !23 + ret i32 0, !dbg !24 +} +; 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 11.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/dir/", checksumkind: CSK_MD5, checksum: "863d08522c2300490dea873efc4b2369") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 5} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0"} +!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 29, type: !8, scopeLine: 29, 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: 30, type: !12) +!12 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "foo", file: !1, line: 26, size: 8, flags: DIFlagTypePassByValue, elements: !2, templateParams: !13, identifier: "_ZTS3fooIiLi6EE") +!13 = !{!14, !15} +!14 = !DITemplateTypeParameter(name: "T", type: !10) +!15 = !DITemplateValueParameter(name: "i", type: !10, value: i32 6) +!16 = !DILocation(line: 30, column: 14, scope: !7) +!17 = !DILocalVariable(name: "f2", scope: !7, file: !1, line: 31, type: !18) +!18 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "foo", file: !1, line: 26, size: 8, flags: DIFlagTypePassByValue, elements: !2, templateParams: !19, identifier: "_ZTS3fooIcLi3EE") +!19 = !{!20, !22} +!20 = !DITemplateTypeParameter(name: "T", type: !21, defaulted: true) +!21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!22 = !DITemplateValueParameter(name: "i", type: !10, defaulted: true, value: i32 3) +!23 = !DILocation(line: 31, column: 9, scope: !7) +!24 = !DILocation(line: 32, 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))); @@ -2100,21 +2100,23 @@ DIType *Type = getBasicType("basic"); Metadata *Value = getConstantAsMetadata(); - auto *N = DITemplateValueParameter::get(Context, Tag, Name, Type, Value); + auto *N = + DITemplateValueParameter::get(Context, Tag, Name, Type, false, Value); EXPECT_EQ(Tag, N->getTag()); EXPECT_EQ(Name, N->getName()); EXPECT_EQ(Type, N->getType()); EXPECT_EQ(Value, N->getValue()); - EXPECT_EQ(N, DITemplateValueParameter::get(Context, Tag, Name, Type, Value)); + EXPECT_EQ( + N, DITemplateValueParameter::get(Context, Tag, Name, Type, false, Value)); EXPECT_NE(N, DITemplateValueParameter::get( Context, dwarf::DW_TAG_GNU_template_template_param, Name, - Type, Value)); - EXPECT_NE(N, - DITemplateValueParameter::get(Context, Tag, "other", Type, Value)); - EXPECT_NE(N, DITemplateValueParameter::get(Context, Tag, Name, - getBasicType("other"), Value)); - EXPECT_NE(N, DITemplateValueParameter::get(Context, Tag, Name, Type, + Type, false, Value)); + EXPECT_NE(N, DITemplateValueParameter::get(Context, Tag, "other", Type, false, + Value)); + EXPECT_NE(N, DITemplateValueParameter::get( + Context, Tag, Name, getBasicType("other"), false, Value)); + EXPECT_NE(N, DITemplateValueParameter::get(Context, Tag, Name, Type, false, getConstantAsMetadata())); TempDITemplateValueParameter Temp = N->clone();