Index: include/lldb/Symbol/ClangASTContext.h =================================================================== --- include/lldb/Symbol/ClangASTContext.h +++ include/lldb/Symbol/ClangASTContext.h @@ -390,10 +390,9 @@ static clang::DeclContext * GetAsDeclContext (clang::ObjCMethodDecl *objc_method_decl); - static bool - CheckOverloadedOperatorKindParameterCount (uint32_t op_kind, - uint32_t num_params); + CheckOverloadedOperatorKindParameterCount(bool is_method, clang::OverloadedOperatorKind op_kind, + uint32_t num_params); bool FieldIsBitfield (clang::FieldDecl* field, @@ -1190,6 +1189,9 @@ return clang::QualType(); } + clang::DeclarationName + GetDeclarationName(const char *name, const CompilerType &function_clang_type); + protected: //------------------------------------------------------------------ // Classes that inherit from ClangASTContext can see and modify these Index: packages/Python/lldbsuite/test/lang/cpp/global_operators/TestCppGlobalOperators.py =================================================================== --- packages/Python/lldbsuite/test/lang/cpp/global_operators/TestCppGlobalOperators.py +++ packages/Python/lldbsuite/test/lang/cpp/global_operators/TestCppGlobalOperators.py @@ -10,8 +10,7 @@ mydir = TestBase.compute_mydir(__file__) - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr21765") - def test_with_run_command(self): + def prepare_executable_and_get_frame(self): self.build() # Get main source file @@ -42,8 +41,11 @@ self.assertTrue(process.GetState() == lldb.eStateStopped, PROCESS_STOPPED) thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) - # Check if global operators are evaluated - frame = thread.GetSelectedFrame() + return thread.GetSelectedFrame() + + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr21765") + def test_equals_operator(self): + frame = self.prepare_executable_and_get_frame() test_result = frame.EvaluateExpression("operator==(s1, s2)") self.assertTrue(test_result.IsValid() and test_result.GetValue() == "false", "operator==(s1, s2) = false") @@ -53,3 +55,25 @@ test_result = frame.EvaluateExpression("operator==(s2, s3)") self.assertTrue(test_result.IsValid() and test_result.GetValue() == "false", "operator==(s2, s3) = false") + + def do_new_test(self, frame, expr, expected_value_name): + """Evaluate a new expression, and check its result""" + + expected_value = frame.FindValue(expected_value_name, lldb.eValueTypeVariableGlobal) + self.assertTrue(expected_value.IsValid()) + + expected_value_addr = expected_value.AddressOf() + self.assertTrue(expected_value_addr.IsValid()) + + got = frame.EvaluateExpression(expr) + self.assertTrue(got.IsValid()) + self.assertEqual(got.GetValueAsUnsigned(), expected_value_addr.GetValueAsUnsigned()) + got_type = got.GetType() + self.assertTrue(got_type.IsPointerType()) + self.assertEqual(got_type.GetPointeeType().GetName(), "Struct") + + def test_operator_new(self): + frame = self.prepare_executable_and_get_frame() + + self.do_new_test(frame, "new Struct()", "global_new_buf") + self.do_new_test(frame, "new(new_tag) Struct()", "tagged_new_buf") Index: packages/Python/lldbsuite/test/lang/cpp/global_operators/main.cpp =================================================================== --- packages/Python/lldbsuite/test/lang/cpp/global_operators/main.cpp +++ packages/Python/lldbsuite/test/lang/cpp/global_operators/main.cpp @@ -1,3 +1,10 @@ +#include + +struct new_tag_t +{ +}; +new_tag_t new_tag; + struct Struct { int value; }; @@ -6,6 +13,25 @@ return a.value == b.value; } +typedef char buf_t[sizeof(Struct)]; +buf_t global_new_buf, tagged_new_buf; + +// This overrides global operator new +// This function and the following does not actually allocate memory. We are merely +// trying to make sure it is getting called. +void * +operator new(std::size_t count) +{ + return &global_new_buf; +} + +// A custom allocator +void * +operator new(std::size_t count, const new_tag_t &) +{ + return &tagged_new_buf; +} + int main() { Struct s1, s2, s3; s1.value = 3; Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp =================================================================== --- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -2069,13 +2069,10 @@ 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); Index: source/Symbol/ClangASTContext.cpp =================================================================== --- source/Symbol/ClangASTContext.cpp +++ source/Symbol/ClangASTContext.cpp @@ -130,6 +130,241 @@ 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 @@ } 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 @@ 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 @@ #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(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 @@ 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); @@ -7321,222 +7580,6 @@ 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) { @@ -7923,7 +7966,8 @@ // 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,