[llvm-branch-commits] [clang] [CIR][CodeGen][NFC] Share isEmptyFieldForLayout and isEmptyRecordForLayout (PR #223424)
Henrich Lauko via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Oct 6 05:50:14 PDT 2026
https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/223424
>From 4fa3ab3578ca2573d1b2d05a201b8b6d4bc31aa3 Mon Sep 17 00:00:00 2001
From: Henrich Lauko <hlauko at nvidia.com>
Date: Tue, 29 Sep 2026 09:56:08 +0000
Subject: [PATCH] [CIR][CodeGen][NFC] Share isEmptyFieldForLayout and
isEmptyRecordForLayout
Deduplicates `isEmptyFieldForLayout` and `isEmptyRecordForLayout` between CIR
and classic CodeGen into a new `RecordLayoutUtils.h`. The 25 callers now name
them as `CodeGenUtils::isEmptyFieldForLayout` and
`CodeGenUtils::isEmptyRecordForLayout`, like the other shared helpers.
Assisted-by: Claude Code (Claude Fable 5.1).
---
.../clang/CodeGenUtils/RecordLayoutUtils.h | 34 ++++++++++++++
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 3 +-
clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp | 6 ++-
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 3 +-
.../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 7 +--
clang/lib/CIR/CodeGen/TargetInfo.cpp | 34 --------------
clang/lib/CIR/CodeGen/TargetInfo.h | 9 ----
clang/lib/CodeGen/ABIInfoImpl.cpp | 33 --------------
clang/lib/CodeGen/ABIInfoImpl.h | 9 ----
clang/lib/CodeGen/CGClass.cpp | 5 ++-
clang/lib/CodeGen/CGExpr.cpp | 3 +-
clang/lib/CodeGen/CGExprConstant.cpp | 11 ++---
clang/lib/CodeGen/CGOpenMPRuntime.cpp | 7 +--
clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 13 +++---
clang/lib/CodeGen/CodeGenTBAA.cpp | 3 +-
clang/lib/CodeGenUtils/CMakeLists.txt | 1 +
clang/lib/CodeGenUtils/RecordLayoutUtils.cpp | 45 +++++++++++++++++++
17 files changed, 116 insertions(+), 110 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 0000000000000..77f14fee5a3b4
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
@@ -0,0 +1,34 @@
+//===--- 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 {
+
+/// 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);
+
+} // namespace clang::CodeGenUtils
+
+#endif // LLVM_CLANG_CODEGENUTILS_RECORDLAYOUTUTILS_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 1f738f9737d31..51533f9dc0f9c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -32,6 +32,7 @@
#include "clang/CIR/MissingFeatures.h"
#include "clang/CodeGenUtils/CodeGenUtils.h"
#include "clang/CodeGenUtils/ExprUtils.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
#include <optional>
using namespace clang;
@@ -77,7 +78,7 @@ Address CIRGenFunction::emitAddrOfFieldStorage(Address base,
bool addressedByFieldIndex =
field->isPotentiallyOverlapping()
? layout.hasCIRField(field)
- : !isEmptyFieldForLayout(getContext(), field);
+ : !CodeGenUtils::isEmptyFieldForLayout(getContext(), field);
if (!addressedByFieldIndex)
return emitAddrOfZeroSizeField(*this, base, field);
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index afc6b8058066d..100d11916dcee 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -29,6 +29,7 @@
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
@@ -1210,7 +1211,8 @@ static mlir::TypedAttr emitNullConstant(CIRGenModule &cgm, const RecordDecl *rd,
const auto *baseDecl = base.getType()->castAsCXXRecordDecl();
// Ignore empty bases.
- if (isEmptyRecordForLayout(cgm.getASTContext(), base.getType()) ||
+ if (CodeGenUtils::isEmptyRecordForLayout(cgm.getASTContext(),
+ base.getType()) ||
cgm.getASTContext()
.getASTRecordLayout(baseDecl)
.getNonVirtualSize()
@@ -1228,7 +1230,7 @@ static mlir::TypedAttr emitNullConstant(CIRGenModule &cgm, const RecordDecl *rd,
// Fill in non-bitfields. (Bitfields always use a zero pattern, which we
// will fill in later.)
if (!field->isBitField() &&
- !isEmptyFieldForLayout(cgm.getASTContext(), field)) {
+ !CodeGenUtils::isEmptyFieldForLayout(cgm.getASTContext(), field)) {
unsigned fieldIndex = layout.getCIRFieldNo(field);
elements[fieldIndex] = cgm.emitNullConstantAttr(field->getType());
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 5063b6a4cc779..92c8af433aace 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -38,6 +38,7 @@
#include "clang/CIR/MissingFeatures.h"
#include "clang/CodeGenUtils/CodeGenUtils.h"
#include "clang/CodeGenUtils/ModuleUtils.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
@@ -2493,7 +2494,7 @@ bool CIRGenModule::findFieldMemberPath(const CXXRecordDecl *currentClass,
bool CIRGenModule::isEmptyFieldForMemberPointer(const FieldDecl *field) {
if (!field->isPotentiallyOverlapping() ||
- !isEmptyFieldForLayout(astContext, field))
+ !CodeGenUtils::isEmptyFieldForLayout(astContext, field))
return false;
// Unions always have a field even if they are empty.
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index c2075a245f05c..8617ba5561e41 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>
@@ -632,7 +633,7 @@ CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator field,
// non-reusable tail padding.
CharUnits limitOffset;
for (auto probe = field; probe != fieldEnd; ++probe)
- if (!isEmptyFieldForLayout(astContext, *probe)) {
+ if (!CodeGenUtils::isEmptyFieldForLayout(astContext, *probe)) {
// A member with storage sets the limit.
assert((getFieldBitOffset(*probe) % charBits) == 0 &&
"Next storage is not byte-aligned");
@@ -730,7 +731,7 @@ void CIRRecordLowering::accumulateFields(bool nonVirtualBaseType) {
field = accumulateBitFields(field, fieldEnd);
assert((field == fieldEnd || !field->isBitField()) &&
"Failed to accumulate all the bitfields");
- } else if (isEmptyFieldForLayout(astContext, *field) &&
+ } else if (CodeGenUtils::isEmptyFieldForLayout(astContext, *field) &&
field->isPotentiallyOverlapping()) {
// We lay out normal empty fields, as they are required for GEPs/getting
// function pointers. However 'no-unique-address' lends some additional
@@ -1287,7 +1288,7 @@ void CIRRecordLowering::accumulateBases() {
void CIRRecordLowering::accumulateVBases() {
for (const auto &base : cxxRecordDecl->vbases()) {
const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();
- if (isEmptyRecordForLayout(astContext, base.getType()))
+ if (CodeGenUtils::isEmptyRecordForLayout(astContext, base.getType()))
continue;
CharUnits offset = astRecordLayout.getVBaseClassOffset(baseDecl);
// If the vbase is a primary virtual base of some base, then it doesn't
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp
index cede4941b4473..57bc5f167e460 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 5f380026e025d..69910491cceca 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -27,15 +27,6 @@
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);
/// 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 887a645a4783a..23b6b7e8200da 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 d9d79c6a55ddb..180a76f4a820e 100644
--- a/clang/lib/CodeGen/ABIInfoImpl.h
+++ b/clang/lib/CodeGen/ABIInfoImpl.h
@@ -120,15 +120,6 @@ 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);
/// 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/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 63f5d9ae13dbf..7e832f8155aa7 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -27,6 +27,7 @@
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/CodeGenUtils/ClassUtils.h"
#include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -882,7 +883,7 @@ class FieldMemcpyizer {
}
void addMemcpyableField(FieldDecl *F) {
- if (isEmptyFieldForLayout(CGF.getContext(), F))
+ if (CodeGenUtils::isEmptyFieldForLayout(CGF.getContext(), F))
return;
if (!FirstField)
addInitialField(F);
@@ -1863,7 +1864,7 @@ class SanitizeDtorCleanupBuilder {
const CXXDestructorDecl *DD)
: Context(Context), EHStack(EHStack), DD(DD), StartIndex(std::nullopt) {}
void PushCleanupForField(const FieldDecl *Field) {
- if (isEmptyFieldForLayout(Context, Field))
+ if (CodeGenUtils::isEmptyFieldForLayout(Context, Field))
return;
unsigned FieldIndex = Field->getFieldIndex();
if (CodeGenUtils::fieldHasTrivialDestructorBody(Context, Field)) {
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 76bd781a709b6..8323a170a1dbb 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -41,6 +41,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/CodeGenUtils/CodeGenUtils.h"
#include "clang/CodeGenUtils/ExprUtils.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringExtras.h"
@@ -5909,7 +5910,7 @@ static Address emitAddrOfZeroSizeField(CodeGenFunction &CGF, Address Base,
static Address emitRawAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
const FieldDecl *field,
bool IsInBounds) {
- if (isEmptyFieldForLayout(CGF.getContext(), field))
+ if (CodeGenUtils::isEmptyFieldForLayout(CGF.getContext(), field))
return emitAddrOfZeroSizeField(CGF, base, field, IsInBounds);
const RecordDecl *rec = field->getParent();
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index cc4793d328166..e2ec07bbae711 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -26,6 +26,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/Analysis/ConstantFolding.h"
@@ -762,7 +763,7 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) {
// Zero-sized fields are not emitted, but their initializers may still
// prevent emission of this struct as a constant.
- if (isEmptyFieldForLayout(CGM.getContext(), Field)) {
+ if (CodeGenUtils::isEmptyFieldForLayout(CGM.getContext(), Field)) {
if (Init && Init->HasSideEffects(CGM.getContext()))
return false;
continue;
@@ -925,7 +926,7 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
// Don't emit anonymous bitfields or zero-sized fields.
if (Field->isUnnamedBitField() ||
- isEmptyFieldForLayout(CGM.getContext(), *Field))
+ CodeGenUtils::isEmptyFieldForLayout(CGM.getContext(), *Field))
continue;
// Emit the value of the initializer.
@@ -2842,7 +2843,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
const auto *base = I.getType()->castAsCXXRecordDecl();
// Ignore empty bases.
- if (isEmptyRecordForLayout(CGM.getContext(), I.getType()) ||
+ if (CodeGenUtils::isEmptyRecordForLayout(CGM.getContext(), I.getType()) ||
CGM.getContext()
.getASTRecordLayout(base)
.getNonVirtualSize()
@@ -2860,7 +2861,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
// Fill in non-bitfields. (Bitfields always use a zero pattern, which we
// will fill in later.)
if (!Field->isBitField() &&
- !isEmptyFieldForLayout(CGM.getContext(), Field)) {
+ !CodeGenUtils::isEmptyFieldForLayout(CGM.getContext(), Field)) {
unsigned fieldIndex = layout.getLLVMFieldNo(Field);
elements[fieldIndex] = CGM.EmitNullConstant(Field->getType());
}
@@ -2880,7 +2881,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
for (const auto &I : CXXR->vbases()) {
const auto *base = I.getType()->castAsCXXRecordDecl();
// Ignore empty bases.
- if (isEmptyRecordForLayout(CGM.getContext(), I.getType()))
+ if (CodeGenUtils::isEmptyRecordForLayout(CGM.getContext(), I.getType()))
continue;
unsigned fieldIndex = layout.getVirtualBaseIndex(base);
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 58bfd48a49d39..9893ecc4ec7cc 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -28,6 +28,7 @@
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/SourceManager.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -8937,7 +8938,7 @@ class MappableExprsHandler {
QualType BaseTy = I.getType();
const auto *Base = BaseTy->getAsCXXRecordDecl();
// Ignore empty bases.
- if (isEmptyRecordForLayout(CGF.getContext(), BaseTy) ||
+ if (CodeGenUtils::isEmptyRecordForLayout(CGF.getContext(), BaseTy) ||
CGF.getContext()
.getASTRecordLayout(Base)
.getNonVirtualSize()
@@ -8951,7 +8952,7 @@ class MappableExprsHandler {
for (const auto &I : RD->vbases()) {
QualType BaseTy = I.getType();
// Ignore empty bases.
- if (isEmptyRecordForLayout(CGF.getContext(), BaseTy))
+ if (CodeGenUtils::isEmptyRecordForLayout(CGF.getContext(), BaseTy))
continue;
const auto *Base = BaseTy->getAsCXXRecordDecl();
@@ -8966,7 +8967,7 @@ class MappableExprsHandler {
// Fill in non-bitfields. (Bitfields always use a zero pattern, which we
// will fill in later.)
if (!Field->isBitField() &&
- !isEmptyFieldForLayout(CGF.getContext(), Field)) {
+ !CodeGenUtils::isEmptyFieldForLayout(CGF.getContext(), Field)) {
unsigned FieldIndex = RL.getLLVMFieldNo(Field);
RecordLayout[FieldIndex] = Field;
}
diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
index d98d7c0c96dc3..14c4b969e141c 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"
@@ -381,7 +382,7 @@ void CGRecordLowering::accumulateFields(bool isNonVirtualBaseType) {
Field = accumulateBitFields(isNonVirtualBaseType, Field, FieldEnd);
assert((Field == FieldEnd || !Field->isBitField()) &&
"Failed to accumulate all the bitfields");
- } else if (isEmptyFieldForLayout(Context, *Field)) {
+ } else if (CodeGenUtils::isEmptyFieldForLayout(Context, *Field)) {
// Empty fields have no storage.
++Field;
} else {
@@ -630,7 +631,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// non-reusable tail padding.
CharUnits LimitOffset;
for (auto Probe = Field; Probe != FieldEnd; ++Probe)
- if (!isEmptyFieldForLayout(Context, *Probe)) {
+ if (!CodeGenUtils::isEmptyFieldForLayout(Context, *Probe)) {
// A member with storage sets the limit.
assert((getFieldBitOffset(*Probe) % CharBits) == 0 &&
"Next storage is not byte-aligned");
@@ -728,7 +729,7 @@ void CGRecordLowering::accumulateBases() {
// Bases can be zero-sized even if not technically empty if they
// contain only a trailing array member.
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
- if (!isEmptyRecordForLayout(Context, Base.getType()) &&
+ if (!CodeGenUtils::isEmptyRecordForLayout(Context, Base.getType()) &&
!Context.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero())
Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl),
MemberInfo::Base, getStorageType(BaseDecl), BaseDecl));
@@ -877,7 +878,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
if (!isNonVirtualBaseType && isOverlappingVBaseABI())
for (const auto &Base : RD->vbases()) {
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
- if (isEmptyRecordForLayout(Context, Base.getType()))
+ if (CodeGenUtils::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.
@@ -893,7 +894,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
void CGRecordLowering::accumulateVBases() {
for (const auto &Base : RD->vbases()) {
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
- if (isEmptyRecordForLayout(Context, Base.getType()))
+ if (CodeGenUtils::isEmptyRecordForLayout(Context, Base.getType()))
continue;
CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl);
// If the vbase is a primary virtual base of some base, then it doesn't
@@ -1154,7 +1155,7 @@ CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) {
const FieldDecl *FD = *it;
// Ignore zero-sized fields.
- if (isEmptyFieldForLayout(getContext(), FD))
+ if (CodeGenUtils::isEmptyFieldForLayout(getContext(), FD))
continue;
// For non-bit-fields, just check that the LLVM struct offset matches the
diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp
index 1854df7c7c0f1..d33188db9da15 100644
--- a/clang/lib/CodeGen/CodeGenTBAA.cpp
+++ b/clang/lib/CodeGen/CodeGenTBAA.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
@@ -455,7 +456,7 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset,
unsigned idx = 0;
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i, ++idx) {
- if (isEmptyFieldForLayout(Context, *i))
+ if (CodeGenUtils::isEmptyFieldForLayout(Context, *i))
continue;
uint64_t Offset =
diff --git a/clang/lib/CodeGenUtils/CMakeLists.txt b/clang/lib/CodeGenUtils/CMakeLists.txt
index 83b11a5ed2cdf..2052ca13f6e5d 100644
--- a/clang/lib/CodeGenUtils/CMakeLists.txt
+++ b/clang/lib/CodeGenUtils/CMakeLists.txt
@@ -15,6 +15,7 @@ add_clang_library(clangCodeGenUtils
FunctionUtils.cpp
ItaniumCXXABIUtils.cpp
ModuleUtils.cpp
+ RecordLayoutUtils.cpp
StmtUtils.cpp
LINK_LIBS
diff --git a/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
new file mode 100644
index 0000000000000..3b8d433dc8759
--- /dev/null
+++ b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
@@ -0,0 +1,45 @@
+//===--- 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"
+
+namespace clang::CodeGenUtils {
+
+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;
+}
+
+} // namespace clang::CodeGenUtils
More information about the llvm-branch-commits
mailing list