zequanwu updated this revision to Diff 473834.
zequanwu added a comment.
Adding a test for incomplete record type as class static member. It returns
error, because its type not required to be completed.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D134066/new/
https://reviews.llvm.org/D134066
Files:
lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
lldb/test/Shell/SymbolFile/NativePDB/Inputs/incomplete-tag-type.cpp
lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.cpp
Index: lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.cpp
===================================================================
--- /dev/null
+++ lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.cpp
@@ -0,0 +1,48 @@
+// 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: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -o \
+// RUN: "settings set interpreter.stop-command-source-on-error false" \
+// RUN: -o "p b" -o "p d" -o "p static_e_ref" -o "exit" 2>&1 | FileCheck %s
+
+// CHECK: (lldb) p b
+// CHECK: (B) $0 = {}
+// CHECK: (lldb) p d
+// CHECK: (D) $1 = {}
+// CHECK: (lldb) p static_e_ref
+// CHECK: error: expression failed to parse:
+// CHECK: error: {{.*}}: incomplete type 'E' where a complete type is required
+// CHECK: static_e_ref
+// CHECK: ^
+
+// 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(){}
Index: lldb/test/Shell/SymbolFile/NativePDB/Inputs/incomplete-tag-type.cpp
===================================================================
--- /dev/null
+++ lldb/test/Shell/SymbolFile/NativePDB/Inputs/incomplete-tag-type.cpp
@@ -0,0 +1,15 @@
+struct A {
+ int x;
+ A();
+};
+A::A() : x(47) {}
+
+struct C {
+ C();
+};
+C::C() = default;
+
+struct E {
+ E();
+};
+E::E() = default;
Index: lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -92,9 +92,10 @@
m_ast_builder.GetOrCreateType(PdbTypeSymId(type_idx));
if (method_qt.isNull())
return;
- m_ast_builder.CompleteType(method_qt);
CompilerType method_ct = m_ast_builder.ToCompilerType(method_qt);
- lldb::opaque_compiler_type_t derived_opaque_ty = m_derived_ct.GetOpaqueQualType();
+ PdbAstBuilder::RequireCompleteType(method_ct);
+ lldb::opaque_compiler_type_t derived_opaque_ty =
+ m_derived_ct.GetOpaqueQualType();
auto iter = m_cxx_record_map.find(derived_opaque_ty);
if (iter != m_cxx_record_map.end()) {
if (iter->getSecond().contains({name, method_ct})) {
@@ -253,7 +254,7 @@
clang::QualType member_qt = m_ast_builder.GetOrCreateType(PdbTypeSymId(ti));
if (member_qt.isNull())
return Error::success();
- m_ast_builder.CompleteType(member_qt);
+ PdbAstBuilder::RequireCompleteType(m_ast_builder.ToCompilerType(member_qt));
lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());
size_t field_size =
bitfield_width ? bitfield_width : GetSizeOfType(ti, m_index.tpi()) * 8;
@@ -310,6 +311,18 @@
bases.push_back(std::move(ib.second));
TypeSystemClang &clang = m_ast_builder.clang();
+ // Make sure all base classes refer to complete types and not forward
+ // declarations. If we don't do this, clang will crash with an
+ // assertion in the call to clang_type.TransferBaseClasses()
+ for (const auto &base_class : bases) {
+ clang::TypeSourceInfo *type_source_info =
+ base_class->getTypeSourceInfo();
+ if (type_source_info) {
+ PdbAstBuilder::RequireCompleteType(
+ clang.GetType(type_source_info->getType()));
+ }
+ }
+
clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(), std::move(bases));
clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());
Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
+++ lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
@@ -87,6 +87,7 @@
ClangASTImporter &GetClangASTImporter() { return m_importer; }
void Dump(Stream &stream);
+ static void RequireCompleteType(CompilerType type);
private:
clang::Decl *TryGetDecl(PdbSymUid uid) const;
Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -1448,3 +1448,30 @@
void PdbAstBuilder::Dump(Stream &stream) {
m_clang.Dump(stream.AsRawOstream());
}
+
+/// Complete a type from debug info, or mark it as forcefully completed if
+/// there is no definition of the type in the current Module. Call this function
+/// in contexts where the usual C++ rules require a type to be complete (base
+/// class, member, etc.).
+void PdbAstBuilder::RequireCompleteType(CompilerType type) {
+ // 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;
+
+ if (type.GetCompleteType())
+ return;
+
+ // No complete definition in this module. Mark the class as complete to
+ // satisfy local ast invariants, but make a note of the fact that
+ // it is not _really_ complete so we can later search for a definition in a
+ // different module.
+ // Since we provide layout assistance, layouts of types containing this class
+ // will be correct even if we are not able to find the definition elsewhere.
+ bool started = TypeSystemClang::StartTagDeclarationDefinition(type);
+ lldbassert(started && "Unable to start a class type definition.");
+ TypeSystemClang::CompleteTagDeclarationDefinition(type);
+ const clang::TagDecl *td = ClangUtil::GetAsTagDecl(type);
+ auto &ts = llvm::cast<TypeSystemClang>(*type.GetTypeSystem());
+ ts.GetMetadata(td)->SetIsForcefullyCompleted();
+}
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits