This is part of a patch series to clean up the
`TypeSystemClang::IsFloatingPointType` API. Currently the API is a bit
of a foot-gun because it returns `true` for both Complex floats and
vector types whose element types are floats, but most call-sites
probably don't handle these correctly. The former aligns with the
`clang::Type::isFloatingType` API, but the latter doesn't. This specific
implementation choice will be addressed in a separate patch. This patch
adds a new `CompilerType::IsRealFloatingPointType` API which clients can
use to query about non-complex floats (named after the similarly named
`clang::Type::isRealFloatingType`).
This allows us to clean up some of the callers which only wanted to
handle non-complex floats. I cleaned those up as part of this patch.
Wherever we checked for `is_float && !is_complex && !is_vector_type` i
just replaced it with the new API.
On encountering complex/vector floats, some of the ABI plugins would set
an error but then immediately overwrite the error to something else. I
just removed those branches entirely, since it was essentially dead
code.
Some of the diff is large because of un-indentation when we remove
if-guards, so I would recommend turning off white-space diff when
reviewing.
Currently we forcefully complete C++ types if we can't find their
definition for layout purposes. This ensures that we at least don't
crash in Clang when laying out the type. The definition is required for
types of members/array elements/base classes for the purposes of
calculating their layout. This is also true for Obj-C types, but we
haven't been forcefully completing those.
The test-case that's being un-XFAILed in this patch demonstrates a case
where not completing the super-class forcefully causes a clang crash.
rdar://168440264
Uncommenting `ENABLE_DEBUG_PRINTF` wasn't compiling on top-of-tree. This code may have been useful for debugging locally in the past but it doesn't seem compelling to keep this in the source-tree. Especially because it doesn't compile, indicating it's most likely not used.
This patch removes `DEBUG_PRINTF` entirely.
Depends on:
* https://github.com/llvm/llvm-project/pull/170132
Clang gained the `-gtemplate-alias` not too long ago, which emits C++
alias templates as `DW_TAG_template_alias` (instead of
`DW_TAG_typedef`). The main difference is that `DW_TAG_template_alias`
has `DW_TAG_template_XXX` children. The flag was not enabled by default
because consumers (mainly LLDB) didn't know how to handle it. This patch
adds rudimentary support for debugging with `DW_TAG_template_alias`.
This patch simply creates the same kind of `TypedefDecl` as we do for
`DW_TAG_typedef`. The more complete solution would be to create a
`TypeAliasTemplateDecl` and associated `TypeAliasDecl`. But that would
require DWARF to carry generic template information, but currently each
`DW_TAG_template_alias` represents a concrete instantiation. We could
probably hack up some working AST representation that includes the
template parameters, but I currently don't see a compelling reason to.
All we need is the `DW_AT_name` and the `DW_AT_type` that the typedef
refers to.
rdar://137499401
We almost had RTTI support for `DWARFASTParserClang`, but because
`classof` was protected, using `llvm::cast`/etc. on it would fail to
compile with:
```
llvm/include/llvm/Support/Casting.h:64:57: error: 'classof' is a protected member of 'DWARFASTParserClang'
64 | static inline bool doit(const From &Val) { return To::classof(&Val); }
| ^
llvm/include/llvm/Support/Casting.h:110:32: note: in instantiation of member function 'llvm::isa_impl<DWARFASTParserClang, lldb_private::plugin::dwarf::DWARFASTParser>::doit' requested here
110 | return isa_impl<To, From>::doit(*Val);
```
This patch makes `classof` public and turns `static_cast`s of
`DWARFASTParserClang` into `llvm::cast`s.
Currently LLDB's `ParseRustVariantPart` generates the following
`CXXRecordDecl` for a Rust enum
```rust
enum AA {
A(u8)
}
```
```
CXXRecordDecl 0x5555568d5970 <<invalid sloc>> <invalid sloc> struct AA
|-CXXRecordDecl 0x5555568d5ab0 <<invalid sloc>> <invalid sloc> union test_issue::AA$Inner definition
| |-CXXRecordDecl 0x5555568d5d18 <<invalid sloc>> <invalid sloc> struct A$Variant definition
| | |-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable trivial
| | | `-Destructor simple irrelevant trivial needs_implicit
| | `-FieldDecl 0x555555a77880 <<invalid sloc>> <invalid sloc> value 'test_issue::AA::A'
| `-FieldDecl 0x555555a778f0 <<invalid sloc>> <invalid sloc> $variant$ 'test_issue::AA::test_issue::AA$Inner::A$Variant'
|-CXXRecordDecl 0x5555568d5c48 <<invalid sloc>> <invalid sloc> struct A definition
| `-FieldDecl 0x555555a777e0 <<invalid sloc>> <invalid sloc> __0 'unsigned char'
`-FieldDecl 0x555555a77960 <<invalid sloc>> <invalid sloc> $variants$ 'test_issue::AA::test_issue::AA$Inner'
```
While when the Rust enum type name is the same as its variant name, the
generated `CXXRecordDecl` becomes the following – there's a circular
reference between `struct A$Variant` and `struct A`, causing #163048.
```rust
enum A {
A(u8)
}
```
```
CXXRecordDecl 0x5555568d5760 <<invalid sloc>> <invalid sloc> struct A
|-CXXRecordDecl 0x5555568d58a0 <<invalid sloc>> <invalid sloc> union test_issue::A$Inner definition
| |-CXXRecordDecl 0x5555568d5a38 <<invalid sloc>> <invalid sloc> struct A$Variant definition
| | `-FieldDecl 0x5555568d5b70 <<invalid sloc>> <invalid sloc> value 'test_issue::A' <---- bug here
| `-FieldDecl 0x5555568d5be0 <<invalid sloc>> <invalid sloc> $variant$ 'test_issue::A::test_issue::A$Inner::A$Variant'
`-FieldDecl 0x5555568d5c50 <<invalid sloc>> <invalid sloc> $variants$ 'test_issue::A::test_issue::A$Inner'
```
The problem was caused by `GetUniqueTypeNameAndDeclaration` not
returning the correct qualified name for DWARF DIE `test_issue::A::A`,
instead, it returned `A`. This caused `ParseStructureLikeDIE` to find
the wrong type `test_issue::A` and returned early.
The failure in `GetUniqueTypeNameAndDeclaration` appears to stem from a
language check that returns early unless the language is C++. I changed
it so Rust follows the C++ path rather than returning. I’m not entirely
sure this is the right approach — Rust’s qualified name rules look
similar, but not identical? Alternatively, we could add a Rust-specific
implementation that forms qualified names according to Rust's rules.
Depends on:
* https://github.com/llvm/llvm-project/pull/165686
This patch ensures we make use of the `DW_AT_bit_size` on
`DW_TAG_base_type`s (which since
https://github.com/llvm/llvm-project/pull/164372 can exist on
`_BitInt`s) and adjusts `TypeSystemClang` to recognize `_BitInt`.
For DWARF from older versions of Clang that didn't emit a
`DW_AT_bit_size`, we would create `_BitInt`s using the byte-size. Not
sure we can do much better than that. But the situation beforehand
wasn't much better.
Before:
```
(lldb) v
(char) a = '\x01'
(unsigned char) b = '\x01'
(long) c = 2
(unsigned long) d = 2
```
After:
```
(lldb) v
(_BitInt(2)) a = 1
(unsigned _BitInt(2)) b = 1
(_BitInt(52)) c = 2
(unsigned _BitInt(52)) d = 2
```
Fixes https://github.com/llvm/llvm-project/issues/110273
Similar motivation to https://github.com/llvm/llvm-project/pull/165702.
It was unused in all callsites and inconsistent with other APIs like
`IsIntegerType` (which doesn't take a `count` parameter).
If we ever need a "how many elements does this type represent", we can
implement one with a new TypeSystem API that does exactly that.
Some callsites checked for `count == 1` previously, but I suspect what
they intended to do is check for whether it's a vector type or complex
type, before reading the FP register. I'm somewhat confident that's the
case because the `TypeSystemClang::GetTypeInfo` currently incorrectly
sets the integer and floating point bits for complex and vector types
(will fix separately). But some architectures might choose to pass
single-element vectors in scalar registers. I should probably changes
these to check the vector element size.
All the `count == 2 && is_complex` were redundant because `count == 2`
iff `is_complex == true`. So I just removed the count check there.
One (DWARF-spec compliant) exmample is:
https://github.com/llvm/llvm-project/pull/164372, where we attach a
`DW_AT_bit_size` to `_BitInt` types that can't be exactly described by a
byte-size.
This patch adds support for `DW_AT_bit_size` to `DWARFASTParserClang`
when parsing type tags.
Note, we don't use this bit-size yet, but will do so in follow-up
patches.
[lldb][DWARFASTParserClang] Added a check for the specialization
existence
While debugging an application with incorrect dwarf information, where
DW_TAG_template_value_parameter was lost, I found that lldb does not
check that the corresponding specialization exists. As a result, at the
stage when ASTImporter works, the type is completed in such a way that
it inherits from itself. And during the calculation of layout, an
infinite recursion occurs. To catch this error, I added a corresponding
check
at the stage of restoring the type from dwarf information. I also added
a
trivial assert in clang to check that the class does not inherit from
itself.
First time check was introduced in
`fa3ab4599d717feedbb83e08e7f654913942520b` to work around a debug-info
generation bug in Clang. This bug was fixed in Clang-4. The check has
since been adjusted (first in
`808ff186f6a6ba1fd38cc7e00697cd82f4afe540`, and then most recently in
`370db9c62910195e664e82dde6f0adb3e255a4fd`).
This check is getting quite convoluted, and all it does is turn an
`array[1]` into an `array[0]` type when it is deemed correct. At this
point the workaround probably never fires, apart from actually valid
codegen. This patch removes the special conditions and emits the error
specifically in those cases where we know the DWARF is malformed.
Added some shell tests for the error case.
GCC doesn't add DW_AT_data_member_location attributes to the
DW_TAG_member children of DW_TAG_union_type types. An error was being
emitted incorrectly for these cases fr om the DWARFASTParserClang. This
fixes that issue and adds a test.
Depends on
* https://github.com/llvm/llvm-project/pull/148877
* https://github.com/llvm/llvm-project/pull/155483
* https://github.com/llvm/llvm-project/pull/155485
* https://github.com/llvm/llvm-project/pull/154137
* https://github.com/llvm/llvm-project/pull/154142
This patch is an implementation of [this
discussion](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816/7)
about handling ABI-tagged structors during expression evaluation.
**Motivation**
LLDB encodes the mangled name of a `DW_TAG_subprogram` into `AsmLabel`s
on function and method Clang AST nodes. This means that when calls to
these functions get lowered into IR (when running JITted expressions),
the address resolver can locate the appropriate symbol by mangled name
(and it is guaranteed to find the symbol because we got the mangled name
from debug-info, instead of letting Clang mangle it based on AST
structure). However, we don't do this for
`CXXConstructorDecl`s/`CXXDestructorDecl`s because these structor
declarations in DWARF don't have a linkage name. This is because there
can be multiple variants of a structor, each with a distinct mangling in
the Itanium ABI. Each structor variant has its own definition
`DW_TAG_subprogram`. So LLDB doesn't know which mangled name to put into
the `AsmLabel`.
Currently this means using ABI-tagged structors in LLDB expressions
won't work (see [this
RFC](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816)
for concrete examples).
**Proposed Solution**
The `FunctionCallLabel` encoding that we put into `AsmLabel`s already
supports stuffing more info about a DIE into it. So this patch extends
the `FunctionCallLabel` to contain an optional discriminator (a sequence
of bytes) which the `SymbolFileDWARF` plugin interprets as the
constructor/destructor variant of that DIE. So when searching for the
definition DIE, LLDB will include the structor variant in its heuristic
for determining a match.
There's a few subtleties here:
1. At the point at which LLDB first constructs the label, it has no way
of knowing (just by looking at the debug-info declaration), which
structor variant the expression evaluator is supposed to call. That's
something that gets decided when compiling the expression. So we let the
Clang mangler inject the correct structor variant into the `AsmLabel`
during JITing. I adjusted the `AsmLabelAttr` mangling for this in
https://github.com/llvm/llvm-project/pull/155485. An option would've
been to create a new Clang attribute which behaved like an `AsmLabel`
but with these special semantics for LLDB. My main concern there is that
we'd have to adjust all the `AsmLabelAttr` checks around Clang to also
now account for this new attribute.
2. The compiler is free to omit the `C1` variant of a constructor if the
`C2` variant is sufficient. In that case it may alias `C1` to `C2`,
leaving us with only the `C2` `DW_TAG_subprogram` in the object file.
Linux is one of the platforms where this occurs. For those cases I added
a heuristic in `SymbolFileDWARF` where we pick `C2` if we asked for `C1`
but it doesn't exist. This may not always be correct (e.g., if the
compiler decided to drop `C1` for other reasons).
3. In https://github.com/llvm/llvm-project/pull/154142 Clang will emit
`C4`/`D4` variants of ctors/dtors on declarations. When resolving the
`FunctionCallLabel` we will now substitute the actual variant that Clang
told us we need to call into the mangled name. We do this using LLDB's
`ManglingSubstitutor`. That way we find the definition DIE exactly the
same way we do for regular function calls.
4. In cases where declarations and definitions live in separate modules,
the DIE ID encoded in the function call label may not be enough to find
the definition DIE in the encoded module ID. For those cases we fall
back to how LLDB used to work: look up in all images of the target. To
make sure we don't use the unified mangled name for the fallback lookup,
we change the lookup name to whatever mangled name the FunctionCallLabel
resolved to.
rdar://104968288
This upstreams https://github.com/swiftlang/llvm-project/pull/10313.
If we detect a situation where a forward declaration is C++ and the
definition DIE is Objective-C, then just don't try to complete the type
(it would crash otherwise). In the long term we might want to add
support for completing such types.
We've seen real world crashes when debugging WebKit and wxWidgets
because of this. Both projects forward declare ObjC++ decls in the way
shown in the test.
rdar://145959981
This reintroduces `Type.h`, having earlier been renamed to `TypeBase.h`,
as a redirection to `TypeBase.h`, and redirects most users to include
the former instead.
This is a preparatory patch for being able to provide inline definitions
for `Type` methods which would otherwise cause a circular dependency
with `Decl{,CXX}.h`.
Doing these operations into their own NFC patch helps the git rename
detection logic work, preserving the history.
This patch makes clang just a little slower to build (~0.17%), just
because it makes more code indirectly include `DeclCXX.h`.
This is a preparatory patch, to be able to provide inline definitions
for `Type` functions which depend on `Decl{,CXX}.h`. As the latter also
depends on `Type.h`, this would not be possible without some
reorganizing.
Splitting this rename into its own patch allows git to track this as a
rename, and preserve all git history, and not force any code
reformatting.
A later NFC patch will reintroduce `Type.h` as redirection to
`TypeBase.h`, rewriting most places back to directly including `Type.h`
instead of `TypeBase.h`, leaving only a handful of places where this is
necessary.
Then yet a later patch will exploit this by making more stuff inline.
Fixes a bug that surfaces in frame recognizers.
Details about the bug:
A new frame recognizer is configured to match a specific symbol
(`swift_willThrow`). This is an `extern "C"` symbol defined in a C++
source file. When Swift is built with debug info, the function
`ParseFunctionFromDWARF` will use the debug info to construct a function
name that looks like a C++ declaration (`::swift_willThrow(void *,
SwiftError**)`). The `Mangled` instance will have this string as its
`m_demangled` field, and have _no_ string for its `m_mangled` field.
The result is the frame recognizer would not match the symbol to the
name (`swift_willThrow` != `::swift_willThrow(void *, SwiftError**)`.
By changing `ParseFunctionFromDWARF` to assign both a demangled name and
a mangled, frame recognizers can successfully match symbols in this
configuration.
LLDB currently attaches `AsmLabel`s to `FunctionDecl`s such that that
the `IRExecutionUnit` can determine which mangled name to call (we can't
rely on Clang deriving the correct mangled name to call because the
debug-info AST doesn't contain all the info that would be encoded in the
DWARF linkage names). However, we don't attach `AsmLabel`s for structors
because they have multiple variants and thus it's not clear which
mangled name to use. In the [RFC on fixing expression evaluation of
abi-tagged
structors](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816)
we discussed encoding the structor variant into the `AsmLabel`s.
Specifically in [this
thread](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816/7)
we discussed that the contents of the `AsmLabel` are completely under
LLDB's control and we could make use of it to uniquely identify a
function by encoding the exact module and DIE that the function is
associated with (mangled names need not be enough since two identical
mangled symbols may live in different modules). So if we already have a
custom `AsmLabel` format, we can encode the structor variant in a
follow-up (the current idea is to append the structor variant as a
suffix to our custom `AsmLabel` when Clang emits the mangled name into
the JITted IR). Then we would just have to teach the `IRExecutionUnit`
to pick the correct structor variant DIE during symbol resolution. The
draft of this is available
[here](https://github.com/llvm/llvm-project/pull/149827)
This patch sets up the infrastructure for the custom `AsmLabel` format
by encoding the module id, DIE id and mangled name in it.
**Implementation**
The flow is as follows:
1. Create the label in `DWARFASTParserClang`. The format is:
`$__lldb_func:module_id:die_id:mangled_name`
2. When resolving external symbols in `IRExecutionUnit`, we parse this
label and then do a lookup by DIE ID (or mangled name into the module if
the encoded DIE is a declaration).
Depends on https://github.com/llvm/llvm-project/pull/151355
Split out from https://github.com/llvm/llvm-project/pull/148877
This patch prepares `TypeSystemClang` APIs to take `AsmLabel`s which
concatenated strings (hence `std::string`) instead of a plain `const
char*`.
Eliminate the `lldb_private::dwarf` namespace, in favor of using
`llvm::dwarf` directly. The latter is shorter, and this avoids ambiguity
in the ABI plugins that define a `dwarf` namespace inside an anonymous
namespace.
This reverts commit 877511920dcf36463e06746d626e8876583a6abd.
This fixes the `TestObjCInBlockVars.py` LLDB API test.
The issue was that `GetCXXObjectParameter` wouldn't deduce the object
parameter of Objective-C method definitions correctly. In DWARF those
don't have a `DW_AT_specification` (so no link back to a DeclContext
that is a class type). The fix is to only check the validity of the
DeclContext DIE *if* no `DW_AT_object_pointer` exists on the DIE. If
`DW_AT_object_pointer` does exist, we should just always use that as the
object_parameter.
We can just always use `GetCXXObjectParameter` instead. We've only used
this attribute to set the object parameter name on ClangASTMetadata,
which doesn't seem like good enough justification to keep it around.
Depends on https://github.com/llvm/llvm-project/pull/144879
My goal is to remove the `object_pointer` member on
`ParsedDWARFTypeAttributes` since it's duplicating information that we
retrieve with `GetCXXObjectParameter` anyway. To continue having
coverage for the `DW_AT_object_pointer` code-paths, instead of checking
the
`attrs.object_pointer` I'm now calling `GetCXXObjectParameter` directly.
We could find some very roundabout way to go via the Clang AST to check
that the object parameter was parsed correctly, but that quickly became
quite painful.
Depends on https://github.com/llvm/llvm-project/pull/144876
I'm trying to call `GetCXXObjectParameter` from unit-tests in a
follow-up patch and taking a `DWARFDIE` instead of `clang::DeclContext`
makes that much simpler. These should be equivalent, since all we're
trying to check is that the parent context is a record type.
Add an overloaded `GetTypeSystem` to specify the expected type system subclass. Changes code from `GetTypeSystem().dyn_cast_or_null<TypeSystemClang>()` to `GetTypeSystem<TypeSystemClang>()`.
This fixes a regression caused by us starting to parse types from
declarations. The code in TypeSystemClang was assuming that the value
held in ClangASTMetadata was authoritative, but this isn't (and cannot)
be the case when the type is parsed from a forward-declaration.
For the fix, I add a new "don't know" state to ClangASTMetadata, and
make sure DWARFASTParserClang sets it only when it encounters a forward
declaration. In this case, the type system will fall back to completing
the type.
This does mean that we will be completing more types than before, but
I'm hoping this will offset by the fact that we don't search for
definition DIEs eagerly. In particular, I don't expect it to make a
difference in -fstandalone-debug scenarios, since types will nearly
always be present as definitions.
To avoid this cost, we'd need to create some sort of a back channel to
query the DWARFASTParser about the dynamicness of the type without
actually completing it. I'd like to avoid that if it is not necessary.
This patch pushes the error handling boundary for the GetBitSize()
methods from Runtime into the Type and CompilerType APIs. This makes it
easier to diagnose problems thanks to more meaningful error messages
being available. GetBitSize() is often the first thing LLDB asks about a
type, so this method is particularly important for a better user
experience.
rdar://145667239
This patch adds support for template arguments of
`clang::TemplateArgument::ArgKind::StructuralValue` kind (added in
https://github.com/llvm/llvm-project/pull/78041). These are used for
non-type template parameters such as floating point constants. When LLDB
created `clang::NonTypeTemplateParmDecl`s, it previously assumed
integral values, this patch accounts for structural values too.
Anywhere LLDB assumed a `DW_TAG_template_value_parameter` was
`Integral`, it will now also check for `StructuralValue`, and will
unpack the `TemplateArgument` value and type accordingly.
We can rely on the fact that any `TemplateArgument` of `StructuralValue`
kind that the `DWARFASTParserClang` creates will have a valid value,
because it gets those from `DW_AT_const_value`.
This patch consumes the `DW_AT_APPLE_enum_kind` attribute added in
https://github.com/llvm/llvm-project/pull/124752 and turns it into a
Clang attribute in the AST. This will currently be used by the Swift
language plugin when it creates `EnumDecl`s from debug-info and passes
it to Swift compiler, which expects these attributes
The `DWARFASTParserClang` reads enum values as `int64_t`s regardless of
the enumerators signedness. Then we pass it to
`AddEnumerationValueToEnumerationType` and only then do we create an
`APSInt` from it. However, there are other places where we read/pass
around the enum value as unsigned. This patch makes sure we consistently
use the same integer type for the enum value and let `APSInt` take care
of signedness. This shouldn't have any observable effect.
I tried using `CompleteEnumType` to replace some duplicated code in
`DWARFASTParserClang::ParseEnum` but tests started failing.
`CompleteEnumType` parses/attaches the child enumerators using the
signedness it got from `CompilerType::IsIntegerType`. However, this
would only report the correct signedness for builtin integer types
(never for `clang::EnumType`s). We have a different API for that in
`CompilerType::IsIntegerOrEnumerationType` which could've been used
there instead. This patch calls `IsEnumerationIntegerTypeSigned` to
determine signedness because we always pass an enum type into
`CompleteEnumType` anyway.
Based on git history this has been the case for a long time, but
possibly never caused issues because `ParseEnum` was completing the
definition manually instead of through `CompleteEnumType`.
I couldn't find a good way to test `CompleteEnumType` on its own because
it expects an enum type to be passed to it, which only gets created in
`ParseEnum` (at which point we already call `CompleteEnumType`). The
only other place we call `CompleteEnumType` at is in
[`CompleteTypeFromDWARF`](466217eb03/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp (L2260-L2262)).
Though I think we don't actually ever end up calling into that codepath
because we eagerly complete enum definitions. Maybe we can remove that
call to `CompleteEnumType` in a follow-up.
While sifting through this part of the code I noticed that when we parse
C++ methods, `DWARFASTParserClang` creates two sets of `ParmVarDecls`,
one in `ParseChildParameters` and once in `AddMethodToCXXRecordType`.
The former is unused when we're dealing with methods. Moreover, the
`ParmVarDecls` we created in `ParseChildParameters` were created with an
incorrect `clang::DeclContext` (namely the DeclContext of the function,
and not the function itself). In Clang, there's
`ParmVarDecl::setOwningFunction` to adjust the DeclContext of a
parameter if the parameter was created before the FunctionDecl. But we
never used it.
This patch removes the `ParmVarDecl` creation from
`ParseChildParameters` and instead creates a
`TypeSystemClang::CreateParameterDeclarations` that ensures we set the
DeclContext correctly.
Note there is one differences in how `ParmVarDecl`s would be created
now: we won't set a ClangASTMetadata entry for any of the parameters. I
don't think this was ever actually useful for parameter DIEs anyway.
This wasn't causing any concrete issues (that I know of), but was quite
surprising. And this way of setting the parameters seems easier to
reason about (in my opinion).
This is the behavior expected by DWARF. It also requires some fixups to
algorithms which were storing the addresses of some objects (Blocks and
Variables) relative to the beginning of the function.
There are plenty of things that still don't work in this setups, but
this change is sufficient for the expression evaluator to correctly
recognize the entry point of a function in this case.
This reverts commit a8020930a8174d84da04fa91b6fef244207f42f5.
Relands original commit but fixing the unit-test to consume the
`llvm::Expected` error object.
Reverts llvm/llvm-project#124096
Broke linux CI:
```
Note: This is test shard 7 of 42.
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from DWARFASTParserClangTests
[ RUN ] DWARFASTParserClangTests.TestParseSubroutine_ExplicitObjectParameter
Expected<T> must be checked before access or destruction.
Expected<T> value was in success state. (Note: Expected<T> values in success mode must still be checked prior to being destroyed).
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0 SymbolFileDWARFTests 0x0000560271ee5ba7
1 SymbolFileDWARFTests 0x0000560271ee3a2c
2 SymbolFileDWARFTests 0x0000560271ee63ea
3 libc.so.6 0x00007f3e54e5b050
4 libc.so.6 0x00007f3e54ea9e2c
5 libc.so.6 0x00007f3e54e5afb2 gsignal + 18
6 libc.so.6 0x00007f3e54e45472 abort + 211
7 SymbolFileDWARFTests 0x0000560271e79d51
8 SymbolFileDWARFTests 0x0000560271e724f7
9 SymbolFileDWARFTests 0x0000560271f39e2c
10 SymbolFileDWARFTests 0x0000560271f3b368
11 SymbolFileDWARFTests 0x0000560271f3c053
12 SymbolFileDWARFTests 0x0000560271f4cf67
13 SymbolFileDWARFTests 0x0000560271f4c18a
14 SymbolFileDWARFTests 0x0000560271f2561c
15 libc.so.6 0x00007f3e54e4624a
16 libc.so.6 0x00007f3e54e46305 __libc_start_main + 133
17 SymbolFileDWARFTests 0x0000560271e65161
```
LLDB deduces the CV-qualifiers and storage class of a C++ method from
the object parameter. Currently it assumes that parameter is implicit
(and is a pointer type with the name "this"). This isn't true anymore in
C++23 with explicit object parameters. To support those we can simply
check the `DW_AT_object_pointer` of the subprogram DIE (works for both
declarations and definitions) when searching for the object parameter.
We can also remove the check for `eEncodingIsPointerUID`, because in C++
an artificial parameter called `this` is only ever the implicit object
parameter (at least for all the major compilers).
This patch continues simplifying `ParseChildParameters` by moving out
the logic that parses the first parameter of a function DIE into a
helper function. Since with GCC (and lately Clang) function declarations
have `DW_AT_object_pointer`s, we should be able to check for the
attribute's existence to determine if a function is static (and also
deduce CV-qualifiers from it). This will be useful for cases where the
object parameter is explicit (which is possible since C++23).
This should be NFC. I added a FIXME to places where we assume an
implicit object parameter (which will be addressed in a follow-up
patch).
We used to guard parsing of the CV-qualifiers of the "this" parameter
with a `encoding_mask & Type::eEncodingIsPointerUID`, which is
incorrect, because `eEncodingIsPointerUID` cannot be used as a bitmask
directly (see https://github.com/llvm/llvm-project/issues/120856). This
patch corrects this, but it should still be NFC because any parameter in
C++ called "this" *is* an implicit object parameter.
This patch refactors `ParseChildParameters` in a way which makes it (in
my opinion) more readable, removing some redundant local variables in
the process and reduces the scope of some variables.
**Motivation**
Since `DW_AT_object_pointer`s are now attached to declarations, we can
test for their existence to check whether a C++ method is static or not
(whereas currently we're deducing this from `ParseChildParameters` based
on some heuristics we know are true for most compilers). So my plan is
to move the code for determining `type_quals` and `is_static` out of
`ParseChildParameters`. The refactoring in this PR will make this
follow-up patch hopefully easier to review.
**Testing**
* This should be NFC. The main change is that we now no longer iterate
over `GetAttributes()` but instead retrieve the name, type and
is_artificial attributes of the parameters individually.
In https://github.com/llvm/llvm-project/pull/122742 we will start
attaching DW_AT_object_pointer to method declarations (in addition to
definitions).
Currently when LLDB parses a `DW_TAG_subprogram` definition, it will
parse all the attributes of the declaration as well. If we have
`DW_AT_object_pointer` on both, then we would overwrite the more
specific attribute that we got from the defintion with the one from the
specification. This is problematic because LLDB relies on getting the
`DW_AT_name` from the `DW_AT_object_pointer`, which doesn't exist on the
specification.
Note GCC does attach `DW_AT_object_pointer` on declarations *and*
definitions already (see https://godbolt.org/z/G1GvddY48), so there's
definitely some expressions that will fail for GCC compiled binaries.
This patch will fix those cases (e.g., I would expect `TestConstThis.py`
to fail with GCC).
The problem here manifests as follows:
1. We are stopped in main.o, so the first `ParseTypeFromDWARF` on
`FooImpl<char>` gets called on `main.o`'s SymbolFile. This adds a
mapping from *declaration die* -> `TypeSP` into `main.o`'s
`GetDIEToType` map.
2. We then `CompleteType(FooImpl<char>)`. Depending on the order of
entries in the debug-map, this might call `CompleteType` on `lib.o`'s
SymbolFile. In which case, `GetDIEToType().lookup(decl_die)` will return
a `nullptr`. This is already a bit iffy because some of the surrounding
code assumes we don't call `CompleteTypeFromDWARF` with a `nullptr`
`Type*`. E.g., `CompleteEnumType` blindly dereferences it (though enums
will never encounter this because their definition is fetched in
ParseEnum, unlike for structures).
3. While in `CompleteTypeFromDWARF`, we call `ParseTypeFromDWARF` again.
This will parse the member function `FooImpl::Create` and its return
type which is a typedef to `FooImpl*`. But now we're inside `lib.o`'s
SymbolFile, so we call it on the definition DIE. In step (2) we just
inserted a `nullptr` into `GetDIEToType` for the definition DIE, so we
trivially return a `nullptr` from `ParseTypeFromDWARF`. Instead of
reporting back this parse failure to the user LLDB trucks on and marks
`FooImpl::Ref` to be `void*`.
This test-case will trigger an assert in `TypeSystemClang::VerifyDecl`
even if we just `frame var` (but only in debug-builds). In release
builds where this function is a no-op, we'll create an incorrect Clang
AST node for the `Ref` typedef.
The proposed fix here is to share the `GetDIEToType` map between
SymbolFiles if a debug-map exists.
**Alternatives considered**
* Check the `GetDIEToType` map of the `SymbolFile` that the declaration
DIE belongs to. The assumption here being that if we called
`ParseTypeFromDWARF` on a declaration, the `GetDIEToType` map that the
result was inserted into was the one on that DIE's SymbolFile. This was
the first version of this patch, but that felt like a weaker version
sharing the map. It complicates the code in `CompleteType` and is less
consistent with the other bookkeeping structures we already share
between SymbolFiles
* Return from `SymbolFileDWARF::CompleteType` if there is no type in the
current `GetDIEToType`. Then `SymbolFileDWARFDebugMap::CompleteType`
could continue to the next `SymbolFile` which does own the type. But
that didn't quite work because we remove the
`GetForwardCompilerTypeToDie` entry in `SymbolFile::CompleteType`, which
`SymbolFileDWARFDebugMap::CompleteType` relies upon for iterating