forked from OSchip/llvm-project
[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:
parent
895aea6d15
commit
09e91ac6ab
|
@ -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 *
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
LEVEL = ../../../make
|
||||
CXX_SOURCES := main.cpp
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -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")])
|
|
@ -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"])
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
LEVEL = ../../../make
|
||||
CXX_SOURCES := main.cpp
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -0,0 +1,6 @@
|
|||
from lldbsuite.test import lldbinline
|
||||
from lldbsuite.test import decorators
|
||||
|
||||
lldbinline.MakeInlineTest(
|
||||
__file__, globals(), [
|
||||
decorators.expectedFailureAll(bugnumber="rdar://problem/32096064")])
|
|
@ -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"])
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue