Skip to content

Commit 25ac0d3

Browse files
committed
DebugInfo: Implement the -gsimple-template-names functionality
This excludes certain names that can't be rebuilt from the available DWARF: * Atomic types - no DWARF differentiating int from atomic int. * Vector types - enough DWARF (an attribute on the array type) to do this, but I haven't written the extra code to add the attributes required for this * Lambdas - ambiguous with any other unnamed class * Unnamed classes/enums - would need column info for the type in addition to file/line number * noexcept function types - not encoded in DWARF
1 parent 7a62a5b commit 25ac0d3

File tree

2 files changed

+258
-2
lines changed

2 files changed

+258
-2
lines changed

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 165 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "clang/AST/DeclTemplate.h"
2626
#include "clang/AST/Expr.h"
2727
#include "clang/AST/RecordLayout.h"
28+
#include "clang/AST/RecursiveASTVisitor.h"
2829
#include "clang/Basic/CodeGenOptions.h"
2930
#include "clang/Basic/FileManager.h"
3031
#include "clang/Basic/SourceManager.h"
@@ -4855,11 +4856,173 @@ llvm::DIGlobalVariableExpression *CGDebugInfo::CollectAnonRecordDecls(
48554856
return GVE;
48564857
}
48574858

4859+
namespace {
4860+
struct ReconstitutableType : public RecursiveASTVisitor<ReconstitutableType> {
4861+
bool Reconstitutable = true;
4862+
bool VisitVectorType(VectorType *FT) {
4863+
Reconstitutable = false;
4864+
return false;
4865+
}
4866+
bool VisitAtomicType(AtomicType *FT) {
4867+
Reconstitutable = false;
4868+
return false;
4869+
}
4870+
bool TraverseEnumType(EnumType *ET) {
4871+
// Unnamed enums can't be reconstituted due to a lack of column info we
4872+
// produce in the DWARF, so we can't get Clang's full name back.
4873+
if (const auto *ED = dyn_cast<EnumDecl>(ET->getDecl())) {
4874+
if (!ED->getIdentifier()) {
4875+
Reconstitutable = false;
4876+
return false;
4877+
}
4878+
}
4879+
return true;
4880+
}
4881+
bool VisitFunctionProtoType(FunctionProtoType *FT) {
4882+
// noexcept is not encoded in DWARF, so the reversi
4883+
Reconstitutable &= !isNoexceptExceptionSpec(FT->getExceptionSpecType());
4884+
return !Reconstitutable;
4885+
}
4886+
bool TraverseRecordType(RecordType *RT) {
4887+
// Unnamed classes/lambdas can't be reconstituted due to a lack of column
4888+
// info we produce in the DWARF, so we can't get Clang's full name back.
4889+
// But so long as it's not one of those, it doesn't matter if some sub-type
4890+
// of the record (a template parameter) can't be reconstituted - because the
4891+
// un-reconstitutable type itself will carry its own name.
4892+
const auto *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
4893+
if (!RD)
4894+
return true;
4895+
if (RD->isLambda() || !RD->getIdentifier()) {
4896+
Reconstitutable = false;
4897+
return false;
4898+
}
4899+
return true;
4900+
}
4901+
};
4902+
} // anonymous namespace
4903+
4904+
// Test whether a type name could be rebuilt from emitted debug info.
4905+
static bool IsReconstitutableType(QualType QT) {
4906+
ReconstitutableType T;
4907+
T.TraverseType(QT);
4908+
return T.Reconstitutable;
4909+
}
4910+
48584911
std::string CGDebugInfo::GetName(const Decl *D, bool Qualified) const {
48594912
std::string Name;
48604913
llvm::raw_string_ostream OS(Name);
4861-
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
4862-
ND->getNameForDiagnostic(OS, getPrintingPolicy(), Qualified);
4914+
const NamedDecl *ND = dyn_cast<NamedDecl>(D);
4915+
if (!ND)
4916+
return Name;
4917+
codegenoptions::DebugTemplateNamesKind TemplateNamesKind =
4918+
CGM.getCodeGenOpts().getDebugSimpleTemplateNames();
4919+
Optional<TemplateArgs> Args;
4920+
4921+
bool IsOperatorOverload = false; // isa<CXXConversionDecl>(ND);
4922+
if (auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
4923+
Args = GetTemplateArgs(RD);
4924+
} else if (auto *FD = dyn_cast<FunctionDecl>(ND)) {
4925+
Args = GetTemplateArgs(FD);
4926+
auto NameKind = ND->getDeclName().getNameKind();
4927+
IsOperatorOverload |=
4928+
NameKind == DeclarationName::CXXOperatorName ||
4929+
NameKind == DeclarationName::CXXConversionFunctionName;
4930+
} else if (auto *VD = dyn_cast<VarDecl>(ND)) {
4931+
Args = GetTemplateArgs(VD);
4932+
}
4933+
std::function<bool(ArrayRef<TemplateArgument>)> HasReconstitutableArgs =
4934+
[&](ArrayRef<TemplateArgument> Args) {
4935+
return llvm::all_of(Args, [&](const TemplateArgument &TA) {
4936+
switch (TA.getKind()) {
4937+
case TemplateArgument::Template:
4938+
// Easy to reconstitute - the value of the parameter in the debug
4939+
// info is the string name of the template. (so the template name
4940+
// itself won't benefit from any name rebuilding, but that's a
4941+
// representational limitation - maybe DWARF could be
4942+
// changed/improved to use some more structural representation)
4943+
return true;
4944+
case TemplateArgument::Declaration:
4945+
// Reference and pointer non-type template parameters point to
4946+
// variables, functions, etc and their value is, at best (for
4947+
// variables) represented as an address - not a reference to the
4948+
// DWARF describing the variable/function/etc. This makes it hard,
4949+
// possibly impossible to rebuild the original name - looking up the
4950+
// address in the executable file's symbol table would be needed.
4951+
return false;
4952+
case TemplateArgument::NullPtr:
4953+
// These could be rebuilt, but figured they're close enough to the
4954+
// declaration case, and not worth rebuilding.
4955+
return false;
4956+
case TemplateArgument::Pack:
4957+
// A pack is invalid if any of the elements of the pack are invalid.
4958+
return HasReconstitutableArgs(TA.getPackAsArray());
4959+
case TemplateArgument::Integral:
4960+
// Larger integers get encoded as DWARF blocks which are a bit
4961+
// harder to parse back into a large integer, etc - so punting on
4962+
// this for now. Re-parsing the integers back into APInt is probably
4963+
// feasible some day.
4964+
return TA.getAsIntegral().getBitWidth() <= 64;
4965+
case TemplateArgument::Type:
4966+
return IsReconstitutableType(TA.getAsType());
4967+
default:
4968+
llvm_unreachable("Other, unresolved, template arguments should "
4969+
"not be seen here");
4970+
}
4971+
});
4972+
};
4973+
// A conversion operator presents complications/ambiguity if there's a
4974+
// conversion to class template that is itself a template, eg:
4975+
// template<typename T>
4976+
// operator ns::t1<T, int>();
4977+
// This should be named, eg: "operator ns::t1<float, int><float>"
4978+
// (ignoring clang bug that means this is currently "operator t1<float>")
4979+
// but if the arguments were stripped, the consumer couldn't differentiate
4980+
// whether the template argument list for the conversion type was the
4981+
// function's argument list (& no reconstitution was needed) or not.
4982+
// This could be handled if reconstitutable names had a separate attribute
4983+
// annotating them as such - this would remove the ambiguity.
4984+
//
4985+
// Alternatively the template argument list could be parsed enough to check
4986+
// whether there's one list or two, then compare that with the DWARF
4987+
// description of the return type and the template argument lists to determine
4988+
// how many lists there should be and if one is missing it could be assumed(?)
4989+
// to be the function's template argument list & then be rebuilt.
4990+
//
4991+
// Other operator overloads that aren't conversion operators could be
4992+
// reconstituted but would require a bit more nuance about detecting the
4993+
// difference between these different operators during that rebuilding.
4994+
bool Reconstitutable =
4995+
Args && HasReconstitutableArgs(Args->Args) && !IsOperatorOverload;
4996+
4997+
PrintingPolicy PP = getPrintingPolicy();
4998+
4999+
if (TemplateNamesKind == codegenoptions::DebugTemplateNamesKind::Full ||
5000+
!Reconstitutable) {
5001+
ND->getNameForDiagnostic(OS, PP, Qualified);
5002+
} else {
5003+
bool Mangled =
5004+
TemplateNamesKind == codegenoptions::DebugTemplateNamesKind::Mangled;
5005+
// check if it's a template
5006+
if (Mangled)
5007+
OS << "_STN";
5008+
5009+
OS << ND->getDeclName();
5010+
std::string EncodedOriginalName;
5011+
llvm::raw_string_ostream EncodedOriginalNameOS(EncodedOriginalName);
5012+
EncodedOriginalNameOS << ND->getDeclName();
5013+
5014+
if (Mangled) {
5015+
OS << "|";
5016+
printTemplateArgumentList(OS, Args->Args, PP);
5017+
printTemplateArgumentList(EncodedOriginalNameOS, Args->Args, PP);
5018+
#ifndef NDEBUG
5019+
std::string CanonicalOriginalName;
5020+
llvm::raw_string_ostream OriginalOS(CanonicalOriginalName);
5021+
ND->getNameForDiagnostic(OriginalOS, PP, Qualified);
5022+
assert(EncodedOriginalNameOS.str() == OriginalOS.str());
5023+
#endif
5024+
}
5025+
}
48635026
return Name;
48645027
}
48655028

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown_unknown -debug-info-kind=limited -gsimple-template-names=mangled %s -o - -w -std=c++17 | FileCheck %s
2+
// RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown_unknown -debug-info-kind=limited -gsimple-template-names=simple %s -o - -w -std=c++17 | FileCheck --check-prefix=SIMPLE --implicit-check-not=_STN %s
3+
// RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown_unknown -debug-info-kind=limited %s -o - -w -std=c++17 | FileCheck --check-prefix=FULL --implicit-check-not=_STN %s
4+
5+
template <typename... T>
6+
void f1() {}
7+
template <typename T, T V>
8+
void f2() {}
9+
template <typename... T>
10+
struct t1 {};
11+
extern int x;
12+
int x;
13+
struct t2 {
14+
template <typename T = float>
15+
operator t1<int>() { __builtin_unreachable(); }
16+
};
17+
template <template <typename...> class T>
18+
void f3() {}
19+
void f() {
20+
// Basic examples of simplifiable/rebuildable names
21+
f1<>();
22+
// CHECK: !DISubprogram(name: "_STNf1|<>",
23+
// SIMPLE: !DISubprogram(name: "f1",
24+
// FULL: !DISubprogram(name: "f1<>",
25+
f1<int>();
26+
// CHECK: !DISubprogram(name: "_STNf1|<int>",
27+
f1<void()>();
28+
// CHECK: !DISubprogram(name: "_STNf1|<void ()>",
29+
f2<int, 42>();
30+
// CHECK: !DISubprogram(name: "_STNf2|<int, 42>",
31+
32+
// Check that even though the nested name can't be rebuilt, it'll carry its
33+
// full name and the outer name can be rebuilt from that.
34+
f1<t1<void() noexcept>>();
35+
// CHECK: !DISubprogram(name: "_STNf1|<t1<void () noexcept> >",
36+
37+
// Vector array types are encoded in DWARF but the decoding in llvm-dwarfdump
38+
// isn't implemented yet.
39+
f1<__attribute__((__vector_size__((sizeof(int) * 2)))) int>();
40+
// CHECK: !DISubprogram(name: "f1<__attribute__((__vector_size__(2 * sizeof(int)))) int>",
41+
42+
// noexcept is part of function types in C++17 onwards, but not encoded in
43+
// DWARF
44+
f1<void() noexcept>();
45+
// CHECK: !DISubprogram(name: "f1<void () noexcept>",
46+
47+
// Unnamed entities (lambdas, structs/classes, enums) can't be fully rebuilt
48+
// since we don't emit the column number. Also lambdas and unnamed classes are
49+
// ambiguous with each other - there's no DWARF that designates a lambda as
50+
// anything other than another unnamed class/struct.
51+
auto A = [] {};
52+
f1<decltype(A)>();
53+
// CHECK: !DISubprogram(name: "f1<(lambda at {{.*}}debug-info-simple-template-names.cpp:[[# @LINE - 2]]:12)>",
54+
struct {
55+
} unnamed_struct;
56+
f1<decltype(unnamed_struct)>();
57+
// CHECK: !DISubprogram(name: "f1<(unnamed struct at {{.*}}CodeGenCXX/debug-info-simple-template-names.cpp:[[# @LINE - 3]]:3)>",
58+
enum {} unnamed_enum;
59+
f1<decltype(unnamed_enum)>();
60+
// CHECK: !DISubprogram(name: "f1<(unnamed enum at {{.*}}debug-info-simple-template-names.cpp:[[# @LINE - 2]]:3)>",
61+
62+
// Declarations can't readily be reversed as the value in the DWARF only
63+
// contains the address of the value - we'd have to do symbol lookup to find
64+
// the name of that value (& rely on it not having been stripped out, etc).
65+
f2<int *, &x>();
66+
// CHECK: !DISubprogram(name: "f2<int *, &x>",
67+
68+
// We could probably handle \/ this case, but since it's a small subset of
69+
// pointer typed non-type-template parameters which can't be handled it
70+
// doesn't seem high priority.
71+
f2<decltype(nullptr), nullptr>();
72+
// CHECK: !DISubprogram(name: "f2<std::nullptr_t, nullptr>",
73+
74+
// These larger constants are encoded as data blocks which makes them a bit
75+
// harder to re-render. I think they might be missing sign information, or at
76+
// maybe it's just a question of doing APInt things to render such large
77+
// values. Punting on this for now.
78+
f2<__int128, ((__int128)9223372036854775807) * 2>();
79+
// CHECK: !DISubprogram(name: "f2<__int128, (__int128)18446744073709551614>",
80+
81+
t2().operator t1<int>();
82+
// FIXME: This should be something like "operator t1<int><float>"
83+
// CHECK: !DISubprogram(name: "operator t1<float>",
84+
85+
// Function pointer non-type-template parameters currently don't get any DWARF
86+
// value (GCC doesn't provide one either) and even if there was a value, if
87+
// it's like variable/pointer non-type template parameters, it couldn't be
88+
// rebuilt anyway (see the note above for details on that) so we don't have to
89+
// worry about seeing conversion operators as parameters to other templates.
90+
91+
f3<t1>();
92+
// CHECK: !DISubprogram(name: "_STNf3|<t1>",
93+
}

0 commit comments

Comments
 (0)