[llvm-branch-commits] [clang] [CIR][CodeGen][NFC] Share the record layout queries (PR #223424)

Henrich Lauko via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Sep 21 06:36:22 PDT 2026


https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/223424

>From 32ffa8e687974dcb95ce9e6460b2c903fd312a01 Mon Sep 17 00:00:00 2001
From: Henrich Lauko <hlauko at nvidia.com>
Date: Mon, 14 Sep 2026 13:43:48 +0000
Subject: [PATCH] [CIR][CodeGen][NFC] Share the record layout queries

Five AST queries that both CodeGens used while lowering a record to its
target type. Two were free functions in both; the other three were
equivalent members of CGRecordLowering and CIRRecordLowering that touched no
lowering state beyond the ASTContext, so they become free functions too.

isEmptyFieldForLayout and isEmptyRecordForLayout have around 30 unqualified
callers between the two CodeGens. ABIInfoImpl.h and CIR/CodeGen/TargetInfo.h
re-export the shared declarations with using-declarations, so those callers
are untouched.

No functional change.
---
 .../clang/CodeGenUtils/RecordLayoutUtils.h    | 51 ++++++++++++++
 .../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 40 ++---------
 clang/lib/CIR/CodeGen/TargetInfo.cpp          | 34 ----------
 clang/lib/CIR/CodeGen/TargetInfo.h            | 12 +---
 clang/lib/CodeGen/ABIInfoImpl.cpp             | 33 ----------
 clang/lib/CodeGen/ABIInfoImpl.h               | 12 +---
 clang/lib/CodeGen/CGRecordLayoutBuilder.cpp   | 48 +++-----------
 clang/lib/CodeGenUtils/CMakeLists.txt         |  1 +
 clang/lib/CodeGenUtils/RecordLayoutUtils.cpp  | 66 +++++++++++++++++++
 9 files changed, 138 insertions(+), 159 deletions(-)
 create mode 100644 clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
 create mode 100644 clang/lib/CodeGenUtils/RecordLayoutUtils.cpp

diff --git a/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h b/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
new file mode 100644
index 00000000000000..594411e0762771
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
@@ -0,0 +1,51 @@
+//===--- RecordLayoutUtils.h - Shared record layout queries -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file holds the AST queries about record layout that both classic
+// CodeGen and CIR CodeGen need while lowering a record to its target type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGENUTILS_RECORDLAYOUTUTILS_H
+#define LLVM_CLANG_CODEGENUTILS_RECORDLAYOUTUTILS_H
+
+#include "clang/AST/ASTContext.h"
+
+namespace clang::CodeGenUtils {
+
+/// Recursively searches all of the bases of \p Decl to find out whether
+/// \p Query is not the primary vbase of some base class.
+bool hasOwnStorage(const ASTContext &Ctx, const CXXRecordDecl *Decl,
+                   const CXXRecordDecl *Query);
+
+/// The Microsoft bitfield layout rule allocates discrete storage units of the
+/// field's formal type and only combines adjacent fields of the same formal
+/// type.  We want to emit a layout with these discrete storage units instead
+/// of combining them into a continuous run.
+bool isDiscreteBitFieldABI(const ASTContext &Ctx, const RecordDecl *RD);
+
+/// Return true iff the field is "empty", that is, either a zero-width
+/// bit-field or an \ref isEmptyRecordForLayout.
+bool isEmptyFieldForLayout(const ASTContext &Ctx, const FieldDecl *FD);
+
+/// Return true iff a structure contains only empty base classes (per \ref
+/// isEmptyRecordForLayout) and fields (per \ref isEmptyFieldForLayout).  Note,
+/// C++ record fields are considered empty if the [[no_unique_address]]
+/// attribute would have made them empty, so this is not the same as \ref
+/// isEmptyRecord.
+bool isEmptyRecordForLayout(const ASTContext &Ctx, QualType T);
+
+/// The Itanium base layout rule allows virtual bases to overlap other bases,
+/// which complicates layout in specific ways.
+///
+/// Note specifically that the ms_struct attribute doesn't change this.
+bool isOverlappingVBaseABI(const ASTContext &Ctx);
+
+} // namespace clang::CodeGenUtils
+
+#endif // LLVM_CLANG_CODEGENUTILS_RECORDLAYOUTUTILS_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index c2075a245f05c9..63715e1f6e8145 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
@@ -23,6 +23,7 @@
 #include "clang/CIR/Dialect/IR/CIRDataLayout.h"
 #include "clang/CIR/MissingFeatures.h"
 #include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
 #include "llvm/Support/Casting.h"
 
 #include <memory>
@@ -133,27 +134,6 @@ struct CIRRecordLowering final {
   /// Helper function to check if the target machine is BigEndian.
   bool isBigEndian() const { return astContext.getTargetInfo().isBigEndian(); }
 
-  // The Itanium base layout rule allows virtual bases to overlap
-  // other bases, which complicates layout in specific ways.
-  //
-  // Note specifically that the ms_struct attribute doesn't change this.
-  bool isOverlappingVBaseABI() {
-    return !astContext.getTargetInfo().getCXXABI().isMicrosoft();
-  }
-  // Recursively searches all of the bases to find out if a vbase is
-  // not the primary vbase of some base class.
-  bool hasOwnStorage(const CXXRecordDecl *decl, const CXXRecordDecl *query);
-
-  /// The Microsoft bitfield layout rule allocates discrete storage
-  /// units of the field's formal type and only combines adjacent
-  /// fields of the same formal type.  We want to emit a layout with
-  /// these discrete storage units instead of combining them into a
-  /// continuous run.
-  bool isDiscreteBitFieldABI() {
-    return astContext.getTargetInfo().getCXXABI().isMicrosoft() ||
-           recordDecl->isMsStruct(astContext);
-  }
-
   CharUnits bitsToCharUnits(uint64_t bitOffset) {
     return astContext.toCharUnitsFromBits(bitOffset);
   }
@@ -445,7 +425,7 @@ void CIRRecordLowering::fillOutputFields() {
 RecordDecl::field_iterator
 CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator field,
                                        RecordDecl::field_iterator fieldEnd) {
-  if (isDiscreteBitFieldABI()) {
+  if (CodeGenUtils::isDiscreteBitFieldABI(astContext, recordDecl)) {
     // run stores the first element of the current run of bitfields. fieldEnd is
     // used as a special value to note that we don't have a current run. A
     // bitfield run is a contiguous collection of bitfields that can be stored
@@ -1128,17 +1108,6 @@ void CIRRecordLowering::lowerUnion(bool nonVirtualBaseType) {
   packed = !layoutSize.isMultipleOf(getMemberAlignment(storageType));
 }
 
-bool CIRRecordLowering::hasOwnStorage(const CXXRecordDecl *decl,
-                                      const CXXRecordDecl *query) {
-  const ASTRecordLayout &declLayout = astContext.getASTRecordLayout(decl);
-  if (declLayout.isPrimaryBaseVirtual() && declLayout.getPrimaryBase() == query)
-    return false;
-  for (const auto &base : decl->bases())
-    if (!hasOwnStorage(base.getType()->getAsCXXRecordDecl(), query))
-      return false;
-  return true;
-}
-
 /// The AAPCS that defines that, when possible, bit-fields should
 /// be accessed using containers of the declared type width:
 /// When a volatile bit-field is read, and its container does not overlap with
@@ -1292,8 +1261,9 @@ void CIRRecordLowering::accumulateVBases() {
     CharUnits offset = astRecordLayout.getVBaseClassOffset(baseDecl);
     // If the vbase is a primary virtual base of some base, then it doesn't
     // get its own storage location but instead lives inside of that base.
-    if (isOverlappingVBaseABI() && astContext.isNearlyEmpty(baseDecl) &&
-        !hasOwnStorage(cxxRecordDecl, baseDecl)) {
+    if (CodeGenUtils::isOverlappingVBaseABI(astContext) &&
+        astContext.isNearlyEmpty(baseDecl) &&
+        !CodeGenUtils::hasOwnStorage(astContext, cxxRecordDecl, baseDecl)) {
       members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase, nullptr,
                                    cir::RecordMemberKind::Data, baseDecl));
       continue;
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp
index cede4941b44737..57bc5f167e4605 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp
@@ -11,40 +11,6 @@
 using namespace clang;
 using namespace clang::CIRGen;
 
-bool clang::CIRGen::isEmptyRecordForLayout(const ASTContext &context,
-                                           QualType t) {
-  const auto *rd = t->getAsRecordDecl();
-  if (!rd)
-    return false;
-
-  // If this is a C++ record, check the bases first.
-  if (const CXXRecordDecl *cxxrd = dyn_cast<CXXRecordDecl>(rd)) {
-    if (cxxrd->isDynamicClass())
-      return false;
-
-    for (const auto &i : cxxrd->bases())
-      if (!isEmptyRecordForLayout(context, i.getType()))
-        return false;
-  }
-
-  for (const auto *i : rd->fields())
-    if (!isEmptyFieldForLayout(context, i))
-      return false;
-
-  return true;
-}
-
-bool clang::CIRGen::isEmptyFieldForLayout(const ASTContext &context,
-                                          const FieldDecl *fd) {
-  if (fd->isZeroLengthBitField())
-    return true;
-
-  if (fd->isUnnamedBitField())
-    return false;
-
-  return isEmptyRecordForLayout(context, fd->getType());
-}
-
 bool clang::CIRGen::isEmptyRecordForABI(const ASTContext &context, QualType t) {
   const auto *rd = t->getAsRecordDecl();
   if (!rd)
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h
index 5f380026e025da..e094fa53561f5a 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -21,21 +21,15 @@
 #include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/Dialect/IR/CIROpsEnums.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
 
 #include <memory>
 #include <utility>
 
 namespace clang::CIRGen {
 
-/// isEmptyFieldForLayout - Return true if the field is "empty", that is,
-/// either a zero-width bit-field or an isEmptyRecordForLayout.
-bool isEmptyFieldForLayout(const ASTContext &context, const FieldDecl *fd);
-
-/// isEmptyRecordForLayout - Return true if a structure contains only empty
-/// base classes (per  isEmptyRecordForLayout) and fields (per
-/// isEmptyFieldForLayout). Note, C++ record fields are considered empty
-/// if the [[no_unique_address]] attribute would have made them empty.
-bool isEmptyRecordForLayout(const ASTContext &context, QualType t);
+using CodeGenUtils::isEmptyFieldForLayout;
+using CodeGenUtils::isEmptyRecordForLayout;
 
 /// isEmptyFieldForABI - Return true if the field is "empty", that is, it is a
 /// zero-width bit-field or an (array of) empty record(s).  An unnamed
diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp
index 887a645a4783a7..23b6b7e8200da1 100644
--- a/clang/lib/CodeGen/ABIInfoImpl.cpp
+++ b/clang/lib/CodeGen/ABIInfoImpl.cpp
@@ -302,39 +302,6 @@ bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
   return true;
 }
 
-bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context,
-                                    const FieldDecl *FD) {
-  if (FD->isZeroLengthBitField())
-    return true;
-
-  if (FD->isUnnamedBitField())
-    return false;
-
-  return isEmptyRecordForLayout(Context, FD->getType());
-}
-
-bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) {
-  const auto *RD = T->getAsRecordDecl();
-  if (!RD)
-    return false;
-
-  // If this is a C++ record, check the bases first.
-  if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
-    if (CXXRD->isDynamicClass())
-      return false;
-
-    for (const auto &I : CXXRD->bases())
-      if (!isEmptyRecordForLayout(Context, I.getType()))
-        return false;
-  }
-
-  for (const auto *I : RD->fields())
-    if (!isEmptyFieldForLayout(Context, I))
-      return false;
-
-  return true;
-}
-
 const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) {
   const auto *RD = T->getAsRecordDecl();
   if (!RD)
diff --git a/clang/lib/CodeGen/ABIInfoImpl.h b/clang/lib/CodeGen/ABIInfoImpl.h
index d9d79c6a55ddb1..89ea2219096a2e 100644
--- a/clang/lib/CodeGen/ABIInfoImpl.h
+++ b/clang/lib/CodeGen/ABIInfoImpl.h
@@ -11,6 +11,7 @@
 
 #include "ABIInfo.h"
 #include "CGCXXABI.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
 
 namespace clang::CodeGen {
 
@@ -120,15 +121,8 @@ bool isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays,
 bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
                    bool AsIfNoUniqueAddr = false);
 
-/// isEmptyFieldForLayout - Return true iff the field is "empty", that is,
-/// either a zero-width bit-field or an \ref isEmptyRecordForLayout.
-bool isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD);
-
-/// isEmptyRecordForLayout - Return true iff a structure contains only empty
-/// base classes (per \ref isEmptyRecordForLayout) and fields (per
-/// \ref isEmptyFieldForLayout). Note, C++ record fields are considered empty
-/// if the [[no_unique_address]] attribute would have made them empty.
-bool isEmptyRecordForLayout(const ASTContext &Context, QualType T);
+using CodeGenUtils::isEmptyFieldForLayout;
+using CodeGenUtils::isEmptyRecordForLayout;
 
 /// isSingleElementStruct - Determine if a structure is a "single
 /// element struct", i.e. it has exactly one non-empty field or
diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
index d98d7c0c96dc3d..905382f5ea9395 100644
--- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -22,6 +22,7 @@
 #include "clang/AST/RecordLayout.h"
 #include "clang/Basic/CodeGenOptions.h"
 #include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Type.h"
@@ -100,27 +101,9 @@ struct CGRecordLowering {
     return MemberInfo(Offset, MemberInfo::Field, Data);
   }
 
-  /// The Microsoft bitfield layout rule allocates discrete storage
-  /// units of the field's formal type and only combines adjacent
-  /// fields of the same formal type.  We want to emit a layout with
-  /// these discrete storage units instead of combining them into a
-  /// continuous run.
-  bool isDiscreteBitFieldABI() const {
-    return Context.getTargetInfo().getCXXABI().isMicrosoft() ||
-           D->isMsStruct(Context);
-  }
-
   /// Helper function to check if the target machine is BigEndian.
   bool isBE() const { return Context.getTargetInfo().isBigEndian(); }
 
-  /// The Itanium base layout rule allows virtual bases to overlap
-  /// other bases, which complicates layout in specific ways.
-  ///
-  /// Note specifically that the ms_struct attribute doesn't change this.
-  bool isOverlappingVBaseABI() const {
-    return !Context.getTargetInfo().getCXXABI().isMicrosoft();
-  }
-
   /// Wraps llvm::Type::getIntNTy with some implicit arguments.
   llvm::Type *getIntNType(uint64_t NumBits) const {
     unsigned AlignedBits = llvm::alignTo(NumBits, Context.getCharWidth());
@@ -143,7 +126,8 @@ struct CGRecordLowering {
   llvm::Type *getStorageType(const FieldDecl *FD) const {
     llvm::Type *Type = Types.ConvertTypeForMem(FD->getType());
     if (!FD->isBitField()) return Type;
-    if (isDiscreteBitFieldABI()) return Type;
+    if (CodeGenUtils::isDiscreteBitFieldABI(Context, D))
+      return Type;
     return getIntNType(std::min(FD->getBitWidthValue(),
                                 (unsigned)Context.toBits(getSize(Type))));
   }
@@ -188,10 +172,6 @@ struct CGRecordLowering {
   void accumulateBases();
   void accumulateVPtrs();
   void accumulateVBases();
-  /// Recursively searches all of the bases to find out if a vbase is
-  /// not the primary vbase of some base class.
-  bool hasOwnStorage(const CXXRecordDecl *Decl,
-                     const CXXRecordDecl *Query) const;
   void calculateZeroInit();
   CharUnits calculateTailClippingOffset(bool isNonVirtualBaseType) const;
   void checkBitfieldClipping(bool isNonVirtualBaseType) const;
@@ -406,7 +386,7 @@ RecordDecl::field_iterator
 CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
                                       RecordDecl::field_iterator Field,
                                       RecordDecl::field_iterator FieldEnd) {
-  if (isDiscreteBitFieldABI()) {
+  if (CodeGenUtils::isDiscreteBitFieldABI(Context, D)) {
     // Run stores the first element of the current run of bitfields. FieldEnd is
     // used as a special value to note that we don't have a current run. A
     // bitfield run is a contiguous collection of bitfields that can be stored
@@ -874,14 +854,15 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
   // smaller than the nvsize.  Here we check to see if such a base is placed
   // before the nvsize and set the scissor offset to that, instead of the
   // nvsize.
-  if (!isNonVirtualBaseType && isOverlappingVBaseABI())
+  if (!isNonVirtualBaseType && CodeGenUtils::isOverlappingVBaseABI(Context))
     for (const auto &Base : RD->vbases()) {
       const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
       if (isEmptyRecordForLayout(Context, Base.getType()))
         continue;
       // If the vbase is a primary virtual base of some base, then it doesn't
       // get its own storage location but instead lives inside of that base.
-      if (Context.isNearlyEmpty(BaseDecl) && !hasOwnStorage(RD, BaseDecl))
+      if (Context.isNearlyEmpty(BaseDecl) &&
+          !CodeGenUtils::hasOwnStorage(Context, RD, BaseDecl))
         continue;
       ScissorOffset = std::min(ScissorOffset,
                                Layout.getVBaseClassOffset(BaseDecl));
@@ -898,9 +879,9 @@ void CGRecordLowering::accumulateVBases() {
     CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl);
     // If the vbase is a primary virtual base of some base, then it doesn't
     // get its own storage location but instead lives inside of that base.
-    if (isOverlappingVBaseABI() &&
+    if (CodeGenUtils::isOverlappingVBaseABI(Context) &&
         Context.isNearlyEmpty(BaseDecl) &&
-        !hasOwnStorage(RD, BaseDecl)) {
+        !CodeGenUtils::hasOwnStorage(Context, RD, BaseDecl)) {
       Members.push_back(MemberInfo(Offset, MemberInfo::VBase, nullptr,
                                    BaseDecl));
       continue;
@@ -914,17 +895,6 @@ void CGRecordLowering::accumulateVBases() {
   }
 }
 
-bool CGRecordLowering::hasOwnStorage(const CXXRecordDecl *Decl,
-                                     const CXXRecordDecl *Query) const {
-  const ASTRecordLayout &DeclLayout = Context.getASTRecordLayout(Decl);
-  if (DeclLayout.isPrimaryBaseVirtual() && DeclLayout.getPrimaryBase() == Query)
-    return false;
-  for (const auto &Base : Decl->bases())
-    if (!hasOwnStorage(Base.getType()->getAsCXXRecordDecl(), Query))
-      return false;
-  return true;
-}
-
 void CGRecordLowering::calculateZeroInit() {
   for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
                                                MemberEnd = Members.end();
diff --git a/clang/lib/CodeGenUtils/CMakeLists.txt b/clang/lib/CodeGenUtils/CMakeLists.txt
index 5839e8f2e1fe5e..f46ac572a0ce90 100644
--- a/clang/lib/CodeGenUtils/CMakeLists.txt
+++ b/clang/lib/CodeGenUtils/CMakeLists.txt
@@ -11,6 +11,7 @@ add_clang_library(clangCodeGenUtils
   FunctionUtils.cpp
   ItaniumCXXABIUtils.cpp
   ModuleUtils.cpp
+  RecordLayoutUtils.cpp
 
   LINK_LIBS
   clangAST
diff --git a/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
new file mode 100644
index 00000000000000..31306470b6da65
--- /dev/null
+++ b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
@@ -0,0 +1,66 @@
+//===--- RecordLayoutUtils.cpp - Shared record layout queries -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/TargetInfo.h"
+
+namespace clang::CodeGenUtils {
+
+bool hasOwnStorage(const ASTContext &Ctx, const CXXRecordDecl *Decl,
+                   const CXXRecordDecl *Query) {
+  const ASTRecordLayout &DeclLayout = Ctx.getASTRecordLayout(Decl);
+  if (DeclLayout.isPrimaryBaseVirtual() && DeclLayout.getPrimaryBase() == Query)
+    return false;
+  for (const auto &Base : Decl->bases())
+    if (!hasOwnStorage(Ctx, Base.getType()->getAsCXXRecordDecl(), Query))
+      return false;
+  return true;
+}
+
+bool isDiscreteBitFieldABI(const ASTContext &Ctx, const RecordDecl *RD) {
+  return Ctx.getTargetInfo().getCXXABI().isMicrosoft() || RD->isMsStruct(Ctx);
+}
+
+bool isEmptyFieldForLayout(const ASTContext &Ctx, const FieldDecl *FD) {
+  if (FD->isZeroLengthBitField())
+    return true;
+
+  if (FD->isUnnamedBitField())
+    return false;
+
+  return isEmptyRecordForLayout(Ctx, FD->getType());
+}
+
+bool isEmptyRecordForLayout(const ASTContext &Ctx, QualType T) {
+  const auto *RD = T->getAsRecordDecl();
+  if (!RD)
+    return false;
+
+  // If this is a C++ record, check the bases first.
+  if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+    if (CXXRD->isDynamicClass())
+      return false;
+
+    for (const auto &I : CXXRD->bases())
+      if (!isEmptyRecordForLayout(Ctx, I.getType()))
+        return false;
+  }
+
+  for (const auto *I : RD->fields())
+    if (!isEmptyFieldForLayout(Ctx, I))
+      return false;
+
+  return true;
+}
+
+bool isOverlappingVBaseABI(const ASTContext &Ctx) {
+  return !Ctx.getTargetInfo().getCXXABI().isMicrosoft();
+}
+
+} // namespace clang::CodeGenUtils



More information about the llvm-branch-commits mailing list