-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Add support for template as type parameter #127654
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-llvm-ir @llvm/pr-subscribers-clang Author: ykhatav (ykhatav) ChangesFor template classes with type parameters, the information of which member variables are of a "templated type" is lost. Full diff: https://github.com/llvm/llvm-project/pull/127654.diff 10 Files Affected:
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 386652d2efa9e..79c3df2e43eef 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -468,6 +468,7 @@ CODEGENOPT(CtorDtorReturnThis, 1, 0)
/// Enables emitting Import Call sections on supported targets that can be used
/// by the Windows kernel to enable import call optimization.
CODEGENOPT(ImportCallOptimization, 1, 0)
+CODEGENOPT(DebugTemplateParameterAsType, 1, 0)
/// FIXME: Make DebugOptions its own top-level .def file.
#include "DebugOptions.def"
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index d8123cc39fdc9..32a88d42dde49 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -9028,3 +9028,8 @@ def wasm_opt : Flag<["--"], "wasm-opt">,
Group<m_Group>,
HelpText<"Enable the wasm-opt optimizer (default)">,
MarshallingInfoNegativeFlag<LangOpts<"NoWasmOpt">>;
+defm debug_template_parameter_as_type
+ : BoolFOption<"debug-template-parameter-as-type",
+ CodeGenOpts<"DebugTemplateParameterAsType">,
+ DefaultFalse, PosFlag<SetTrue>, NegFlag<SetFalse>,
+ BothFlags<[], [CC1Option]>>;
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index db595796c067e..ce2d34dcd4ce3 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1003,6 +1003,13 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
return DBuilder.createBasicType(BTName, Size, Encoding);
}
+llvm::DIType *CGDebugInfo::CreateType(const SubstTemplateTypeParmType *Ty,
+ llvm::DIFile *U) {
+ llvm::DIType *debugType = getOrCreateType(Ty->getReplacementType(), U);
+ return DBuilder.createTemplateTypeParameterAsType(
+ U, Ty->getReplacedParameter()->getName(), debugType);
+}
+
llvm::DIType *CGDebugInfo::CreateType(const BitIntType *Ty) {
StringRef Name = Ty->isUnsigned() ? "unsigned _BitInt" : "_BitInt";
@@ -3611,7 +3618,8 @@ llvm::DILocation *CGDebugInfo::CreateTrapFailureMessageFor(
/*Scope=*/TrapSP, /*InlinedAt=*/TrapLocation);
}
-static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
+static QualType UnwrapTypeForDebugInfo(QualType T, const CodeGenModule &CGM) {
+ const ASTContext &C = CGM.getContext();
Qualifiers Quals;
do {
Qualifiers InnerQuals = T.getLocalQualifiers();
@@ -3664,6 +3672,8 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
T = cast<MacroQualifiedType>(T)->getUnderlyingType();
break;
case Type::SubstTemplateTypeParm:
+ if (CGM.getCodeGenOpts().DebugTemplateParameterAsType)
+ return C.getQualifiedType(T.getTypePtr(), Quals);
T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
break;
case Type::Auto:
@@ -3690,7 +3700,7 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
}
llvm::DIType *CGDebugInfo::getTypeOrNull(QualType Ty) {
- assert(Ty == UnwrapTypeForDebugInfo(Ty, CGM.getContext()));
+ assert(Ty == UnwrapTypeForDebugInfo(Ty, CGM));
auto It = TypeCache.find(Ty.getAsOpaquePtr());
if (It != TypeCache.end()) {
// Verify that the debug info still exists.
@@ -3729,7 +3739,7 @@ llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
});
// Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
+ Ty = UnwrapTypeForDebugInfo(Ty, CGM);
if (auto *T = getTypeOrNull(Ty))
return T;
@@ -3866,6 +3876,9 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
case Type::Decltype:
case Type::PackIndexing:
case Type::UnaryTransform:
+ if (Ty->getTypeClass() == Type::SubstTemplateTypeParm &&
+ CGM.getCodeGenOpts().DebugTemplateParameterAsType)
+ return CreateType(cast<SubstTemplateTypeParmType>(Ty), Unit);
break;
}
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 38f73eca561b7..5e28fd5bf9039 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -228,6 +228,8 @@ class CGDebugInfo {
llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const PipeType *Ty, llvm::DIFile *F);
+ llvm::DIType *CreateType(const SubstTemplateTypeParmType *Ty,
+ llvm::DIFile *F);
/// Get enumeration type.
llvm::DIType *CreateEnumType(const EnumType *Ty);
llvm::DIType *CreateTypeDefinition(const EnumType *Ty);
diff --git a/clang/test/CodeGenCXX/debug-info-temp-param-as-type.cpp b/clang/test/CodeGenCXX/debug-info-temp-param-as-type.cpp
new file mode 100644
index 0000000000000..3422ce8f1e2bd
--- /dev/null
+++ b/clang/test/CodeGenCXX/debug-info-temp-param-as-type.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -fdebug-template-parameter-as-type -triple x86_64-apple-darwin %s -o - | FileCheck %s
+
+
+template <typename T>
+struct TClass {
+ TClass();
+ void foo();
+ T val_;
+ int val2_;
+};
+
+template <typename T>
+void TClass<T>::foo() {
+ T tVar = 1;
+ T* pT = &tVar;
+ tVar++;
+}
+
+template <typename T>
+T bar(T tp) {
+ return tp;
+}
+
+int main () {
+ TClass<int> a;
+ a.val2_ = 3;
+ a.foo();
+ auto A = bar(42);
+ TClass<double> b;
+ return 0;
+}
+
+// CHECK: [[INT:![0-9]+]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+// CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "TClass<int>"
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "val_",{{.*}}baseType: [[TPARAM:![0-9]+]]
+// CHECK: [[TPARAM]] = !DIDerivedType(tag: DW_TAG_template_type_parameter, name: "T", {{.*}}baseType: [[INT]])
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "val2_",{{.*}}baseType: [[INT]]
+
+// CHECK: !DILocalVariable(name: "A",{{.*}}type: [[TPARAM]])
+
+// CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "TClass<double>"
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "val_",{{.*}}baseType: [[TPARAM2:![0-9]+]]
+// CHECK: [[TPARAM2]] = !DIDerivedType(tag: DW_TAG_template_type_parameter, name: "T", {{.*}}baseType: [[DOUBLE:![0-9]+]])
+// CHECK: [[DOUBLE]] = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
+
+// CHECK: distinct !DISubprogram(name: "foo"
+// CHECK: !DILocalVariable(name: "tVar",{{.*}}type: [[TPARAM]])
+// CHECK: !DILocalVariable(name: "pT",{{.*}}type: [[TPTR:![0-9]+]]
+// CHECK: [[TPTR]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[TPARAM]]
+
+// CHECK: distinct !DISubprogram(name: "bar<int>"
+// CHECK: !DILocalVariable(name: "tp",{{.*}}type: [[TPARAM]])
diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h
index 6c479415b9ed2..bb9b9490fdcdd 100644
--- a/llvm/include/llvm/IR/DIBuilder.h
+++ b/llvm/include/llvm/IR/DIBuilder.h
@@ -550,6 +550,12 @@ namespace llvm {
StringRef Name,
DIType *Ty,
bool IsDefault);
+ /// \param Scope Scope in which this type is defined.
+ /// \param Name Type parameter name.
+ /// \param Ty Parameter type.
+ DIDerivedType *createTemplateTypeParameterAsType(DIScope *Scope,
+ StringRef Name,
+ DIType *Ty);
/// Create debugging information for template
/// value parameter.
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index 0a8a1ad38c959..8557d833dfb0e 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -520,6 +520,8 @@ void DwarfUnit::addTemplateParams(DIE &Buffer, DINodeArray TParams) {
constructTemplateTypeParameterDIE(Buffer, TTP);
else if (auto *TVP = dyn_cast<DITemplateValueParameter>(Element))
constructTemplateValueParameterDIE(Buffer, TVP);
+ else if (auto *TDT = dyn_cast<DIDerivedType>(Element))
+ createTypeDIE(TDT->getScope(), Buffer, TDT);
}
}
diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp
index 8f9462ab46d88..fc50077ba8736 100644
--- a/llvm/lib/IR/DIBuilder.cpp
+++ b/llvm/lib/IR/DIBuilder.cpp
@@ -458,6 +458,15 @@ DIBuilder::createObjCProperty(StringRef Name, DIFile *File, unsigned LineNumber,
SetterName, PropertyAttributes, Ty);
}
+DIDerivedType *DIBuilder::createTemplateTypeParameterAsType(DIScope *Context,
+ StringRef Name,
+ DIType *Ty) {
+ return DIDerivedType::get(VMContext, dwarf::DW_TAG_template_type_parameter,
+ Name, nullptr, 0, Context, Ty, 0, 0, 0,
+ std::nullopt, std::nullopt, DINode::FlagZero,
+ nullptr);
+}
+
DITemplateTypeParameter *
DIBuilder::createTemplateTypeParameter(DIScope *Context, StringRef Name,
DIType *Ty, bool isDefault) {
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 8432779c107de..669c3370d9fc4 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -1241,6 +1241,7 @@ void Verifier::visitDIDerivedType(const DIDerivedType &N) {
N.getTag() == dwarf::DW_TAG_inheritance ||
N.getTag() == dwarf::DW_TAG_friend ||
N.getTag() == dwarf::DW_TAG_set_type ||
+ N.getTag() == dwarf::DW_TAG_template_type_parameter ||
N.getTag() == dwarf::DW_TAG_template_alias,
"invalid tag", &N);
if (N.getTag() == dwarf::DW_TAG_ptr_to_member_type) {
@@ -1288,8 +1289,11 @@ void Verifier::visitTemplateParams(const MDNode &N, const Metadata &RawParams) {
auto *Params = dyn_cast<MDTuple>(&RawParams);
CheckDI(Params, "invalid template params", &N, &RawParams);
for (Metadata *Op : Params->operands()) {
- CheckDI(Op && isa<DITemplateParameter>(Op), "invalid template parameter",
- &N, Params, Op);
+ CheckDI(((Op) && (isa<DITemplateParameter>(Op))) ||
+ ((isa<DIDerivedType>(Op)) &&
+ (dyn_cast<DIDerivedType>(Op)->getTag() ==
+ dwarf::DW_TAG_template_type_parameter)),
+ "invalid template parameter", &N, Params, Op);
}
}
diff --git a/llvm/test/DebugInfo/X86/template-as-type-param.ll b/llvm/test/DebugInfo/X86/template-as-type-param.ll
new file mode 100644
index 0000000000000..25eaeb92fec3e
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/template-as-type-param.ll
@@ -0,0 +1,119 @@
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu %s -o %t -filetype=obj
+; RUN: llvm-dwarfdump %t | FileCheck %s
+;Source code for the IR below:
+;template <typename T>
+;struct A
+;{
+; A () : val_ (), val2_ () { }
+; T val_;
+; int val2_;
+;};
+
+;int main (void)
+;{
+; A<int> a;
+; a.val2_ = 3;
+; return 0;
+;}
+
+; CHECK: DW_TAG_structure_type
+; CHECK: DW_AT_name ("A<int>")
+; CHECK-NEXT: DW_AT_byte_size (0x08)
+; CHECK-NEXT: DW_AT_decl_file ("test.cpp")
+; CHECK-NEXT: DW_AT_decl_line (2)
+
+; CHECK-NOT: NULL
+
+; CHECK:[[TEMPLATE:0x[0-9a-f]*]]: DW_TAG_template_type_parameter
+; CHECK-NEXT: DW_AT_type {{.*}} "int"
+; CHECK-NEXT: DW_AT_name ("T")
+
+; CHECK: DW_TAG_member
+; CHECK-NEXT: DW_AT_name ("val_")
+; CHECK-NEXT: DW_AT_type ([[TEMPLATE]] "T")
+
+; CHECK: DW_TAG_member
+; CHECK-NEXT: DW_AT_name ("val2_")
+; CHECK-NEXT: DW_AT_type {{.*}} "int"
+; ModuleID = 'test.cpp'
+source_filename = "test.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.A = type { i32, i32 }
+
+$_ZN1AIiEC2Ev = comdat any
+
+; Function Attrs: mustprogress noinline norecurse optnone uwtable
+define dso_local noundef i32 @main() #0 !dbg !22 {
+entry:
+ %retval = alloca i32, align 4
+ %a = alloca %struct.A, align 4
+ store i32 0, ptr %retval, align 4
+ #dbg_declare(ptr %a, !26, !DIExpression(), !27)
+ call void @_ZN1AIiEC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %a), !dbg !27
+ %val2_ = getelementptr inbounds nuw %struct.A, ptr %a, i32 0, i32 1, !dbg !28
+ store i32 3, ptr %val2_, align 4, !dbg !29
+ ret i32 0, !dbg !30
+}
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define linkonce_odr dso_local void @_ZN1AIiEC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %this) unnamed_addr #1 comdat align 2 !dbg !31 {
+entry:
+ %this.addr = alloca ptr, align 8
+ store ptr %this, ptr %this.addr, align 8
+ #dbg_declare(ptr %this.addr, !32, !DIExpression(), !34)
+ %this1 = load ptr, ptr %this.addr, align 8
+ %val_ = getelementptr inbounds nuw %struct.A, ptr %this1, i32 0, i32 0, !dbg !35
+ store i32 0, ptr %val_, align 4, !dbg !35
+ %val2_ = getelementptr inbounds nuw %struct.A, ptr %this1, i32 0, i32 1, !dbg !36
+ store i32 0, ptr %val2_, align 4, !dbg !36
+ ret void, !dbg !37
+}
+
+attributes #0 = { mustprogress noinline norecurse optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!14, !15, !16, !17, !18, !19, !20}
+!llvm.ident = !{!21}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.cpp", directory: "", checksumkind: CSK_MD5, checksum: "451371997e00e9e85d610a4e9d44a9b5")
+!2 = !{!3}
+!3 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A<int>", file: !1, line: 2, size: 64, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !4, templateParams: !12, identifier: "_ZTS1AIiE")
+!4 = !{!5, !7, !8}
+!5 = !DIDerivedType(tag: DW_TAG_member, name: "val_", scope: !3, file: !1, line: 4, baseType: !38, size: 32)
+!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "val2_", scope: !3, file: !1, line: 5, baseType: !6, size: 32, offset: 32)
+!8 = !DISubprogram(name: "A", scope: !3, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: 0)
+!9 = !DISubroutineType(types: !10)
+!10 = !{null, !11}
+!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!12 = !{!38}
+!13 = !DITemplateTypeParameter(name: "T", type: !6)
+!14 = !{i32 7, !"Dwarf Version", i32 5}
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 1, !"wchar_size", i32 4}
+!17 = !{i32 8, !"PIC Level", i32 2}
+!18 = !{i32 7, !"PIE Level", i32 2}
+!19 = !{i32 7, !"uwtable", i32 2}
+!20 = !{i32 7, !"frame-pointer", i32 2}
+!21 = !{!"clang"}
+!22 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 7, type: !23, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !25)
+!23 = !DISubroutineType(types: !24)
+!24 = !{!6}
+!25 = !{}
+!26 = !DILocalVariable(name: "a", scope: !22, file: !1, line: 8, type: !3)
+!27 = !DILocation(line: 8, column: 8, scope: !22)
+!28 = !DILocation(line: 9, column: 3, scope: !22)
+!29 = !DILocation(line: 9, column: 9, scope: !22)
+!30 = !DILocation(line: 10, column: 1, scope: !22)
+!31 = distinct !DISubprogram(name: "A", linkageName: "_ZN1AIiEC2Ev", scope: !3, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !8, retainedNodes: !25)
+!32 = !DILocalVariable(name: "this", arg: 1, scope: !31, type: !33, flags: DIFlagArtificial | DIFlagObjectPointer)
+!33 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3, size: 64)
+!34 = !DILocation(line: 0, scope: !31)
+!35 = !DILocation(line: 3, column: 8, scope: !31)
+!36 = !DILocation(line: 3, column: 17, scope: !31)
+!37 = !DILocation(line: 3, column: 28, scope: !31)
+!38 = !DIDerivedType(tag: DW_TAG_template_type_parameter,name:"T",scope:!3, baseType: !6)
|
|
Couple high-level of questions/comments:
|
The desired behavior would be to show "int val2_" instead of "T val2_".
Sure, I'll work on adding more test cases. As for the dwarf output, it looks like this: |
|
I found some gaps in my implementation. Converting this PR to draft while I work on it. |
What features are you hoping to build on this debug info? Mostly I worry it won't be terribly complete, because it can't work through situations, like this: In this case, v2 can be described as being of type "T" referencing the template_type_parameter, but v1 can't be - because it references trait::type, for instance. Also, I'd worry that most debuggers/DWARF consumers aren't ready to handle type references to template_type_parameters? So best to test this with at least LLDB and GDB before we commit it. |
I would say it is more of an improvement in debug information. The current implementation of Clang generates DWARF debug information that could be improved for better compliance with DWARF v5 standards. Consider the example D.11 from DWARF v5. Currently, Clang produces the following DWARF output: Note that the type of variable "comp" directly references "int" instead of DW_TAG_template_type_parameter.
I believe, in this case, the debug information of "v2" can still be improved and align with DWARF v5, it could be represented using DW_TAG_template_type instead of "int":
While I acknowledge that current debuggers may not fully support this DWARF representation, I suggest that this implementation be controlled by a switch until downstream tools are updated to accommodate these changes. |
Right - like I said, I get that "v2" gets better, but "v1" doesn't, right? And I imagine many/(most?) uses of type parameters in templates are more complicated - so I'm not sure how much this helps, and will feel awkwardly inconsistent for DWARF consumers/users?
Yeah - not sure it rises to the level of needing a flag (flags are a bit of an unfortunate maintenance burden - means more DWARF variety, harder to know everyone's doing the same thing, etc... ) - but some testing ahead of time would be good. |
I am not sure that I understand your concern completely. Consider the following DWARF output based on my implementation. How would you say "v1" should be represented ideally? 0x00000048: DW_TAG_template_type_parameter 0x0000004e: DW_TAG_member 0x00000057: DW_TAG_member
My primary reason for placing this implementation behind a flag is that it currently causes LLDB to crash and results in the following output from GDB. This is largely due to the fact that these debuggers do not yet support handling template type parameters represented as types: |
That's basically my point, sorry, that v1 must be represented as "trait::type" (because it has to be canonical) and so if many uses, like this one, of a type in a template can't reference the DW_TAG_template_type_parameter, because it's non-canonical - I'm not sure there's a lot of value in making it work for the subset of cases where it is workable.
Ah, thanks for testing. Yeah, that makes me similarly less inclined to pursue this direction. I'd say unless there's some specifically valuable feature that hinges on this representation change, I'm not super inclined to put this into Clang at the moment. Other folks/reviewers might have other perspectives, though. |
Are you suggesting that for the implementation to be considered as complete, both v1 and v2 should have the same type information? I.e "v1" type should point to 0x48 instead of 0x6d? As per my understanding based on the DWARF output below, the type for "trait::type"(0x6d) DOES reference a DW_TAG_template_type_parameter(0x67) entry: |
No, I don't think it should point to 0x67 instead of 0x6d - you could imagine a trait with a resulting type that has nothing to do with T (like My contention is that DWARF doesn't have a way to express this - and I don't really have a good idea for novel solutions/additions to DWARF etc to handle this. And without that, only changing the raw That's why I don't think this is a great direction to go. |
I created a sample test case containing a conditional trait type: If you run the above test case with -fdebug-template-parameter-as-type, we get the attached DWARF(conditional_trait_dwarf_w_change.txt). Note that this DWARF has the added benefit of indicating whether the type came from the true or false branch. While the type of trait remains the same with and without -fdebug-template-parameter-as-type , I believe the new DWARF adds more context about types in templates and conditionals. Could you please take a look at the attached DWARF and let me know your concerns with the implementation? I have also attached the DWARF output without -fdebug-template-parameter-as-type for your reference. conditional_trait_dwarf_orig.txt |
Sure - I see the effect, but I still think it's probably not worthwhile due to the limited capacity, inconsistency (due to that limited expressiveness) between direct uses of type parameters and situations where a template parameter is passed to another template, and missing consumer support (which I realize is a chicken-and-egg problem, and not always a deal breaker if there's valuable benefits to be had once consumers do support a given feature). But perhaps other reviewers have different takes on it. |
|
@adrian-prantl @Michael137 gentle ping! |
|
Closing due to lack of downstream support. |
For template classes with type parameters, the information of which member variables are of a "templated type" is lost.
The debugger cannot differentiate between "templated" types and "hardcoded" types. This is because both types have the same debug information, so there is no way that gdb can distinguish between them. This patch adds support for templates as type by representing the template type as a derived type.