Skip to content

Commit 2d5c43a

Browse files
JDevliegheretru
authored andcommitted
[lldb] Automatically unwrap parameter packs in template argument accessors
When looking at template arguments in LLDB, we usually care about what the user passed in his code, not whether some of those arguments where passed as a variadic parameter pack. This patch extends all the C++ APIs to look at template parameters to take an additional 'expand_pack' boolean that automatically unwraps the potential argument packs. The equivalent SBAPI calls have been changed to pass true for this parameter. A byproduct of the patch is to also fix the support for template type that have only a parameter pack as argument (like the OnlyPack type in the test). Those were not recognized as template instanciations before. The added test verifies that the SBAPI is able to iterate over the arguments of a variadic template. The original patch was written by Fred Riss almost 4 years ago. Differential revision: https://reviews.llvm.org/D51387 (cherry picked from commit b706f56)
1 parent 1e1c520 commit 2d5c43a

File tree

11 files changed

+190
-68
lines changed

11 files changed

+190
-68
lines changed

lldb/include/lldb/API/SBType.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ class SBType {
182182

183183
lldb::SBType GetTemplateArgumentType(uint32_t idx);
184184

185+
/// Return the TemplateArgumentKind of the template argument at index idx.
186+
/// Variadic argument packs are automatically expanded.
185187
lldb::TemplateArgumentKind GetTemplateArgumentKind(uint32_t idx);
186188

187189
lldb::SBType GetFunctionReturnType();

lldb/include/lldb/Symbol/CompilerType.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -338,14 +338,28 @@ class CompilerType {
338338
GetIndexOfChildMemberWithName(const char *name, bool omit_empty_base_classes,
339339
std::vector<uint32_t> &child_indexes) const;
340340

341-
size_t GetNumTemplateArguments() const;
342-
343-
lldb::TemplateArgumentKind GetTemplateArgumentKind(size_t idx) const;
344-
CompilerType GetTypeTemplateArgument(size_t idx) const;
341+
/// Return the number of template arguments the type has.
342+
/// If expand_pack is true, then variadic argument packs are automatically
343+
/// expanded to their supplied arguments. If it is false an argument pack
344+
/// will only count as 1 argument.
345+
size_t GetNumTemplateArguments(bool expand_pack = false) const;
346+
347+
// Return the TemplateArgumentKind of the template argument at index idx.
348+
// If expand_pack is true, then variadic argument packs are automatically
349+
// expanded to their supplied arguments. With expand_pack set to false, an
350+
// arguement pack will count as 1 argument and return a type of Pack.
351+
lldb::TemplateArgumentKind
352+
GetTemplateArgumentKind(size_t idx, bool expand_pack = false) const;
353+
CompilerType GetTypeTemplateArgument(size_t idx,
354+
bool expand_pack = false) const;
345355

346356
/// Returns the value of the template argument and its type.
357+
/// If expand_pack is true, then variadic argument packs are automatically
358+
/// expanded to their supplied arguments. With expand_pack set to false, an
359+
/// arguement pack will count as 1 argument and it is invalid to call this
360+
/// method on the pack argument.
347361
llvm::Optional<IntegralTemplateArgument>
348-
GetIntegralTemplateArgument(size_t idx) const;
362+
GetIntegralTemplateArgument(size_t idx, bool expand_pack = false) const;
349363

350364
CompilerType GetTypeForFormatters() const;
351365

lldb/include/lldb/Symbol/TypeSystem.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -346,14 +346,18 @@ class TypeSystem : public PluginInterface {
346346
const char *name, bool omit_empty_base_classes,
347347
std::vector<uint32_t> &child_indexes) = 0;
348348

349-
virtual size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type);
349+
virtual size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
350+
bool expand_pack);
350351

351352
virtual lldb::TemplateArgumentKind
352-
GetTemplateArgumentKind(lldb::opaque_compiler_type_t type, size_t idx);
353-
virtual CompilerType GetTypeTemplateArgument(lldb::opaque_compiler_type_t type,
354-
size_t idx);
353+
GetTemplateArgumentKind(lldb::opaque_compiler_type_t type, size_t idx,
354+
bool expand_pack);
355+
virtual CompilerType
356+
GetTypeTemplateArgument(lldb::opaque_compiler_type_t type, size_t idx,
357+
bool expand_pack);
355358
virtual llvm::Optional<CompilerType::IntegralTemplateArgument>
356-
GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, size_t idx);
359+
GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, size_t idx,
360+
bool expand_pack);
357361

358362
// Dumping types
359363

lldb/source/API/SBType.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,8 @@ uint32_t SBType::GetNumberOfTemplateArguments() {
542542
LLDB_INSTRUMENT_VA(this);
543543

544544
if (IsValid())
545-
return m_opaque_sp->GetCompilerType(false).GetNumTemplateArguments();
545+
return m_opaque_sp->GetCompilerType(false).GetNumTemplateArguments(
546+
/*expand_pack=*/true);
546547
return 0;
547548
}
548549

@@ -553,13 +554,15 @@ lldb::SBType SBType::GetTemplateArgumentType(uint32_t idx) {
553554
return SBType();
554555

555556
CompilerType type;
557+
const bool expand_pack = true;
556558
switch(GetTemplateArgumentKind(idx)) {
557559
case eTemplateArgumentKindType:
558-
type = m_opaque_sp->GetCompilerType(false).GetTypeTemplateArgument(idx);
560+
type = m_opaque_sp->GetCompilerType(false).GetTypeTemplateArgument(
561+
idx, expand_pack);
559562
break;
560563
case eTemplateArgumentKindIntegral:
561564
type = m_opaque_sp->GetCompilerType(false)
562-
.GetIntegralTemplateArgument(idx)
565+
.GetIntegralTemplateArgument(idx, expand_pack)
563566
->type;
564567
break;
565568
default:
@@ -574,7 +577,8 @@ lldb::TemplateArgumentKind SBType::GetTemplateArgumentKind(uint32_t idx) {
574577
LLDB_INSTRUMENT_VA(this, idx);
575578

576579
if (IsValid())
577-
return m_opaque_sp->GetCompilerType(false).GetTemplateArgumentKind(idx);
580+
return m_opaque_sp->GetCompilerType(false).GetTemplateArgumentKind(
581+
idx, /*expand_pack=*/true);
578582
return eTemplateArgumentKindNull;
579583
}
580584

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7096,7 +7096,8 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
70967096
}
70977097

70987098
size_t
7099-
TypeSystemClang::GetNumTemplateArguments(lldb::opaque_compiler_type_t type) {
7099+
TypeSystemClang::GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
7100+
bool expand_pack) {
71007101
if (!type)
71017102
return 0;
71027103

@@ -7111,8 +7112,17 @@ TypeSystemClang::GetNumTemplateArguments(lldb::opaque_compiler_type_t type) {
71117112
const clang::ClassTemplateSpecializationDecl *template_decl =
71127113
llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
71137114
cxx_record_decl);
7114-
if (template_decl)
7115-
return template_decl->getTemplateArgs().size();
7115+
if (template_decl) {
7116+
const auto &template_arg_list = template_decl->getTemplateArgs();
7117+
size_t num_args = template_arg_list.size();
7118+
assert(num_args && "template specialization without any args");
7119+
if (expand_pack && num_args) {
7120+
const auto &pack = template_arg_list[num_args - 1];
7121+
if (pack.getKind() == clang::TemplateArgument::Pack)
7122+
num_args += pack.pack_size() - 1;
7123+
}
7124+
return num_args;
7125+
}
71167126
}
71177127
}
71187128
break;
@@ -7149,15 +7159,51 @@ TypeSystemClang::GetAsTemplateSpecialization(
71497159
}
71507160
}
71517161

7162+
const TemplateArgument *
7163+
GetNthTemplateArgument(const clang::ClassTemplateSpecializationDecl *decl,
7164+
size_t idx, bool expand_pack) {
7165+
const auto &args = decl->getTemplateArgs();
7166+
const size_t args_size = args.size();
7167+
7168+
assert(args_size && "template specialization without any args");
7169+
if (!args_size)
7170+
return nullptr;
7171+
7172+
const size_t last_idx = args_size - 1;
7173+
7174+
// We're asked for a template argument that can't be a parameter pack, so
7175+
// return it without worrying about 'expand_pack'.
7176+
if (idx < last_idx)
7177+
return &args[idx];
7178+
7179+
// We're asked for the last template argument but we don't want/need to
7180+
// expand it.
7181+
if (!expand_pack || args[last_idx].getKind() != clang::TemplateArgument::Pack)
7182+
return idx >= args.size() ? nullptr : &args[idx];
7183+
7184+
// Index into the expanded pack.
7185+
// Note that 'idx' counts from the beginning of all template arguments
7186+
// (including the ones preceding the parameter pack).
7187+
const auto &pack = args[last_idx];
7188+
const size_t pack_idx = idx - last_idx;
7189+
const size_t pack_size = pack.pack_size();
7190+
assert(pack_idx < pack_size && "parameter pack index out-of-bounds");
7191+
return &pack.pack_elements()[pack_idx];
7192+
}
7193+
71527194
lldb::TemplateArgumentKind
71537195
TypeSystemClang::GetTemplateArgumentKind(lldb::opaque_compiler_type_t type,
7154-
size_t arg_idx) {
7196+
size_t arg_idx, bool expand_pack) {
71557197
const clang::ClassTemplateSpecializationDecl *template_decl =
71567198
GetAsTemplateSpecialization(type);
7157-
if (! template_decl || arg_idx >= template_decl->getTemplateArgs().size())
7199+
if (!template_decl)
7200+
return eTemplateArgumentKindNull;
7201+
7202+
const auto *arg = GetNthTemplateArgument(template_decl, arg_idx, expand_pack);
7203+
if (!arg)
71587204
return eTemplateArgumentKindNull;
71597205

7160-
switch (template_decl->getTemplateArgs()[arg_idx].getKind()) {
7206+
switch (arg->getKind()) {
71617207
case clang::TemplateArgument::Null:
71627208
return eTemplateArgumentKindNull;
71637209

@@ -7190,35 +7236,32 @@ TypeSystemClang::GetTemplateArgumentKind(lldb::opaque_compiler_type_t type,
71907236

71917237
CompilerType
71927238
TypeSystemClang::GetTypeTemplateArgument(lldb::opaque_compiler_type_t type,
7193-
size_t idx) {
7239+
size_t idx, bool expand_pack) {
71947240
const clang::ClassTemplateSpecializationDecl *template_decl =
71957241
GetAsTemplateSpecialization(type);
7196-
if (!template_decl || idx >= template_decl->getTemplateArgs().size())
7242+
if (!template_decl)
71977243
return CompilerType();
71987244

7199-
const clang::TemplateArgument &template_arg =
7200-
template_decl->getTemplateArgs()[idx];
7201-
if (template_arg.getKind() != clang::TemplateArgument::Type)
7245+
const auto *arg = GetNthTemplateArgument(template_decl, idx, expand_pack);
7246+
if (!arg || arg->getKind() != clang::TemplateArgument::Type)
72027247
return CompilerType();
72037248

7204-
return GetType(template_arg.getAsType());
7249+
return GetType(arg->getAsType());
72057250
}
72067251

72077252
Optional<CompilerType::IntegralTemplateArgument>
72087253
TypeSystemClang::GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type,
7209-
size_t idx) {
7254+
size_t idx, bool expand_pack) {
72107255
const clang::ClassTemplateSpecializationDecl *template_decl =
72117256
GetAsTemplateSpecialization(type);
7212-
if (! template_decl || idx >= template_decl->getTemplateArgs().size())
7257+
if (!template_decl)
72137258
return llvm::None;
72147259

7215-
const clang::TemplateArgument &template_arg =
7216-
template_decl->getTemplateArgs()[idx];
7217-
if (template_arg.getKind() != clang::TemplateArgument::Integral)
7260+
const auto *arg = GetNthTemplateArgument(template_decl, idx, expand_pack);
7261+
if (!arg || arg->getKind() != clang::TemplateArgument::Integral)
72187262
return llvm::None;
72197263

7220-
return {
7221-
{template_arg.getAsIntegral(), GetType(template_arg.getIntegralType())}};
7264+
return {{arg->getAsIntegral(), GetType(arg->getIntegralType())}};
72227265
}
72237266

72247267
CompilerType TypeSystemClang::GetTypeForFormatters(void *type) {

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class TypePayloadClang {
9191
void SetOwningModule(OptionalClangModuleID id);
9292
/// \}
9393
};
94-
94+
9595
/// A TypeSystem implementation based on Clang.
9696
///
9797
/// This class uses a single clang::ASTContext as the backend for storing
@@ -334,7 +334,7 @@ class TypeSystemClang : public TypeSystem {
334334

335335
llvm::SmallVector<const char *, 2> names;
336336
llvm::SmallVector<clang::TemplateArgument, 2> args;
337-
337+
338338
const char * pack_name = nullptr;
339339
std::unique_ptr<TemplateParameterInfos> packed_args;
340340
};
@@ -537,7 +537,7 @@ class TypeSystemClang : public TypeSystem {
537537
#ifndef NDEBUG
538538
bool Verify(lldb::opaque_compiler_type_t type) override;
539539
#endif
540-
540+
541541
bool IsArrayType(lldb::opaque_compiler_type_t type,
542542
CompilerType *element_type, uint64_t *size,
543543
bool *is_incomplete) override;
@@ -810,16 +810,17 @@ class TypeSystemClang : public TypeSystem {
810810
const char *name, bool omit_empty_base_classes,
811811
std::vector<uint32_t> &child_indexes) override;
812812

813-
size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override;
813+
size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
814+
bool expand_pack) override;
814815

815816
lldb::TemplateArgumentKind
816-
GetTemplateArgumentKind(lldb::opaque_compiler_type_t type,
817-
size_t idx) override;
817+
GetTemplateArgumentKind(lldb::opaque_compiler_type_t type, size_t idx,
818+
bool expand_pack) override;
818819
CompilerType GetTypeTemplateArgument(lldb::opaque_compiler_type_t type,
819-
size_t idx) override;
820+
size_t idx, bool expand_pack) override;
820821
llvm::Optional<CompilerType::IntegralTemplateArgument>
821-
GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type,
822-
size_t idx) override;
822+
GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, size_t idx,
823+
bool expand_pack) override;
823824

824825
CompilerType GetTypeForFormatters(void *type) override;
825826

lldb/source/Symbol/CompilerType.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -659,30 +659,32 @@ size_t CompilerType::GetIndexOfChildMemberWithName(
659659
return 0;
660660
}
661661

662-
size_t CompilerType::GetNumTemplateArguments() const {
662+
size_t CompilerType::GetNumTemplateArguments(bool expand_pack) const {
663663
if (IsValid()) {
664-
return m_type_system->GetNumTemplateArguments(m_type);
664+
return m_type_system->GetNumTemplateArguments(m_type, expand_pack);
665665
}
666666
return 0;
667667
}
668668

669-
TemplateArgumentKind CompilerType::GetTemplateArgumentKind(size_t idx) const {
669+
TemplateArgumentKind
670+
CompilerType::GetTemplateArgumentKind(size_t idx, bool expand_pack) const {
670671
if (IsValid())
671-
return m_type_system->GetTemplateArgumentKind(m_type, idx);
672+
return m_type_system->GetTemplateArgumentKind(m_type, idx, expand_pack);
672673
return eTemplateArgumentKindNull;
673674
}
674675

675-
CompilerType CompilerType::GetTypeTemplateArgument(size_t idx) const {
676+
CompilerType CompilerType::GetTypeTemplateArgument(size_t idx,
677+
bool expand_pack) const {
676678
if (IsValid()) {
677-
return m_type_system->GetTypeTemplateArgument(m_type, idx);
679+
return m_type_system->GetTypeTemplateArgument(m_type, idx, expand_pack);
678680
}
679681
return CompilerType();
680682
}
681683

682684
llvm::Optional<CompilerType::IntegralTemplateArgument>
683-
CompilerType::GetIntegralTemplateArgument(size_t idx) const {
685+
CompilerType::GetIntegralTemplateArgument(size_t idx, bool expand_pack) const {
684686
if (IsValid())
685-
return m_type_system->GetIntegralTemplateArgument(m_type, idx);
687+
return m_type_system->GetIntegralTemplateArgument(m_type, idx, expand_pack);
686688
return llvm::None;
687689
}
688690

lldb/source/Symbol/TypeSystem.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,23 +118,25 @@ CompilerType TypeSystem::GetTypeForFormatters(void *type) {
118118
return CompilerType(this, type);
119119
}
120120

121-
size_t TypeSystem::GetNumTemplateArguments(lldb::opaque_compiler_type_t type) {
121+
size_t TypeSystem::GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
122+
bool expand_pack) {
122123
return 0;
123124
}
124125

125126
TemplateArgumentKind
126-
TypeSystem::GetTemplateArgumentKind(opaque_compiler_type_t type, size_t idx) {
127+
TypeSystem::GetTemplateArgumentKind(opaque_compiler_type_t type, size_t idx,
128+
bool expand_pack) {
127129
return eTemplateArgumentKindNull;
128130
}
129131

130132
CompilerType TypeSystem::GetTypeTemplateArgument(opaque_compiler_type_t type,
131-
size_t idx) {
133+
size_t idx, bool expand_pack) {
132134
return CompilerType();
133135
}
134136

135137
llvm::Optional<CompilerType::IntegralTemplateArgument>
136-
TypeSystem::GetIntegralTemplateArgument(opaque_compiler_type_t type,
137-
size_t idx) {
138+
TypeSystem::GetIntegralTemplateArgument(opaque_compiler_type_t type, size_t idx,
139+
bool expand_pack) {
138140
return llvm::None;
139141
}
140142

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
Test that the type of arguments to C++ template classes that have variadic
3+
parameters can be enumerated.
4+
"""
5+
import lldb
6+
from lldbsuite.test.decorators import *
7+
from lldbsuite.test.lldbtest import *
8+
from lldbsuite.test import lldbutil
9+
10+
11+
class TemplatePackArgsTestCase(TestBase):
12+
13+
mydir = TestBase.compute_mydir(__file__)
14+
15+
def test_template_argument_pack(self):
16+
self.build()
17+
(_, _, thread, _) = lldbutil.run_to_source_breakpoint(self,
18+
'breakpoint here', lldb.SBFileSpec('main.cpp'), exe_name = 'a.out')
19+
frame = thread.GetSelectedFrame()
20+
21+
empty_pack = frame.FindVariable('emptyPack')
22+
self.assertTrue(empty_pack.IsValid(),
23+
'make sure we find the emptyPack variable')
24+
25+
only_pack = frame.FindVariable('onlyPack')
26+
self.assertTrue(only_pack.IsValid(),
27+
'make sure we find the onlyPack variable')
28+
self.assertEqual(only_pack.GetType().GetNumberOfTemplateArguments(), 4)
29+
self.assertEqual(only_pack.GetType().GetTemplateArgumentType(0).GetName(), 'int')
30+
self.assertEqual(only_pack.GetType().GetTemplateArgumentType(1).GetName(), 'char')
31+
self.assertEqual(only_pack.GetType().GetTemplateArgumentType(2).GetName(), 'double')
32+
# Access the C<double, 42> template parameter.
33+
nested_template = only_pack.GetType().GetTemplateArgumentType(3)
34+
self.assertEqual(nested_template.GetName(), 'D<int, int, bool>')
35+
self.assertEqual(nested_template.GetNumberOfTemplateArguments(), 3)
36+
self.assertEqual(nested_template.GetTemplateArgumentType(0).GetName(), 'int')
37+
self.assertEqual(nested_template.GetTemplateArgumentType(1).GetName(), 'int')
38+
self.assertEqual(nested_template.GetTemplateArgumentType(2).GetName(), 'bool')

0 commit comments

Comments
 (0)