================ @@ -2482,6 +2485,134 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, return false; } +static int ClangToItaniumCtorKind(clang::CXXCtorType kind) { + switch (kind) { + case clang::CXXCtorType::Ctor_Complete: + return 1; + case clang::CXXCtorType::Ctor_Base: + return 2; + case clang::CXXCtorType::Ctor_CopyingClosure: + case clang::CXXCtorType::Ctor_DefaultClosure: + case clang::CXXCtorType::Ctor_Comdat: + llvm_unreachable("Unexpected constructor kind."); + } +} + +static int ClangToItaniumDtorKind(clang::CXXDtorType kind) { + switch (kind) { + case clang::CXXDtorType::Dtor_Deleting: + return 0; + case clang::CXXDtorType::Dtor_Complete: + return 1; + case clang::CXXDtorType::Dtor_Base: + return 2; + case clang::CXXDtorType::Dtor_Comdat: + llvm_unreachable("Unexpected destructor kind."); + } +} + +static std::optional<int> +GetItaniumCtorDtorVariant(llvm::StringRef discriminator) { + const bool is_ctor = discriminator.consume_front("C"); + if (!is_ctor && !discriminator.consume_front("D")) + return std::nullopt; + + uint64_t structor_kind; + if (!llvm::to_integer(discriminator, structor_kind)) + return std::nullopt; + + if (is_ctor) { + if (structor_kind > clang::CXXCtorType::Ctor_DefaultClosure) + return std::nullopt; + + return ClangToItaniumCtorKind( + static_cast<clang::CXXCtorType>(structor_kind)); + } + + if (structor_kind > clang::CXXDtorType::Dtor_Comdat) + return std::nullopt; + + return ClangToItaniumDtorKind(static_cast<clang::CXXDtorType>(structor_kind)); +} + +DWARFDIE SymbolFileDWARF::FindFunctionDefinition(const FunctionCallLabel &label, + const DWARFDIE &declaration) { + DWARFDIE definition; + llvm::DenseMap<int, DWARFDIE> structor_variant_to_die; + + // eFunctionNameTypeFull for mangled name lookup. + // eFunctionNameTypeMethod is required for structor lookups (since we look + // those up by DW_AT_name). + Module::LookupInfo info(ConstString(label.lookup_name), + lldb::eFunctionNameTypeFull | + lldb::eFunctionNameTypeMethod, + lldb::eLanguageTypeUnknown); + + m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) { + if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) + return IterationAction::Continue; + + auto spec = entry.GetAttributeValueAsReferenceDIE(DW_AT_specification); + if (!spec) + return IterationAction::Continue; + + if (spec != declaration) ---------------- Michael137 wrote:
> Okay, I guess this is why. I don't think this will work, for the reasons > outlined in the other comment. This needs to be a structural match between > the two DIEs, maybe facilitated by > DWARFASTParserClang::CopyUniqueClassMethodTypes. That's a good point. This mainly cropped up in the test-suite for type-units, but yea this need not be related to them. I guess this is similar to the other case you pointed out where the declaration DIE might be in a different module than the definition. For those cases we also ended up falling back on the old lookup. So the type-unit check is actually redundant because we can just rely on the fallback lookup. But if we want to support a wider range we'd have to change this specification check. Happy to try and change it to a structural match though. > Given then ABI tags are meant to allow different versions of the same class > to coexist, then if you want to support these different versions coexisting, > then the DWARF sort of has to contain the ABI tag information as it relies on > structural matches to connect DIEs from different compilation units. Maybe > this is irrelevant as you don't want to support this "coexistence" (I believe > you just want to "deal with" the presence of ABI tags), but I think this > might make a reasonable case for encoding the ABI tag information (in one way > or another) in DWARF. Hmm interesting point. Trying out the case where we have two ABI-tagged structures in two TUs, it looks like Clang/ld64 decide to emit two structure types with the same name only if there is a structural mismatch: ``` // lib.cpp #include <cassert> struct [[gnu::abi_tag("Lib")]] A { A() {} int mem = 5; } a; void func() { assert (a.mem == 5); } // main.cpp #include <cassert> struct [[gnu::abi_tag("Main")]] A { A() {} int mem = 10; } a; void func(); int main(int argc, char **argv) { func(); assert (a.mem == 10); return 0; } ``` Here `a` in `lib.o` would point to the `DW_TAG_structure_type` of `main.o`, but the subprogram definitions for the constructors are different (and local to each CU). If we change the structure layout though we get a `DW_TAG_structure_type` in each CU. But if they only differ by which methods they carry we only emit 1 definition! I guess for now the goal of the expression evaluator is to just support two versions of the same function (with different tags). Which is the easier version of this problem you outline. I don't think we had reservations about encoding ABI-tag information into DWARF. The concerns were: 1. debug-info size (libc++ uses these tags on a ton of APIs). 2. whether we want to rely on AST fidelity again 3. libc++ makes no guarantee that they'll continue annotating individual APIs in the future and might put the tags on namespaces/structures. At which point LLDB will need to take care to propagate the tags appropriately (maybe this will be handled by Clang out-of-the-box, though I haven't thought about this specific point in detail) Do you prefer us looking into alternatives to the approach in this PR? E.g., make DWARF do some of the heavy lifting? We could put e.g., the structor variant info into DWARF, alleviating the need for demangling, etc. https://github.com/llvm/llvm-project/pull/149827 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits