return type_sp;
}
-static void CompleteExternalTagDeclType(TypeSystemClang &ast,
- ClangASTImporter &ast_importer,
- clang::DeclContext *decl_ctx,
- DWARFDIE die,
- const char *type_name_cstr) {
+static void ForcefullyCompleteType(CompilerType type) {
+ 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();
+}
+
+/// 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.).
+static void 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.
+ ForcefullyCompleteType(type);
+}
+
+/// This function serves a similar purpose as RequireCompleteType above, but it
+/// avoids completing the type if it is not immediately necessary. It only
+/// ensures we _can_ complete the type later.
+static void PrepareContextToReceiveMembers(TypeSystemClang &ast,
+ ClangASTImporter &ast_importer,
+ clang::DeclContext *decl_ctx,
+ DWARFDIE die,
+ const char *type_name_cstr) {
auto *tag_decl_ctx = clang::dyn_cast<clang::TagDecl>(decl_ctx);
if (!tag_decl_ctx)
+ return; // Non-tag context are always ready.
+
+ // We have already completed the type, or we have found its definition and are
+ // ready to complete it later (cf. ParseStructureLikeDIE).
+ if (tag_decl_ctx->isCompleteDefinition() || tag_decl_ctx->isBeingDefined())
return;
+ // We reach this point of the tag was present in the debug info as a
+ // declaration only. If it was imported from another AST context (in the
+ // gmodules case), we can complete the type by doing a full import.
+
// If this type was not imported from an external AST, there's nothing to do.
CompilerType type = ast.GetTypeForDecl(tag_decl_ctx);
- if (!type || !ast_importer.CanImport(type))
- return;
-
- auto qual_type = ClangUtil::GetQualType(type);
- if (!ast_importer.RequireCompleteType(qual_type)) {
+ if (type && ast_importer.CanImport(type)) {
+ auto qual_type = ClangUtil::GetQualType(type);
+ if (ast_importer.RequireCompleteType(qual_type))
+ return;
die.GetDWARF()->GetObjectFile()->GetModule()->ReportError(
"Unable to complete the Decl context for DIE '%s' at offset "
"0x%8.8x.\nPlease file a bug report.",
type_name_cstr ? type_name_cstr : "", die.GetOffset());
- // We need to make the type look complete otherwise, we might crash in
- // Clang when adding children.
- if (TypeSystemClang::StartTagDeclarationDefinition(type))
- TypeSystemClang::CompleteTagDeclarationDefinition(type);
}
+
+ // We don't have a type definition and/or the import failed. We must
+ // forcefully complete the type to avoid crashes.
+ ForcefullyCompleteType(type);
}
ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
if (attrs.byte_stride == 0 && attrs.bit_stride == 0)
attrs.byte_stride = element_type->GetByteSize(nullptr).getValueOr(0);
CompilerType array_element_type = element_type->GetForwardCompilerType();
- CompleteType(array_element_type);
+ RequireCompleteType(array_element_type);
uint64_t array_element_bit_stride =
attrs.byte_stride * 8 + attrs.bit_stride;
return nullptr;
}
-void DWARFASTParserClang::CompleteType(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);
- m_ast.GetMetadata(td)->SetIsForcefullyCompleted();
-}
-
TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType(
const SymbolContext &sc, const DWARFDIE &die, TypeSP type_sp) {
if (!type_sp)
clang::DeclContext *decl_ctx =
GetClangDeclContextContainingDIE(die, nullptr);
- // If your decl context is a record that was imported from another
- // AST context (in the gmodules case), we need to make sure the type
- // backing the Decl is complete before adding children to it. This is
- // not an issue in the non-gmodules case because the debug info will
- // always contain a full definition of parent types in that case.
- CompleteExternalTagDeclType(m_ast, GetClangASTImporter(), decl_ctx, die,
- attrs.name.GetCString());
+ PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(), decl_ctx, die,
+ attrs.name.GetCString());
if (attrs.accessibility == eAccessNone && decl_ctx) {
// Check the decl context that contains this class/struct/union. If
clang::TypeSourceInfo *type_source_info =
base_class->getTypeSourceInfo();
if (type_source_info)
- CompleteType(m_ast.GetType(type_source_info->getType()));
+ RequireCompleteType(m_ast.GetType(type_source_info->getType()));
}
m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(),
}
}
- CompleteType(member_clang_type);
+ RequireCompleteType(member_clang_type);
field_decl = TypeSystemClang::AddFieldToRecordType(
class_clang_type, name, member_clang_type, accessibility,
-# Test that a forward-declared (DW_AT_declaration) structure is treated as a
-# forward-declaration even if it has children. These types can be produced due
-# to vtable-based type homing, or other -flimit-debug-info optimizations.
+# Test handling of forward-declared (DW_AT_declaration) structures. These types
+# can be produced due to vtable-based type homing, or other -flimit-debug-info
+# optimizations.
# REQUIRES: x86
-# RUN: llvm-mc --triple x86_64-pc-linux %s --filetype=obj > %t
-# RUN: %lldb %t -o "expr a" -o exit 2>&1 | FileCheck %s --check-prefix=EXPR
-# RUN: %lldb %t -o "target var a" -o exit 2>&1 | FileCheck %s --check-prefix=VAR
-
-# EXPR: incomplete type 'A' where a complete type is required
+# RUN: rm -rf %t
+# RUN: split-file %s %t
+# RUN: llvm-mc --triple x86_64-pc-linux %t/asm --filetype=obj > %t.o
+# RUN: %lldb -o "settings set interpreter.stop-command-source-on-error false" \
+# RUN: -s %t/commands -o exit %t.o 2>&1 | FileCheck %s
+#--- commands
+# Type A should be treated as a forward-declaration even though it has a child.
+target var a
+# CHECK-LABEL: target var a
# FIXME: This should also produce some kind of an error.
-# VAR: (A) a = {}
+# CHECK: (A) a = {}
+expr a
+# CHECK-LABEL: expr a
+# CHECK: incomplete type 'A' where a complete type is required
+
+# Parsing B::B1 should not crash even though B is incomplete. Note that in this
+# case B must be forcefully completed.
+target var b1
+# CHECK-LABEL: target var b1
+# CHECK: (B::B1) b1 = (ptr = 0x00000000baadf00d)
+expr b1
+# CHECK-LABEL: expr b1
+# CHECK: (B::B1) $0 = (ptr = 0x00000000baadf00d)
+#--- asm
.text
_ZN1AC2Ev:
retq
.LZN1AC2Ev_end:
.data
+ .p2align 4
a:
- .quad $_ZTV1A+16
- .quad $0xdeadbeef
+ .quad _ZTV1A+16
+ .quad 0xdeadbeef
+
+b1:
+ .quad 0xbaadf00d
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 25 # DW_FORM_flag_present
.byte 0 # EOM(1)
.byte 0 # EOM(2)
+ .byte 6 # Abbreviation Code
+ .byte 2 # DW_TAG_class_type
+ .byte 1 # DW_CHILDREN_yes
+ .byte 3 # DW_AT_name
+ .byte 8 # DW_FORM_string
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 7 # Abbreviation Code
+ .byte 13 # DW_TAG_member
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 8 # DW_FORM_string
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 56 # DW_AT_data_member_location
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
.byte 8 # Abbreviation Code
.byte 15 # DW_TAG_pointer_type
.byte 0 # DW_CHILDREN_no
.asciz "Hand-written DWARF" # DW_AT_producer
.quad _ZN1AC2Ev # DW_AT_low_pc
.long .LZN1AC2Ev_end-_ZN1AC2Ev # DW_AT_high_pc
+
+# Case 1: The compiler has omitted the declaration of the type, but it still
+# produces an entry for its implicit constructor instantiated in this compile
+# unit.
+# Roughly corresponds to this:
+# struct A {
+# virtual ~A(); // not defined here
+# // implicit A() {}
+# } a;
.byte 2 # Abbrev [2] DW_TAG_variable
.asciz "a" # DW_AT_name
.long .LA-.Lcu_begin0 # DW_AT_type
.long .LAptr-.Lcu_begin0 # DW_AT_type
# DW_AT_artificial
.byte 0 # End Of Children Mark
+
+# Case 2: A structure has been emitted as a declaration only, but it contains a
+# nested class, which has a full definition present.
+# Rougly corresponds to this:
+# struct B {
+# virtual ~B(); // not defined here
+# class B1 {
+# A* ptr;
+# };
+# };
+# B::B1 b1;
+# Note that it is important that the inner type is a class (not struct) as that
+# triggers a clang assertion.
+ .byte 3 # Abbrev [3] DW_TAG_structure_type
+ .asciz "B" # DW_AT_name
+ # DW_AT_declaration
+.LB1:
+ .byte 6 # Abbrev [6] DW_TAG_class_type
+ .asciz "B1" # DW_AT_name
+ # DW_AT_declaration
+ .byte 7 # Abbrev [5] 0x58:0xc DW_TAG_member
+ .asciz "ptr" # DW_AT_name
+ .long .LAptr # DW_AT_type
+ .byte 0 # DW_AT_data_member_location
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+
+ .byte 2 # Abbrev [2] DW_TAG_variable
+ .asciz "b1" # DW_AT_name
+ .long .LB1-.Lcu_begin0 # DW_AT_type
+ .byte 9 # DW_AT_location
+ .byte 3
+ .quad b1
+
.byte 0 # End Of Children Mark
.Ldebug_info_end0: