diff options
| author | Pavel Labath <labath@google.com> | 2016-08-15 14:32:32 +0000 |
|---|---|---|
| committer | Pavel Labath <labath@google.com> | 2016-08-15 14:32:32 +0000 |
| commit | 1ac2b20d25869f7dafd8a5f9b99f43eb60a07bb2 (patch) | |
| tree | c641f44aee757720089228a31b3c69d79a4ec32c /lldb/source | |
| parent | ad61c170d5ac9f5a6fa22ad7ddac7e58daa6b46e (diff) | |
| download | bcm5719-llvm-1ac2b20d25869f7dafd8a5f9b99f43eb60a07bb2.tar.gz bcm5719-llvm-1ac2b20d25869f7dafd8a5f9b99f43eb60a07bb2.zip | |
Fix expression evaluation with operator new
Summary:
referencing a user-defined operator new was triggering an assert in clang because we were
registering the function name as string "operator new", instead of using the special operator
enum, which clang has for this purpose. Method operators already had code to handle this, and now
I extend this to cover free standing operator functions as well. Test included.
Reviewers: spyffe
Subscribers: sivachandra, paulherman, lldb-commits
Differential Revision: http://reviews.llvm.org/D17856
llvm-svn: 278670
Diffstat (limited to 'lldb/source')
| -rw-r--r-- | lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp | 7 | ||||
| -rw-r--r-- | lldb/source/Symbol/ClangASTContext.cpp | 518 |
2 files changed, 283 insertions, 242 deletions
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 7aeff6e964f..a0ea8ae730f 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -2081,13 +2081,10 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context, StreamString ss; function->DumpSymbolContext(&ss); - + log->Printf(" CEDM::FEVD[%u] Imported decl for function %s (description %s), returned %s", - current_id, - copied_function_decl->getName().str().c_str(), - ss.GetData(), + current_id, copied_function_decl->getNameAsString().c_str(), ss.GetData(), ast_dumper.GetCString()); - } context.AddNamedDecl(copied_function_decl); diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index c575a6f56c3..9521c3dee0a 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -131,6 +131,241 @@ GetASTMap() return *g_map_ptr; } +static bool +IsOperator(const char *name, clang::OverloadedOperatorKind &op_kind) +{ + if (name == nullptr || name[0] == '\0') + return false; + +#define OPERATOR_PREFIX "operator" +#define OPERATOR_PREFIX_LENGTH (sizeof(OPERATOR_PREFIX) - 1) + + const char *post_op_name = nullptr; + + bool no_space = true; + + if (::strncmp(name, OPERATOR_PREFIX, OPERATOR_PREFIX_LENGTH)) + return false; + + post_op_name = name + OPERATOR_PREFIX_LENGTH; + + if (post_op_name[0] == ' ') + { + post_op_name++; + no_space = false; + } + +#undef OPERATOR_PREFIX +#undef OPERATOR_PREFIX_LENGTH + + // This is an operator, set the overloaded operator kind to invalid + // in case this is a conversion operator... + op_kind = clang::NUM_OVERLOADED_OPERATORS; + + switch (post_op_name[0]) + { + default: + if (no_space) + return false; + break; + case 'n': + if (no_space) + return false; + if (strcmp(post_op_name, "new") == 0) + op_kind = clang::OO_New; + else if (strcmp(post_op_name, "new[]") == 0) + op_kind = clang::OO_Array_New; + break; + + case 'd': + if (no_space) + return false; + if (strcmp(post_op_name, "delete") == 0) + op_kind = clang::OO_Delete; + else if (strcmp(post_op_name, "delete[]") == 0) + op_kind = clang::OO_Array_Delete; + break; + + case '+': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Plus; + else if (post_op_name[2] == '\0') + { + if (post_op_name[1] == '=') + op_kind = clang::OO_PlusEqual; + else if (post_op_name[1] == '+') + op_kind = clang::OO_PlusPlus; + } + break; + + case '-': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Minus; + else if (post_op_name[2] == '\0') + { + switch (post_op_name[1]) + { + case '=': + op_kind = clang::OO_MinusEqual; + break; + case '-': + op_kind = clang::OO_MinusMinus; + break; + case '>': + op_kind = clang::OO_Arrow; + break; + } + } + else if (post_op_name[3] == '\0') + { + if (post_op_name[2] == '*') + op_kind = clang::OO_ArrowStar; + break; + } + break; + + case '*': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Star; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_StarEqual; + break; + + case '/': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Slash; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_SlashEqual; + break; + + case '%': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Percent; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_PercentEqual; + break; + + case '^': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Caret; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_CaretEqual; + break; + + case '&': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Amp; + else if (post_op_name[2] == '\0') + { + switch (post_op_name[1]) + { + case '=': + op_kind = clang::OO_AmpEqual; + break; + case '&': + op_kind = clang::OO_AmpAmp; + break; + } + } + break; + + case '|': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Pipe; + else if (post_op_name[2] == '\0') + { + switch (post_op_name[1]) + { + case '=': + op_kind = clang::OO_PipeEqual; + break; + case '|': + op_kind = clang::OO_PipePipe; + break; + } + } + break; + + case '~': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Tilde; + break; + + case '!': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Exclaim; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_ExclaimEqual; + break; + + case '=': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Equal; + else if (post_op_name[1] == '=' && post_op_name[2] == '\0') + op_kind = clang::OO_EqualEqual; + break; + + case '<': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Less; + else if (post_op_name[2] == '\0') + { + switch (post_op_name[1]) + { + case '<': + op_kind = clang::OO_LessLess; + break; + case '=': + op_kind = clang::OO_LessEqual; + break; + } + } + else if (post_op_name[3] == '\0') + { + if (post_op_name[2] == '=') + op_kind = clang::OO_LessLessEqual; + } + break; + + case '>': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Greater; + else if (post_op_name[2] == '\0') + { + switch (post_op_name[1]) + { + case '>': + op_kind = clang::OO_GreaterGreater; + break; + case '=': + op_kind = clang::OO_GreaterEqual; + break; + } + } + else if (post_op_name[1] == '>' && post_op_name[2] == '=' && post_op_name[3] == '\0') + { + op_kind = clang::OO_GreaterGreaterEqual; + } + break; + + case ',': + if (post_op_name[1] == '\0') + op_kind = clang::OO_Comma; + break; + + case '(': + if (post_op_name[1] == ')' && post_op_name[2] == '\0') + op_kind = clang::OO_Call; + break; + + case '[': + if (post_op_name[1] == ']' && post_op_name[2] == '\0') + op_kind = clang::OO_Subscript; + break; + } + + return true; +} clang::AccessSpecifier ClangASTContext::ConvertAccessTypeToAccessSpecifier (AccessType access) @@ -1524,23 +1759,26 @@ ClangASTContext::CreateClassTemplateSpecializationType (ClassTemplateSpecializat } static inline bool -check_op_param (uint32_t op_kind, bool unary, bool binary, uint32_t num_params) +check_op_param(bool is_method, clang::OverloadedOperatorKind op_kind, bool unary, bool binary, uint32_t num_params) { // Special-case call since it can take any number of operands if(op_kind == OO_Call) return true; // The parameter count doesn't include "this" - if (num_params == 0) - return unary; + if (is_method) + ++num_params; if (num_params == 1) + return unary; + if (num_params == 2) return binary; else return false; } bool -ClangASTContext::CheckOverloadedOperatorKindParameterCount (uint32_t op_kind, uint32_t num_params) +ClangASTContext::CheckOverloadedOperatorKindParameterCount(bool is_method, clang::OverloadedOperatorKind op_kind, + uint32_t num_params) { switch (op_kind) { @@ -1553,8 +1791,10 @@ ClangASTContext::CheckOverloadedOperatorKindParameterCount (uint32_t op_kind, ui case OO_Array_Delete: return true; } - -#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) case OO_##Name: return check_op_param (op_kind, Unary, Binary, num_params); + +#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \ + case OO_##Name: \ + return check_op_param(is_method, op_kind, Unary, Binary, num_params); switch (op_kind) { #include "clang/Basic/OperatorKinds.def" @@ -1965,6 +2205,35 @@ ClangASTContext::GetOpaqueCompilerType(clang::ASTContext *ast, lldb::BasicType b #pragma mark Function Types +clang::DeclarationName +ClangASTContext::GetDeclarationName(const char *name, const CompilerType &function_clang_type) +{ + if (!name || !name[0]) + return clang::DeclarationName(); + + clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; + if (!IsOperator(name, op_kind) || op_kind == clang::NUM_OVERLOADED_OPERATORS) + return DeclarationName(&getASTContext()->Idents.get(name)); // Not operator, but a regular function. + + // Check the number of operator parameters. Sometimes we have + // seen bad DWARF that doesn't correctly describe operators and + // if we try to create a method and add it to the class, clang + // will assert and crash, so we need to make sure things are + // acceptable. + clang::QualType method_qual_type(ClangUtil::GetQualType(function_clang_type)); + const clang::FunctionProtoType *function_type = + llvm::dyn_cast<clang::FunctionProtoType>(method_qual_type.getTypePtr()); + if (function_type == nullptr) + return clang::DeclarationName(); + + const bool is_method = false; + const unsigned int num_params = function_type->getNumParams(); + if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount(is_method, op_kind, num_params)) + return clang::DeclarationName(); + + return getASTContext()->DeclarationNames.getCXXOperatorName(op_kind); +} + FunctionDecl * ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx, const char *name, @@ -1981,20 +2250,10 @@ ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx, const bool hasWrittenPrototype = true; const bool isConstexprSpecified = false; - if (name && name[0]) - { - func_decl = FunctionDecl::Create( - *ast, decl_ctx, SourceLocation(), SourceLocation(), DeclarationName(&ast->Idents.get(name)), - ClangUtil::GetQualType(function_clang_type), nullptr, (clang::StorageClass)storage, is_inline, - hasWrittenPrototype, isConstexprSpecified); - } - else - { - func_decl = - FunctionDecl::Create(*ast, decl_ctx, SourceLocation(), SourceLocation(), DeclarationName(), - ClangUtil::GetQualType(function_clang_type), nullptr, (clang::StorageClass)storage, - is_inline, hasWrittenPrototype, isConstexprSpecified); - } + clang::DeclarationName declarationName = GetDeclarationName(name, function_clang_type); + func_decl = FunctionDecl::Create(*ast, decl_ctx, SourceLocation(), SourceLocation(), declarationName, + ClangUtil::GetQualType(function_clang_type), nullptr, (clang::StorageClass)storage, + is_inline, hasWrittenPrototype, isConstexprSpecified); if (func_decl) decl_ctx->addDecl (func_decl); @@ -7382,222 +7641,6 @@ ClangASTContext::GetTypeForFormatters (void* type) return CompilerType(); } -static bool -IsOperator (const char *name, clang::OverloadedOperatorKind &op_kind) -{ - if (name == nullptr || name[0] == '\0') - return false; - -#define OPERATOR_PREFIX "operator" -#define OPERATOR_PREFIX_LENGTH (sizeof (OPERATOR_PREFIX) - 1) - - const char *post_op_name = nullptr; - - bool no_space = true; - - if (::strncmp(name, OPERATOR_PREFIX, OPERATOR_PREFIX_LENGTH)) - return false; - - post_op_name = name + OPERATOR_PREFIX_LENGTH; - - if (post_op_name[0] == ' ') - { - post_op_name++; - no_space = false; - } - -#undef OPERATOR_PREFIX -#undef OPERATOR_PREFIX_LENGTH - - // This is an operator, set the overloaded operator kind to invalid - // in case this is a conversion operator... - op_kind = clang::NUM_OVERLOADED_OPERATORS; - - switch (post_op_name[0]) - { - default: - if (no_space) - return false; - break; - case 'n': - if (no_space) - return false; - if (strcmp (post_op_name, "new") == 0) - op_kind = clang::OO_New; - else if (strcmp (post_op_name, "new[]") == 0) - op_kind = clang::OO_Array_New; - break; - - case 'd': - if (no_space) - return false; - if (strcmp (post_op_name, "delete") == 0) - op_kind = clang::OO_Delete; - else if (strcmp (post_op_name, "delete[]") == 0) - op_kind = clang::OO_Array_Delete; - break; - - case '+': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Plus; - else if (post_op_name[2] == '\0') - { - if (post_op_name[1] == '=') - op_kind = clang::OO_PlusEqual; - else if (post_op_name[1] == '+') - op_kind = clang::OO_PlusPlus; - } - break; - - case '-': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Minus; - else if (post_op_name[2] == '\0') - { - switch (post_op_name[1]) - { - case '=': op_kind = clang::OO_MinusEqual; break; - case '-': op_kind = clang::OO_MinusMinus; break; - case '>': op_kind = clang::OO_Arrow; break; - } - } - else if (post_op_name[3] == '\0') - { - if (post_op_name[2] == '*') - op_kind = clang::OO_ArrowStar; break; - } - break; - - case '*': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Star; - else if (post_op_name[1] == '=' && post_op_name[2] == '\0') - op_kind = clang::OO_StarEqual; - break; - - case '/': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Slash; - else if (post_op_name[1] == '=' && post_op_name[2] == '\0') - op_kind = clang::OO_SlashEqual; - break; - - case '%': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Percent; - else if (post_op_name[1] == '=' && post_op_name[2] == '\0') - op_kind = clang::OO_PercentEqual; - break; - - - case '^': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Caret; - else if (post_op_name[1] == '=' && post_op_name[2] == '\0') - op_kind = clang::OO_CaretEqual; - break; - - case '&': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Amp; - else if (post_op_name[2] == '\0') - { - switch (post_op_name[1]) - { - case '=': op_kind = clang::OO_AmpEqual; break; - case '&': op_kind = clang::OO_AmpAmp; break; - } - } - break; - - case '|': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Pipe; - else if (post_op_name[2] == '\0') - { - switch (post_op_name[1]) - { - case '=': op_kind = clang::OO_PipeEqual; break; - case '|': op_kind = clang::OO_PipePipe; break; - } - } - break; - - case '~': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Tilde; - break; - - case '!': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Exclaim; - else if (post_op_name[1] == '=' && post_op_name[2] == '\0') - op_kind = clang::OO_ExclaimEqual; - break; - - case '=': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Equal; - else if (post_op_name[1] == '=' && post_op_name[2] == '\0') - op_kind = clang::OO_EqualEqual; - break; - - case '<': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Less; - else if (post_op_name[2] == '\0') - { - switch (post_op_name[1]) - { - case '<': op_kind = clang::OO_LessLess; break; - case '=': op_kind = clang::OO_LessEqual; break; - } - } - else if (post_op_name[3] == '\0') - { - if (post_op_name[2] == '=') - op_kind = clang::OO_LessLessEqual; - } - break; - - case '>': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Greater; - else if (post_op_name[2] == '\0') - { - switch (post_op_name[1]) - { - case '>': op_kind = clang::OO_GreaterGreater; break; - case '=': op_kind = clang::OO_GreaterEqual; break; - } - } - else if (post_op_name[1] == '>' && - post_op_name[2] == '=' && - post_op_name[3] == '\0') - { - op_kind = clang::OO_GreaterGreaterEqual; - } - break; - - case ',': - if (post_op_name[1] == '\0') - op_kind = clang::OO_Comma; - break; - - case '(': - if (post_op_name[1] == ')' && post_op_name[2] == '\0') - op_kind = clang::OO_Call; - break; - - case '[': - if (post_op_name[1] == ']' && post_op_name[2] == '\0') - op_kind = clang::OO_Subscript; - break; - } - - return true; -} - clang::EnumDecl * ClangASTContext::GetAsEnumDecl (const CompilerType& type) { @@ -7982,7 +8025,8 @@ ClangASTContext::AddMethodToCXXRecordType (lldb::opaque_compiler_type_t type, co // if we try to create a method and add it to the class, clang // will assert and crash, so we need to make sure things are // acceptable. - if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount (op_kind, num_params)) + const bool is_method = true; + if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount(is_method, op_kind, num_params)) return nullptr; cxx_method_decl = clang::CXXMethodDecl::Create (*getASTContext(), cxx_record_decl, |

