diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3679,6 +3679,28 @@ D->getInClassInitStyle())) return ToField; + // FieldDecl::isZeroSize may need to check these. + if (const Attr *FromAttr = D->getAttr()) { + if (auto ToAttrOrErr = Importer.Import(FromAttr)) + ToField->addAttr(*ToAttrOrErr); + else + return ToAttrOrErr.takeError(); + RecordType *FromRT = + const_cast(D->getType()->getAs()); + // Is this field a struct? FieldDecl::isZeroSize will need its definition. + if (FromRT) { + RecordDecl *FromRD = FromRT->getDecl(); + RecordType *ToRT = + const_cast(ToField->getType()->getAs()); + assert(ToRT && "RecordType import has different type"); + RecordDecl *ToRD = ToRT->getDecl(); + if (FromRD->isCompleteDefinition() && !ToRD->isCompleteDefinition()) { + if (Error Err = ImportDefinition(FromRD, ToRD, IDK_Basic)) + return std::move(Err); + } + } + } + ToField->setAccess(D->getAccess()); ToField->setLexicalDeclContext(LexicalDC); if (ToInitializer) @@ -8497,6 +8519,8 @@ // Make sure that ImportImpl registered the imported decl. assert(ImportedDecls.count(FromD) != 0 && "Missing call to MapImported?"); + // There may have been NoUniqueAddressAttr for FieldDecl::isZeroSize. + ToD->dropAttrs(); if (FromD->hasAttrs()) for (const Attr *FromAttr : FromD->getAttrs()) { auto ToAttrOrErr = Import(FromAttr); diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -296,15 +296,16 @@ SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits, uint32_t AlignInBits, llvm::DIFile *tunit, llvm::DIScope *scope, + bool IsZeroSize, const RecordDecl *RD = nullptr); llvm::DIType *createFieldType(StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits, llvm::DIFile *tunit, - llvm::DIScope *scope, + llvm::DIScope *scope, bool IsZeroSize, const RecordDecl *RD = nullptr) { return createFieldType(name, type, loc, AS, offsetInBits, 0, tunit, scope, - RD); + IsZeroSize, RD); } /// Create new bit field member. diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1401,11 +1401,10 @@ Flags, DebugType); } -llvm::DIType * -CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc, - AccessSpecifier AS, uint64_t offsetInBits, - uint32_t AlignInBits, llvm::DIFile *tunit, - llvm::DIScope *scope, const RecordDecl *RD) { +llvm::DIType *CGDebugInfo::createFieldType( + StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, + uint64_t offsetInBits, uint32_t AlignInBits, llvm::DIFile *tunit, + llvm::DIScope *scope, bool IsZeroSize, const RecordDecl *RD) { llvm::DIType *debugType = getOrCreateType(type, tunit); // Get the location for the field. @@ -1422,6 +1421,8 @@ } llvm::DINode::DIFlags flags = getAccessFlag(AS, RD); + if (IsZeroSize) + flags |= llvm::DINode::FlagIsZeroSize; return DBuilder.createMemberType(scope, name, file, line, SizeInBits, Align, offsetInBits, flags, debugType); } @@ -1439,6 +1440,9 @@ E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) { const LambdaCapture &C = *I; + bool IsZeroSize = false; + assert(!Field->isZeroSize(CGM.getContext()) && + "lambdas cannot use [[no_unique_address]]!"); if (C.capturesVariable()) { SourceLocation Loc = C.getLocation(); assert(!Field->isBitField() && "lambdas don't have bitfield members!"); @@ -1446,9 +1450,10 @@ StringRef VName = V->getName(); llvm::DIFile *VUnit = getOrCreateFile(Loc); auto Align = getDeclAlignIfRequired(V, CGM.getContext()); - llvm::DIType *FieldType = createFieldType( - VName, Field->getType(), Loc, Field->getAccess(), - layout.getFieldOffset(fieldno), Align, VUnit, RecordTy, CXXDecl); + llvm::DIType *FieldType = + createFieldType(VName, Field->getType(), Loc, Field->getAccess(), + layout.getFieldOffset(fieldno), Align, VUnit, + RecordTy, IsZeroSize, CXXDecl); elements.push_back(FieldType); } else if (C.capturesThis()) { // TODO: Need to handle 'this' in some way by probably renaming the @@ -1460,7 +1465,7 @@ QualType type = f->getType(); llvm::DIType *fieldType = createFieldType( "this", type, f->getLocation(), f->getAccess(), - layout.getFieldOffset(fieldno), VUnit, RecordTy, CXXDecl); + layout.getFieldOffset(fieldno), VUnit, RecordTy, IsZeroSize, CXXDecl); elements.push_back(fieldType); } @@ -1513,9 +1518,10 @@ FieldType = createBitFieldType(field, RecordTy, RD); } else { auto Align = getDeclAlignIfRequired(field, CGM.getContext()); + bool IsZeroSize = field->isZeroSize(CGM.getContext()); FieldType = createFieldType(name, type, field->getLocation(), field->getAccess(), - OffsetInBits, Align, tunit, RecordTy, RD); + OffsetInBits, Align, tunit, RecordTy, IsZeroSize, RD); } elements.push_back(FieldType); @@ -4563,37 +4569,39 @@ const CGBlockInfo &Block, const ASTContext &Context, SourceLocation Loc, const llvm::StructLayout &BlockLayout, llvm::DIFile *Unit, SmallVectorImpl &Fields) { + bool IsZeroSize = false; // Blocks in OpenCL have unique constraints which make the standard fields // redundant while requiring size and align fields for enqueue_kernel. See // initializeForBlockHeader in CGBlocks.cpp if (CGM.getLangOpts().OpenCL) { Fields.push_back(createFieldType("__size", Context.IntTy, Loc, AS_public, BlockLayout.getElementOffsetInBits(0), - Unit, Unit)); + Unit, Unit, IsZeroSize)); Fields.push_back(createFieldType("__align", Context.IntTy, Loc, AS_public, BlockLayout.getElementOffsetInBits(1), - Unit, Unit)); + Unit, Unit, IsZeroSize)); } else { Fields.push_back(createFieldType("__isa", Context.VoidPtrTy, Loc, AS_public, BlockLayout.getElementOffsetInBits(0), - Unit, Unit)); + Unit, Unit, IsZeroSize)); Fields.push_back(createFieldType("__flags", Context.IntTy, Loc, AS_public, BlockLayout.getElementOffsetInBits(1), - Unit, Unit)); - Fields.push_back( - createFieldType("__reserved", Context.IntTy, Loc, AS_public, - BlockLayout.getElementOffsetInBits(2), Unit, Unit)); + Unit, Unit, IsZeroSize)); + Fields.push_back(createFieldType( + "__reserved", Context.IntTy, Loc, AS_public, + BlockLayout.getElementOffsetInBits(2), Unit, Unit, IsZeroSize)); auto *FnTy = Block.getBlockExpr()->getFunctionType(); auto FnPtrType = CGM.getContext().getPointerType(FnTy->desugar()); Fields.push_back(createFieldType("__FuncPtr", FnPtrType, Loc, AS_public, BlockLayout.getElementOffsetInBits(3), - Unit, Unit)); + Unit, Unit, IsZeroSize)); Fields.push_back(createFieldType( "__descriptor", Context.getPointerType(Block.NeedsCopyDispose ? Context.getBlockDescriptorExtendedType() : Context.getBlockDescriptorType()), - Loc, AS_public, BlockLayout.getElementOffsetInBits(4), Unit, Unit)); + Loc, AS_public, BlockLayout.getElementOffsetInBits(4), Unit, Unit, + IsZeroSize)); } } @@ -4669,8 +4677,9 @@ else llvm_unreachable("unexpected block declcontext"); + bool IsZeroSize = false; fields.push_back(createFieldType("this", type, loc, AS_public, - offsetInBits, tunit, tunit)); + offsetInBits, tunit, tunit, IsZeroSize)); continue; } @@ -4691,8 +4700,10 @@ llvm::DINode::FlagZero, fieldType); } else { auto Align = getDeclAlignIfRequired(variable, CGM.getContext()); - fieldType = createFieldType(name, variable->getType(), loc, AS_public, - offsetInBits, Align, tunit, tunit); + bool IsZeroSize = false; + fieldType = + createFieldType(name, variable->getType(), loc, AS_public, + offsetInBits, Align, tunit, tunit, IsZeroSize); } fields.push_back(fieldType); } diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp @@ -99,9 +99,12 @@ if (ptr_obj) m_ptr_obj = ptr_obj->Clone(ConstString("pointer")).get(); - ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1); - if (del_obj) - m_del_obj = del_obj->Clone(ConstString("deleter")).get(); + // GCC 11 std::default_delete<...> has existing child with GetByteSize()==1. + if (tuple_sp->GetByteSize() > ptr_obj->GetByteSize()) { + ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1); + if (del_obj) + m_del_obj = del_obj->Clone(ConstString("deleter")).get(); + } if (m_ptr_obj) { Status error; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2472,6 +2472,7 @@ } } } + bool IsZeroSize = byte_size && *byte_size == 0; if (prop_name) { ConstString fixed_setter; @@ -2721,8 +2722,8 @@ RequireCompleteType(member_clang_type); field_decl = TypeSystemClang::AddFieldToRecordType( - class_clang_type, name, member_clang_type, accessibility, - bit_size); + class_clang_type, name, member_clang_type, accessibility, bit_size, + IsZeroSize); m_ast.SetMetadataAsUserID(field_decl, die.GetID()); diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -228,9 +228,10 @@ lldb::AccessType access = TranslateMemberAccess(data_member.getAccess()); + bool IsZeroSize = false; // FIXME: Is there [[no_unique_address]] in PDB? clang::FieldDecl *decl = TypeSystemClang::AddFieldToRecordType( m_derived_ct, data_member.Name, m_ast_builder.ToCompilerType(member_qt), - access, bitfield_width); + access, bitfield_width, IsZeroSize); // FIXME: Add a PdbSymUid namespace for field list members and update // the m_uid_to_decl map with this decl. diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -1264,8 +1264,10 @@ if (location_type == PDB_LocType::ThisRel) bit_size *= 8; + bool IsZeroSize = false; // FIXME: Is there [[no_unique_address]] in PDB? auto decl = TypeSystemClang::AddFieldToRecordType( - record_type, member_name.c_str(), member_comp_type, access, bit_size); + record_type, member_name.c_str(), member_comp_type, access, bit_size, + IsZeroSize); if (!decl) continue; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -843,11 +843,10 @@ CompilerType *child_type = nullptr); // Modifying RecordType - static clang::FieldDecl *AddFieldToRecordType(const CompilerType &type, - llvm::StringRef name, - const CompilerType &field_type, - lldb::AccessType access, - uint32_t bitfield_bit_size); + static clang::FieldDecl * + AddFieldToRecordType(const CompilerType &type, llvm::StringRef name, + const CompilerType &field_type, lldb::AccessType access, + uint32_t bitfield_bit_size, bool IsZeroSize = false); static void BuildIndirectFields(const CompilerType &type); diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -7164,7 +7164,7 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( const CompilerType &type, llvm::StringRef name, const CompilerType &field_clang_type, AccessType access, - uint32_t bitfield_bit_size) { + uint32_t bitfield_bit_size, bool IsZeroSize) { if (!type.IsValid() || !field_clang_type.IsValid()) return nullptr; TypeSystemClang *ast = @@ -7196,6 +7196,8 @@ if (bit_width) field->setBitWidth(bit_width); SetMemberOwningModule(field, record_decl); + if (IsZeroSize) + field->addAttr(NoUniqueAddressAttr::CreateImplicit(ast->getASTContext())); if (name.empty()) { // Determine whether this field corresponds to an anonymous struct or diff --git a/lldb/test/Shell/Expr/no_unique_address.cpp b/lldb/test/Shell/Expr/no_unique_address.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/Expr/no_unique_address.cpp @@ -0,0 +1,15 @@ +// Test LLDB does not assert on miscalculated field offsets. + +// RUN: %clang_host %s -g -c -o %t.o +// RUN: %lldb %t.o -o "p c.c" -o exit | FileCheck %s + +// CHECK: (lldb) p c.c +// CHECK-NEXT: (char) $0 = '\0' + +struct A {}; +struct B { + [[no_unique_address]] A a; +}; +struct C : B { + char c; +} c; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1603,12 +1603,16 @@ } else { addUInt(MemberDie, dwarf::DW_AT_data_bit_offset, None, Offset); } + assert(!(DT->getFlags() & DINode::FlagIsZeroSize) && + "bitfields cannot have [[no_unique_address]]"); } else { // This is not a bitfield. OffsetInBytes = DT->getOffsetInBits() / 8; if (AlignInBytes) addUInt(MemberDie, dwarf::DW_AT_alignment, dwarf::DW_FORM_udata, AlignInBytes); + if (DT->getFlags() & DINode::FlagIsZeroSize) + addUInt(MemberDie, dwarf::DW_AT_byte_size, None, 0); } if (DD->getDwarfVersion() <= 2) {