Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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]>>;
19 changes: 16 additions & 3 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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:
Expand All @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
52 changes: 52 additions & 0 deletions clang/test/CodeGenCXX/debug-info-temp-param-as-type.cpp
Original file line number Diff line number Diff line change
@@ -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]])
6 changes: 6 additions & 0 deletions llvm/include/llvm/IR/DIBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/IR/DIBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 6 additions & 2 deletions llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
}

Expand Down
124 changes: 124 additions & 0 deletions llvm/test/DebugInfo/X86/template-as-type-param.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
; 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 ("/path/to{{/|\\}}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 = '<stdin>'
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"

%struct.A = type { i32, i32 }

$_ZN1AIiEC2Ev = comdat any

; Function Attrs: mustprogress noinline norecurse optnone uwtable
define dso_local noundef i32 @main() #0 !dbg !20 {
entry:
%retval = alloca i32, align 4
%a = alloca %struct.A, align 4
store i32 0, i32* %retval, align 4
call void @llvm.dbg.declare(metadata %struct.A* %a, metadata !24, metadata !DIExpression()), !dbg !25
call void @_ZN1AIiEC2Ev(%struct.A* noundef nonnull align 4 dereferenceable(8) %a), !dbg !25
%val2_ = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 1, !dbg !26
store i32 3, i32* %val2_, align 4, !dbg !27
ret i32 0, !dbg !28
}

; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1

; Function Attrs: noinline nounwind optnone uwtable
define linkonce_odr dso_local void @_ZN1AIiEC2Ev(%struct.A* noundef nonnull align 4 dereferenceable(8) %this) unnamed_addr #2 comdat align 2 !dbg !29 {

entry:
%this.addr = alloca %struct.A*, align 8
store %struct.A* %this, %struct.A** %this.addr, align 8
call void @llvm.dbg.declare(metadata %struct.A** %this.addr, metadata !30, metadata !DIExpression()), !dbg !32
%this1 = load %struct.A*, %struct.A** %this.addr, align 8
%val_ = getelementptr inbounds %struct.A, %struct.A* %this1, i32 0, i32 0, !dbg !33
store i32 0, i32* %val_, align 4, !dbg !33
%val2_ = getelementptr inbounds %struct.A, %struct.A* %this1, i32 0, i32 1, !dbg !34
store i32 0, i32* %val2_, align 4, !dbg !34
ret void, !dbg !35
}

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"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
attributes #2 = { 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"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!14, !15, !16, !17, !18}
!llvm.ident = !{!19}

!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "", isOptimized: false, flags: " -S -g -O0 -emit-llvm reproducer.cxx -o reproducer.ll", runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "test.cpp", directory: "/path/to")
!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: 5, baseType: !36, size: 32,offset: 32)
!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!7 = !DIDerivedType(tag: DW_TAG_member, name: "val2_", scope: !3, file: !1, line: 6, baseType: !6, size: 32, offset: 32)
!8 = !DISubprogram(name: "A", scope: !3, file: !1, line: 4, type: !9, scopeLine: 4, 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 = !{!36}
!13 = !DITemplateTypeParameter(name: "T", type: !6)
!14 = !{i32 7, !"Dwarf Version", i32 4}
!15 = !{i32 2, !"Debug Info Version", i32 3}
!16 = !{i32 1, !"wchar_size", i32 4}
!17 = !{i32 7, !"uwtable", i32 2}
!18 = !{i32 7, !"frame-pointer", i32 2}
!19 = !{!""}
!20 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 10, type: !21, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !23)
!21 = !DISubroutineType(types: !22)
!22 = !{!6}
!23 = !{}
!24 = !DILocalVariable(name: "a", scope: !20, file: !1, line: 12, type: !3)
!25 = !DILocation(line: 12, column: 10, scope: !20)
!26 = !DILocation(line: 13, column: 5, scope: !20)
!27 = !DILocation(line: 13, column: 11, scope: !20)
!28 = !DILocation(line: 15, column: 3, scope: !20)
!29 = distinct !DISubprogram(name: "A", linkageName: "_ZN1AIiEC2Ev", scope: !3, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !8, retainedNodes: !23)
!30 = !DILocalVariable(name: "this", arg: 1, scope: !29, type: !31, flags: DIFlagArtificial | DIFlagObjectPointer)
!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3, size: 64)
!32 = !DILocation(line: 0, scope: !29)
!33 = !DILocation(line: 4, column: 10, scope: !29)
!34 = !DILocation(line: 4, column: 19, scope: !29)
!35 = !DILocation(line: 4, column: 30, scope: !29)
!36 = !DIDerivedType(tag: DW_TAG_template_type_parameter,name:"T",scope:!3, baseType: !6)
Loading