[DWARF parser] Produce correct template parameter packs

Templates can end in parameter packs, like this

template <class T...> struct MyStruct 
  { /*...*/ };

LLDB does not currently support these parameter packs; 
it does not emit them into the template argument list
at all. This causes problems when you specialize, e.g.:

template <> struct MyStruct<int> 
  { /*...*/ };
template <> struct MyStruct<int, int> : MyStruct<int> 
  { /*...*/ };

LLDB generates two template specializations, each with 
no template arguments, and then when they are imported 
by the ASTImporter into a parser's AST context we get a 
single specialization that inherits from itself, 
causing Clang's record layout mechanism to smash its
stack.

This patch fixes the problem for classes and adds
tests. The tests for functions fail because Clang's
ASTImporter can't import them at the moment, so I've
xfailed that test.

Differential Revision: https://reviews.llvm.org/D33025

llvm-svn: 302833
This commit is contained in:
Sean Callanan 2017-05-11 22:08:05 +00:00
parent 895aea6d15
commit 09e91ac6ab
12 changed files with 211 additions and 36 deletions

View File

@ -275,17 +275,16 @@ public:
bool IsValid() const {
if (args.empty())
return false;
return args.size() == names.size();
}
size_t GetSize() const {
if (IsValid())
return args.size();
return 0;
return args.size() == names.size() &&
((bool)pack_name == (bool)packed_args) &&
(!packed_args || !packed_args->packed_args);
}
llvm::SmallVector<const char *, 2> names;
llvm::SmallVector<clang::TemplateArgument, 2> args;
const char * pack_name = nullptr;
std::unique_ptr<TemplateParameterInfos> packed_args;
};
clang::FunctionTemplateDecl *

View File

@ -0,0 +1,3 @@
LEVEL = ../../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,7 @@
from lldbsuite.test import lldbinline
from lldbsuite.test import decorators
lldbinline.MakeInlineTest(
__file__, globals(), [
decorators.expectedFailureAll(
oslist=["windows"], bugnumber="llvm.org/pr24764")])

View File

@ -0,0 +1,61 @@
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LIDENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
template <class T, int... Args> struct C {
T member;
bool isSixteenThirtyTwo() { return false; }
};
template <> struct C<int, 16> {
int member;
bool isSixteenThirtyTwo() { return false; }
};
template <> struct C<int, 16, 32> : C<int, 16> {
bool isSixteenThirtyTwo() { return true; }
};
template <class T, typename... Args> struct D {
T member;
bool isIntBool() { return false; }
};
template <> struct D<int, int> {
int member;
bool isIntBool() { return false; }
};
template <> struct D<int, int, bool> : D<int, int> {
bool isIntBool() { return true; }
};
int main (int argc, char const *argv[])
{
C<int,16,32> myC;
C<int,16> myLesserC;
myC.member = 64;
(void)C<int,16,32>().isSixteenThirtyTwo();
(void)C<int,16>().isSixteenThirtyTwo();
(void)(myC.member != 64); //% self.expect("expression -- myC", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["64"])
//% self.expect("expression -- C<int, 16>().isSixteenThirtyTwo()", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["false"])
//% self.expect("expression -- C<int, 16, 32>().isSixteenThirtyTwo()", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["true"])
//% self.expect("expression -- myLesserC.isSixteenThirtyTwo()", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["false"])
//% self.expect("expression -- myC.isSixteenThirtyTwo()", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["true"])
D<int,int,bool> myD;
D<int,int> myLesserD;
myD.member = 64;
(void)D<int,int,bool>().isIntBool();
(void)D<int,int>().isIntBool();
return myD.member != 64; //% self.expect("expression -- myD", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["64"])
//% self.expect("expression -- D<int, int>().isIntBool()", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["false"])
//% self.expect("expression -- D<int, int, bool>().isIntBool()", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["true"])
//% self.expect("expression -- myLesserD.isIntBool()", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["false"])
//% self.expect("expression -- myD.isIntBool()", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["true"])
}

View File

@ -0,0 +1,3 @@
LEVEL = ../../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,6 @@
from lldbsuite.test import lldbinline
from lldbsuite.test import decorators
lldbinline.MakeInlineTest(
__file__, globals(), [
decorators.expectedFailureAll(bugnumber="rdar://problem/32096064")])

View File

@ -0,0 +1,24 @@
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LIDENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
template <class T> int staticSizeof() {
return sizeof(T);
}
template <class T1, class T2, class... Ts> int staticSizeof() {
return staticSizeof<T2, Ts...>() + sizeof(T1);
}
int main (int argc, char const *argv[])
{
int sz = staticSizeof<long, int, char>();
return staticSizeof<long, int, char>() != sz; //% self.expect("expression -- sz == staticSizeof<long, int, char>()", "staticSizeof<long, int, char> worked", substrs = ["true"])
//% self.expect("expression -- sz == staticSizeof<long, int>() + sizeof(char)", "staticSizeof<long, int> worked", substrs = ["true"])
//% self.expect("expression -- sz == staticSizeof<long>() + sizeof(int) + sizeof(char)", "staticSizeof<long> worked", substrs = ["true"])
}

View File

@ -1987,8 +1987,33 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context,
.GetOpaqueDeclContext();
clang::FunctionDecl *src_function_decl =
llvm::dyn_cast_or_null<clang::FunctionDecl>(src_decl_context);
if (src_function_decl) {
if (src_function_decl &&
src_function_decl->getTemplateSpecializationInfo()) {
clang::FunctionTemplateDecl *function_template =
src_function_decl->getTemplateSpecializationInfo()->getTemplate();
clang::FunctionTemplateDecl *copied_function_template =
llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(
m_ast_importer_sp->CopyDecl(m_ast_context,
src_ast->getASTContext(),
function_template));
if (copied_function_template) {
if (log) {
ASTDumper ast_dumper((clang::Decl *)copied_function_template);
StreamString ss;
function->DumpSymbolContext(&ss);
log->Printf(" CEDM::FEVD[%u] Imported decl for function template"
" %s (description %s), returned %s",
current_id,
copied_function_template->getNameAsString().c_str(),
ss.GetData(), ast_dumper.GetCString());
}
context.AddNamedDecl(copied_function_template);
}
} else if (src_function_decl) {
if (clang::FunctionDecl *copied_function_decl =
llvm::dyn_cast_or_null<clang::FunctionDecl>(
m_ast_importer_sp->CopyDecl(m_ast_context,

View File

@ -1595,24 +1595,17 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc,
: containing_decl_ctx,
type_name_cstr, clang_type, storage, is_inline);
// if (template_param_infos.GetSize() >
// 0)
// {
// clang::FunctionTemplateDecl
// *func_template_decl =
// CreateFunctionTemplateDecl
// (containing_decl_ctx,
// function_decl,
// type_name_cstr,
// template_param_infos);
//
// CreateFunctionTemplateSpecializationInfo
// (function_decl,
// func_template_decl,
// template_param_infos);
// }
// Add the decl to our DIE to decl context map
if (has_template_params) {
ClangASTContext::TemplateParameterInfos template_param_infos;
ParseTemplateParameterInfos(die, template_param_infos);
clang::FunctionTemplateDecl *func_template_decl =
m_ast.CreateFunctionTemplateDecl(
containing_decl_ctx, function_decl, type_name_cstr,
template_param_infos);
m_ast.CreateFunctionTemplateSpecializationInfo(
function_decl, func_template_decl, template_param_infos);
}
lldbassert(function_decl);
if (function_decl) {
@ -1951,6 +1944,19 @@ bool DWARFASTParserClang::ParseTemplateDIE(
const dw_tag_t tag = die.Tag();
switch (tag) {
case DW_TAG_GNU_template_parameter_pack: {
template_param_infos.packed_args.reset(
new ClangASTContext::TemplateParameterInfos);
for (DWARFDIE child_die = die.GetFirstChild(); child_die.IsValid();
child_die = child_die.GetSibling()) {
if (!ParseTemplateDIE(child_die, *template_param_infos.packed_args))
return false;
}
if (const char *name = die.GetName()) {
template_param_infos.pack_name = name;
}
return true;
}
case DW_TAG_template_type_parameter:
case DW_TAG_template_value_parameter: {
DWARFAttributes attributes;
@ -2040,6 +2046,7 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos(
switch (tag) {
case DW_TAG_template_type_parameter:
case DW_TAG_template_value_parameter:
case DW_TAG_GNU_template_parameter_pack:
ParseTemplateDIE(die, template_param_infos);
break;
@ -3450,6 +3457,7 @@ size_t DWARFASTParserClang::ParseChildParameters(
case DW_TAG_template_type_parameter:
case DW_TAG_template_value_parameter:
case DW_TAG_GNU_template_parameter_pack:
// The one caller of this was never using the template_param_infos,
// and the local variable was taking up a large amount of stack space
// in SymbolFileDWARF::ParseType() so this was removed. If we ever need

View File

@ -1647,6 +1647,8 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address,
break;
case DW_TAG_template_value_parameter:
break;
case DW_TAG_GNU_template_parameter_pack:
break;
case DW_TAG_thrown_type:
break;
case DW_TAG_try_block:

View File

@ -610,6 +610,8 @@ DW_TAG_CategoryEnum get_tag_category(uint16_t tag) {
return TagCategoryType;
case DW_TAG_template_value_parameter:
return TagCategoryType;
case DW_TAG_GNU_template_parameter_pack:
return TagCategoryType;
case DW_TAG_thrown_type:
return TagCategoryType;
case DW_TAG_try_block:

View File

@ -1394,6 +1394,12 @@ CompilerType ClangASTContext::CreateRecordType(DeclContext *decl_ctx,
return CompilerType();
}
namespace {
bool IsValueParam(const clang::TemplateArgument &argument) {
return argument.getKind() == TemplateArgument::Integral;
}
}
static TemplateParameterList *CreateTemplateParameterList(
ASTContext *ast,
const ClangASTContext::TemplateParameterInfos &template_param_infos,
@ -1401,31 +1407,51 @@ static TemplateParameterList *CreateTemplateParameterList(
const bool parameter_pack = false;
const bool is_typename = false;
const unsigned depth = 0;
const size_t num_template_params = template_param_infos.GetSize();
const size_t num_template_params = template_param_infos.args.size();
DeclContext *const decl_context =
ast->getTranslationUnitDecl(); // Is this the right decl context?,
for (size_t i = 0; i < num_template_params; ++i) {
const char *name = template_param_infos.names[i];
IdentifierInfo *identifier_info = nullptr;
if (name && name[0])
identifier_info = &ast->Idents.get(name);
if (template_param_infos.args[i].getKind() == TemplateArgument::Integral) {
if (IsValueParam(template_param_infos.args[i])) {
template_param_decls.push_back(NonTypeTemplateParmDecl::Create(
*ast,
ast->getTranslationUnitDecl(), // Is this the right decl context?,
// SourceLocation StartLoc,
*ast, decl_context,
SourceLocation(), SourceLocation(), depth, i, identifier_info,
template_param_infos.args[i].getIntegralType(), parameter_pack,
nullptr));
} else {
template_param_decls.push_back(TemplateTypeParmDecl::Create(
*ast,
ast->getTranslationUnitDecl(), // Is this the right decl context?
*ast, decl_context,
SourceLocation(), SourceLocation(), depth, i, identifier_info,
is_typename, parameter_pack));
}
}
if (template_param_infos.packed_args &&
template_param_infos.packed_args->args.size()) {
IdentifierInfo *identifier_info = nullptr;
if (template_param_infos.pack_name && template_param_infos.pack_name[0])
identifier_info = &ast->Idents.get(template_param_infos.pack_name);
const bool parameter_pack_true = true;
if (IsValueParam(template_param_infos.packed_args->args[0])) {
template_param_decls.push_back(NonTypeTemplateParmDecl::Create(
*ast, decl_context,
SourceLocation(), SourceLocation(), depth, num_template_params,
identifier_info,
template_param_infos.packed_args->args[0].getIntegralType(),
parameter_pack_true, nullptr));
} else {
template_param_decls.push_back(TemplateTypeParmDecl::Create(
*ast, decl_context,
SourceLocation(), SourceLocation(), depth, num_template_params,
identifier_info,
is_typename, parameter_pack_true));
}
}
clang::Expr *const requires_clause = nullptr; // TODO: Concepts
TemplateParameterList *template_param_list = TemplateParameterList::Create(
*ast, SourceLocation(), SourceLocation(), template_param_decls,
@ -1535,10 +1561,19 @@ ClangASTContext::CreateClassTemplateSpecializationDecl(
DeclContext *decl_ctx, ClassTemplateDecl *class_template_decl, int kind,
const TemplateParameterInfos &template_param_infos) {
ASTContext *ast = getASTContext();
llvm::SmallVector<clang::TemplateArgument, 2> args(
template_param_infos.args.size() +
(template_param_infos.packed_args ? 1 : 0));
std::copy(template_param_infos.args.begin(), template_param_infos.args.end(),
args.begin());
if (template_param_infos.packed_args) {
args[args.size() - 1] = TemplateArgument::CreatePackCopy(
*ast, template_param_infos.packed_args->args);
}
ClassTemplateSpecializationDecl *class_template_specialization_decl =
ClassTemplateSpecializationDecl::Create(
*ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(),
SourceLocation(), class_template_decl, template_param_infos.args,
SourceLocation(), class_template_decl, args,
nullptr);
class_template_specialization_decl->setSpecializationKind(