llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: nerix (Nerixyz)
<details>
<summary>Changes</summary>
In native PDB, types of constant array members were not completed when
completing a struct. This lead to an assertion failure later when trying to
print a variable of the struct (`Shell/SymbolFile/PDB/udt-layout.test`, see
#<!-- -->114906).
The following shows the issue:
```cpp
struct G {
int foo = 1;
};
struct H {
G g[2];
};
H h;
```
Running `target variable h` would result in a request to complete `H`. This
will run the `UdtRecordCompleter` over the struct fields. When it encounters a
data member, [it tries to complete its
type](https://github.com/llvm/llvm-project/blob/bf4486eb29c3009ddf68968b021c6fd98e3c2d52/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp#L260).
This would previously only complete records. However, types of constant array
members (in our case `G`) need to be completed as well, as they are required to
compute the layout of the record.
With this PR, `TypeSystemClang::RequireCompleteType` will also complete the
types of constant array members.
To hit the assertion, the layout needs to be requested (e.g. by getting a child
member). That's why I used both `target variable` and `expression`.
Unfortunately, this doesn't allow `Shell/SymbolFile/PDB/udt-layout.test` to run
with the native plugin yet, because it checks for the order in which base
classes are printed. The DIA plugin puts virtual bases first, while the native
plugin puts them last (where they are in memory).
---
Full diff: https://github.com/llvm/llvm-project/pull/156370.diff
4 Files Affected:
- (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+12-3)
- (modified)
lldb/test/Shell/SymbolFile/NativePDB/Inputs/incomplete-tag-type.cpp (+5)
- (removed) lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.cpp (-45)
- (added) lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.test (+109)
``````````diff
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 39aacdb58e694..038677f68b991 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9577,12 +9577,21 @@ TypeSystemClang::DeclContextGetTypeSystemClang(const
CompilerDeclContext &dc) {
}
void TypeSystemClang::RequireCompleteType(CompilerType type) {
+ if (!type)
+ return;
+
+ clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type));
+ if (qual_type.isNull())
+ return;
+
// Technically, enums can be incomplete too, but we don't handle those as
they
// are emitted even under -flimit-debug-info.
- if (!TypeSystemClang::IsCXXClassType(type))
- return;
+ bool is_constant_array = qual_type->isConstantArrayType();
+ bool is_cxx_record = qual_type->getAsCXXRecordDecl() != nullptr;
+ if (is_constant_array || is_cxx_record)
+ type.GetCompleteType();
- if (type.GetCompleteType())
+ if (!is_cxx_record)
return;
// No complete definition in this module. Mark the class as complete to
diff --git
a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/incomplete-tag-type.cpp
b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/incomplete-tag-type.cpp
index c930338905445..d08f49d1014ba 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/incomplete-tag-type.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/incomplete-tag-type.cpp
@@ -13,3 +13,8 @@ struct E {
E();
};
E::E() = default;
+
+struct I {
+ I();
+};
+I::I() = default;
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.cpp
b/lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.cpp
deleted file mode 100644
index 7bc7e618667f7..0000000000000
--- a/lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-// clang-format off
-// REQUIRES: lld, x86
-
-// RUN: %clang_cl --target=x86_64-windows-msvc -c /Fo%t1.obj --
%p/Inputs/incomplete-tag-type.cpp
-// RUN: %clang_cl --target=x86_64-windows-msvc /O1 /Z7 -c /Fo%t2.obj -- %s
-// RUN: lld-link /debug:full /nodefaultlib /entry:main %t1.obj %t2.obj
/out:%t.exe /pdb:%t.pdb
-// RUN: %lldb -f %t.exe -o \
-// RUN: "settings set interpreter.stop-command-source-on-error false" \
-// RUN: -o "expression b" -o "expression d" -o "expression static_e_ref" -o
"exit" 2>&1 | FileCheck %s
-
-// CHECK: (lldb) expression b
-// CHECK: (B) $0 = {}
-// CHECK: (lldb) expression d
-// CHECK: (D) $1 = {}
-// CHECK: (lldb) expression static_e_ref
-// CHECK: error:{{.*}}incomplete type 'E' where a complete type is required
-
-// Complete base class.
-struct A { int x; A(); };
-struct B : A {};
-B b;
-
-// Complete data member.
-struct C {
- C();
-};
-
-struct D {
- C c;
-};
-D d;
-
-// Incomplete static data member should return error.
-struct E {
- E();
-};
-
-struct F {
- static E static_e;
-};
-
-E F::static_e = E();
-E& static_e_ref = F::static_e;
-
-int main(){}
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.test
b/lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.test
new file mode 100644
index 0000000000000..f30866ccdd6f0
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.test
@@ -0,0 +1,109 @@
+# REQUIRES: lld, x86
+
+# RUN: split-file %s %t
+
+# RUN: %clang_cl --target=x86_64-windows-msvc -c /Fo%t1.obj --
%p/Inputs/incomplete-tag-type.cpp
+# RUN: %clang_cl --target=x86_64-windows-msvc /O1 /Z7 -c /Fo%t2.obj --
%t/main.cpp
+# RUN: lld-link /debug:full /nodefaultlib /entry:main %t1.obj %t2.obj
/out:%t.exe /pdb:%t.pdb
+
+# RUN: %lldb -f %t.exe -s %t/target-var.input 2>&1 | FileCheck %s
--check-prefix=TARGET-VAR
+# RUN: %lldb -f %t.exe -s %t/expr.input 2>&1 | FileCheck %s --check-prefix=EXPR
+
+#--- main.cpp
+
+// Complete base class.
+struct A { int x; A(); };
+struct B : A {};
+B b;
+
+// Complete data member.
+struct C {
+ C();
+};
+
+struct D {
+ C c;
+};
+D d;
+
+// Incomplete static data member should return error.
+struct E {
+ E();
+};
+
+struct F {
+ static E static_e;
+};
+
+E F::static_e = E();
+E& static_e_ref = F::static_e;
+
+struct G {
+ int foo = 1;
+};
+struct H {
+ G g[2];
+};
+H h;
+
+struct I {
+ I();
+};
+struct J {
+ I i[2];
+};
+J j;
+
+
+int main(){}
+
+#--- target-var.input
+
+target variable b
+target variable d
+target variable h
+target variable j
+target variable static_e_ref
+exit
+
+#--- expr.input
+
+settings set interpreter.stop-command-source-on-error false
+expression b
+expression d
+expression h
+expression j
+expression static_e_ref
+exit
+
+# TARGET-VAR: (lldb) target variable b
+# TARGET-VAR-NEXT: (B) b = (A = <incomplete type>)
+# TARGET-VAR-NEXT: (lldb) target variable d
+# TARGET-VAR-NEXT: (D) d = {}
+# TARGET-VAR-NEXT: (lldb) target variable h
+# TARGET-VAR-NEXT: (H) h = {
+# TARGET-VAR-NEXT: g = {
+# TARGET-VAR-NEXT: [0] = (foo = 1)
+# TARGET-VAR-NEXT: [1] = (foo = 1)
+# TARGET-VAR-NEXT: }
+# TARGET-VAR-NEXT: }
+# TARGET-VAR-NEXT: (lldb) target variable j
+# TARGET-VAR-NEXT: (J) j = {}
+# TARGET-VAR-NEXT: (lldb) target variable static_e_ref
+# TARGET-VAR-NEXT: (E &) static_e_ref = 0x{{.*}} <incomplete type "E">
+
+# EXPR: (lldb) expression b
+# EXPR-NEXT: (B) $0 = {}
+# EXPR-NEXT: (lldb) expression d
+# EXPR-NEXT: (D) $1 = {}
+# EXPR-NEXT: (lldb) expression h
+# EXPR-NEXT: (H) $2 = {
+# EXPR-NEXT: g = {
+# EXPR-NEXT: [0] = (foo = 1)
+# EXPR-NEXT: [1] = (foo = 1)
+# EXPR-NEXT: }
+# EXPR-NEXT: }
+# EXPR-NEXT: (lldb) expression j
+# EXPR-NEXT: (J) $3 = {}
+# EXPR-NEXT: (lldb) expression static_e_ref
+# EXPR: error:{{.*}}incomplete type 'E' where a complete type is required
``````````
</details>
https://github.com/llvm/llvm-project/pull/156370
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits