diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -162,14 +162,13 @@ const lldb::AccessType default_accessibility, lldb_private::ClangASTImporter::LayoutInfo &layout_info); - size_t - ParseChildParameters(clang::DeclContext *containing_decl_ctx, - const DWARFDIE &parent_die, bool skip_artificial, - bool &is_static, bool &is_variadic, - bool &has_template_params, - std::vector &function_args, - std::vector &function_param_decls, - unsigned &type_quals); + size_t ParseChildParameters( + clang::DeclContext *containing_decl_ctx, const DWARFDIE &parent_die, + bool skip_artificial, bool &is_static, bool &is_variadic, + bool &has_template_params, + std::vector &function_args, + std::vector &function_param_decls, + unsigned &type_quals, llvm::SmallVector &abi_tags); size_t ParseChildEnumerators(lldb_private::CompilerType &compiler_type, bool is_signed, uint32_t enumerator_byte_size, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -941,12 +941,12 @@ is_static = true; } + llvm::SmallVector abi_tags; if (die.HasChildren()) { bool skip_artificial = true; ParseChildParameters(containing_decl_ctx, die, skip_artificial, is_static, - is_variadic, has_template_params, - function_param_types, function_param_decls, - type_quals); + is_variadic, has_template_params, function_param_types, + function_param_decls, type_quals, abi_tags); } bool ignore_containing_context = false; @@ -1124,6 +1124,11 @@ is_static, attrs.is_inline, attrs.is_explicit, is_attr_used, attrs.is_artificial); + if (!abi_tags.empty()) + cxx_method_decl->addAttr(clang::AbiTagAttr::CreateImplicit( + m_ast.getASTContext(), abi_tags.data(), + abi_tags.size())); + type_handled = cxx_method_decl != nullptr; // Artificial methods are always handled even when we // don't create a new declaration for them. @@ -2366,11 +2371,13 @@ DWARFDeclContext decl_ctx = SymbolFileDWARF::GetDWARFDeclContext(die); sstr << decl_ctx.GetQualifiedName(); + llvm::SmallVector abi_tags; clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); ParseChildParameters(containing_decl_ctx, die, true, is_static, is_variadic, has_template_params, param_types, param_decls, - type_quals); + type_quals, abi_tags); + sstr << "("; for (size_t i = 0; i < param_types.size(); i++) { if (i > 0) @@ -3049,7 +3056,7 @@ bool skip_artificial, bool &is_static, bool &is_variadic, bool &has_template_params, std::vector &function_param_types, std::vector &function_param_decls, - unsigned &type_quals) { + unsigned &type_quals, llvm::SmallVector &abi_tags) { if (!parent_die) return 0; @@ -3159,6 +3166,15 @@ has_template_params = true; break; + case DW_TAG_LLVM_annotation: { + const char *name = die.GetName(); + if (!name || ::strcmp(name, "abi_tag") != 0) + break; + + if (const char *tag = + die.GetAttributeValueAsString(DW_AT_const_value, nullptr)) + abi_tags.push_back(tag); + } break; default: break; } diff --git a/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/Makefile b/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/Makefile @@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp lib.cpp +CXXFLAGS_EXTRAS := -glldb + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/TestExternalCtorDtorLookup.py b/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/TestExternalCtorDtorLookup.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/TestExternalCtorDtorLookup.py @@ -0,0 +1,51 @@ +""" +Test that we can constructors/destructors +without a linkage name because they are +marked DW_AT_external and the fallback +mangled-name-guesser in LLDB doesn't account +for ABI tags. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class ExternalCtorDtorLookupTestCase(TestBase): + + @skipIfWindows + def test(self): + self.build() + lldbutil.run_to_source_breakpoint(self, 'b\.getWrapper\(\)', + lldb.SBFileSpec('main.cpp', False)) + + self.expect_expr('b.sinkWrapper(b.getWrapper())', result_type='int', result_value='-1') + self.expect_expr('B{}.m_int', result_type='int', result_value='47') + self.expect_expr('D{}.m_int', result_type='int', result_value='-1') + self.filecheck("target module dump ast", __file__) +# CHECK: |-CXXRecordDecl {{.*}} struct B definition +# CHECK: | |-virtual public 'A' +# CHECK: | `-CXXConstructorDecl {{.*}} B 'void ()' +# CHECK: | `-AbiTagAttr {{.*}} TagB +# CHECK: |-CXXRecordDecl {{.*}} struct D definition +# CHECK: | `-CXXConstructorDecl {{.*}} D 'void ()' +# CHECK: | `-AbiTagAttr {{.*}} TagD +# CHECK: |-CXXRecordDecl {{.*}} struct A definition +# CHECK: | |-CXXConstructorDecl {{.*}} A 'void (int)' +# CHECK: | | |-ParmVarDecl {{.*}} 'int' +# CHECK: | | `-AbiTagAttr {{.*}} Ctor Int +# CHECK: | |-CXXConstructorDecl {{.*}} A 'void (float)' +# CHECK: | | |-ParmVarDecl {{.*}} 'float' +# CHECK: | | `-AbiTagAttr {{.*}} Ctor Float +# CHECK: | |-CXXConstructorDecl {{.*}} A 'void ()' +# CHECK: | | `-AbiTagAttr {{.*}} Ctor Default +# CHECK: | `-CXXDestructorDecl {{.*}} ~A 'void ()' +# CHECK: | `-AbiTagAttr {{.*}} Default Dtor + + # Confirm that we can call the C2 constructor for 'struct A' + self.expect('expression --top-level -- class Derived : virtual A {};') + self.expect_expr('Derived{}.m_int', result_type='int', result_value='-1') + + # Confirm that we can call the D2 destructor for 'struct A' + self.expect('expression Derived* $derived_ptr = new Derived()') + self.expect('expression delete $derived_ptr') diff --git a/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/lib.h b/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/lib.h new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/lib.h @@ -0,0 +1,15 @@ +#ifndef LIB_H_IN +#define LIB_H_IN + +template class Wrapper { +public: + [[gnu::abi_tag("test", "ctor")]] Wrapper(){}; + + [[gnu::abi_tag("test", "dtor")]] ~Wrapper(){}; +}; + +struct Foo {}; + +Wrapper getFooWrapper(); + +#endif // _H_IN diff --git a/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/lib.cpp b/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/lib.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/lib.cpp @@ -0,0 +1,3 @@ +#include "lib.h" + +Wrapper getFooWrapper() { return {}; } diff --git a/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/main.cpp b/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/external_ctor_dtor_lookup/main.cpp @@ -0,0 +1,40 @@ +#include "lib.h" + +struct Bar { + Wrapper getWrapper() { return Wrapper(); } + int sinkWrapper(Wrapper) { return -1; } +}; + +struct A { + int m_int = -1; + float m_float = -1.0; + [[gnu::abi_tag("Ctor", "Int")]] A(int a) : m_int(a) {} + [[gnu::abi_tag("Ctor", "Float")]] A(float f) : m_float(f) {} + [[gnu::abi_tag("Ctor", "Default")]] A() {} + [[gnu::abi_tag("Dtor", "Default")]] ~A() {} +}; + +struct B : virtual A { + [[gnu::abi_tag("TagB")]] B(); +}; +B::B() : A(47) {} + +struct D : B { + [[gnu::abi_tag("TagD")]] D() : A(4.7f) {} +}; + +struct X : public virtual A {}; + +int main() { + Bar b; + Wrapper w1; + Wrapper w2; + Wrapper w3 = getFooWrapper(); + Wrapper w4; + B b2; + D d; + A a; + auto *ptr = new X(); + delete ptr; + return b.sinkWrapper(b.getWrapper()); +}