[clang] [clang][bytecode] Use a regular static function in `Pointer::toRValue()` (PR #219772)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Sun Aug 30 00:01:48 PDT 2026
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/219772
>From 2a8076f69982cb2b424f345b17e64541cfef3dcc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sun, 30 Aug 2026 07:42:14 +0200
Subject: [PATCH] torvalue
---
clang/lib/AST/ByteCode/Pointer.cpp | 293 ++++++++++++++---------------
1 file changed, 146 insertions(+), 147 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 01968cfe6c9a1..e7b78bde0f2f2 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -980,177 +980,176 @@ Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) {
llvm_unreachable("The loop above should've returned.");
}
-std::optional<APValue> Pointer::toRValue(const Context &Ctx,
- QualType ResultType) const {
+/// Convert a pointer to a composite value to an rvalue.
+static bool toRValue(const Context &Ctx, QualType Ty, PtrView Ptr, APValue &R) {
const ASTContext &ASTCtx = Ctx.getASTContext();
- assert(!ResultType.isNull());
- // Method to recursively traverse composites.
- std::function<bool(QualType, PtrView, APValue &)> Composite;
- Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, PtrView Ptr,
- APValue &R) {
- if (const auto *AT = Ty->getAs<AtomicType>())
- Ty = AT->getValueType();
-
- // Invalid pointers.
- if (Ptr.isDummy() || !Ptr.isLive() || Ptr.isPastEnd())
- return false;
+ if (const auto *AT = Ty->getAs<AtomicType>())
+ Ty = AT->getValueType();
- // Primitives should never end up here.
- assert(!Ctx.canClassify(Ty));
- const Descriptor *FieldDesc = Ptr.getFieldDesc();
- assert(FieldDesc);
-
- if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
- if (!FieldDesc->isRecord())
- return false;
- const auto *Record = Ptr.getRecord();
- assert(Record && "Missing record descriptor");
-
- bool Ok = true;
- if (RT->getDecl()->isUnion()) {
- const FieldDecl *ActiveField = nullptr;
- APValue Value;
- for (const auto &F : Record->fields()) {
- PtrView FP = Ptr.atField(F.Offset);
- if (FP.isActive()) {
- const Descriptor *Desc = F.Desc;
- if (Desc->isPrimitive()) {
- TYPE_SWITCH(Desc->getPrimType(),
- Value = FP.deref<T>().toAPValue(ASTCtx));
- } else {
- QualType FieldTy = F.Decl->getType();
- Ok &= Composite(FieldTy, FP, Value);
- }
- ActiveField = FP.getFieldDesc()->asFieldDecl();
- break;
- }
- }
- R = APValue(ActiveField, Value);
- } else {
- unsigned NF = Record->getNumFields();
- unsigned NB = Record->getNumBases();
- unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
+ // Invalid pointers.
+ if (Ptr.isDummy() || !Ptr.isLive() || Ptr.isPastEnd())
+ return false;
- R = APValue(APValue::UninitStruct(), NB, NF, NV);
+ // Primitives should never end up here.
+ assert(!Ctx.canClassify(Ty));
+ const Descriptor *FieldDesc = Ptr.getFieldDesc();
+ assert(FieldDesc);
- for (unsigned I = 0; I != NF; ++I) {
- const Record::Field *FD = Record->getField(I);
- const Descriptor *Desc = FD->Desc;
- PtrView FP = Ptr.atField(FD->Offset);
- APValue &Value = R.getStructField(I);
+ if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
+ if (!FieldDesc->isRecord())
+ return false;
+ const auto *Record = Ptr.getRecord();
+ assert(Record && "Missing record descriptor");
+
+ bool Ok = true;
+ if (RT->getDecl()->isUnion()) {
+ const FieldDecl *ActiveField = nullptr;
+ APValue Value;
+ for (const auto &F : Record->fields()) {
+ PtrView FP = Ptr.atField(F.Offset);
+ if (FP.isActive()) {
+ const Descriptor *Desc = F.Desc;
if (Desc->isPrimitive()) {
TYPE_SWITCH(Desc->getPrimType(),
Value = FP.deref<T>().toAPValue(ASTCtx));
} else {
- QualType FieldTy = FD->Decl->getType();
- Ok &= Composite(FieldTy, FP, Value);
+ QualType FieldTy = F.Decl->getType();
+ Ok &= toRValue(Ctx, FieldTy, FP, Value);
}
+ ActiveField = FP.getFieldDesc()->asFieldDecl();
+ break;
}
-
- for (unsigned I = 0; I != NB; ++I) {
- const Record::Base *BD = Record->getBase(I);
- QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl);
- PtrView BP = Ptr.atField(BD->Offset);
- Ok &= Composite(BaseTy, BP, R.getStructBase(I));
+ }
+ R = APValue(ActiveField, Value);
+ } else {
+ unsigned NF = Record->getNumFields();
+ unsigned NB = Record->getNumBases();
+ unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
+
+ R = APValue(APValue::UninitStruct(), NB, NF, NV);
+
+ for (unsigned I = 0; I != NF; ++I) {
+ const Record::Field *FD = Record->getField(I);
+ const Descriptor *Desc = FD->Desc;
+ PtrView FP = Ptr.atField(FD->Offset);
+ APValue &Value = R.getStructField(I);
+ if (Desc->isPrimitive()) {
+ TYPE_SWITCH(Desc->getPrimType(),
+ Value = FP.deref<T>().toAPValue(ASTCtx));
+ } else {
+ QualType FieldTy = FD->Decl->getType();
+ Ok &= toRValue(Ctx, FieldTy, FP, Value);
}
+ }
- for (unsigned I = 0; I != NV; ++I) {
- const Record::Base *VD = Record->getVirtualBase(I);
- assert(VD);
- QualType VirtBaseTy =
- Ctx.getASTContext().getCanonicalTagType(VD->Decl);
- PtrView VP = Ptr.atField(VD->Offset);
- Ok &= Composite(VirtBaseTy, VP, R.getStructVirtualBase(I));
- }
+ for (unsigned I = 0; I != NB; ++I) {
+ const Record::Base *BD = Record->getBase(I);
+ QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl);
+ PtrView BP = Ptr.atField(BD->Offset);
+ Ok &= toRValue(Ctx, BaseTy, BP, R.getStructBase(I));
}
- return Ok;
- }
- if (Ty->isIncompleteArrayType()) {
- R = APValue(APValue::UninitArray(), 0, 0);
- return true;
+ for (unsigned I = 0; I != NV; ++I) {
+ const Record::Base *VD = Record->getVirtualBase(I);
+ assert(VD);
+ QualType VirtBaseTy = Ctx.getASTContext().getCanonicalTagType(VD->Decl);
+ PtrView VP = Ptr.atField(VD->Offset);
+ Ok &= toRValue(Ctx, VirtBaseTy, VP, R.getStructVirtualBase(I));
+ }
}
+ return Ok;
+ }
- if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
- if (!FieldDesc->isArray())
- return false;
- const size_t NumElems = Ptr.getNumElems();
- QualType ElemTy = AT->getElementType();
- R = APValue(APValue::UninitArray{}, NumElems, NumElems);
-
- bool Ok = true;
- OptPrimType ElemT = Ctx.classify(ElemTy);
- for (unsigned I = 0; I != NumElems; ++I) {
- APValue &Slot = R.getArrayInitializedElt(I);
- if (ElemT) {
- TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
- } else {
- Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);
- }
+ if (Ty->isIncompleteArrayType()) {
+ R = APValue(APValue::UninitArray(), 0, 0);
+ return true;
+ }
+
+ if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
+ if (!FieldDesc->isArray())
+ return false;
+ const size_t NumElems = Ptr.getNumElems();
+ QualType ElemTy = AT->getElementType();
+ R = APValue(APValue::UninitArray{}, NumElems, NumElems);
+
+ bool Ok = true;
+ OptPrimType ElemT = Ctx.classify(ElemTy);
+ for (unsigned I = 0; I != NumElems; ++I) {
+ APValue &Slot = R.getArrayInitializedElt(I);
+ if (ElemT) {
+ TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
+ } else {
+ Ok &= toRValue(Ctx, ElemTy, Ptr.atIndex(I).narrow(), Slot);
}
- return Ok;
}
+ return Ok;
+ }
- // Complex types.
- if (Ty->isAnyComplexType()) {
- // Can happen via C casts.
- if (!FieldDesc->getType()->isAnyComplexType())
- return false;
-
- PrimType ElemT = FieldDesc->getPrimType();
- if (isIntegerOrBoolType(ElemT)) {
- INT_TYPE_SWITCH(ElemT, {
- auto V1 = Ptr.elem<T>(0);
- auto V2 = Ptr.elem<T>(1);
- R = APValue(V1.toAPSInt(), V2.toAPSInt());
- return true;
- });
- } else if (ElemT == PT_Float) {
- R = APValue(Ptr.elem<Floating>(0).getAPFloat(),
- Ptr.elem<Floating>(1).getAPFloat());
- return true;
- }
+ // Complex types.
+ if (Ty->isAnyComplexType()) {
+ // Can happen via C casts.
+ if (!FieldDesc->getType()->isAnyComplexType())
return false;
+
+ PrimType ElemT = FieldDesc->getPrimType();
+ if (isIntegerOrBoolType(ElemT)) {
+ INT_TYPE_SWITCH(ElemT, {
+ auto V1 = Ptr.elem<T>(0);
+ auto V2 = Ptr.elem<T>(1);
+ R = APValue(V1.toAPSInt(), V2.toAPSInt());
+ return true;
+ });
+ } else if (ElemT == PT_Float) {
+ R = APValue(Ptr.elem<Floating>(0).getAPFloat(),
+ Ptr.elem<Floating>(1).getAPFloat());
+ return true;
}
+ return false;
+ }
- // Vector types.
- if (const auto *VT = Ty->getAs<VectorType>()) {
- if (!FieldDesc->isPrimitiveArray())
- return false;
-
- PrimType ElemT = FieldDesc->getPrimType();
- SmallVector<APValue> Values;
- Values.reserve(VT->getNumElements());
- for (unsigned I = 0; I != VT->getNumElements(); ++I) {
- TYPE_SWITCH(ElemT,
- { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
- }
+ // Vector types.
+ if (const auto *VT = Ty->getAs<VectorType>()) {
+ if (!FieldDesc->isPrimitiveArray())
+ return false;
- assert(Values.size() == VT->getNumElements());
- R = APValue(Values.data(), Values.size());
- return true;
+ PrimType ElemT = FieldDesc->getPrimType();
+ SmallVector<APValue> Values;
+ Values.reserve(VT->getNumElements());
+ for (unsigned I = 0; I != VT->getNumElements(); ++I) {
+ TYPE_SWITCH(ElemT,
+ { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
}
- // Constant Matrix types.
- if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
- if (!FieldDesc->isPrimitiveArray())
- return false;
- PrimType ElemT = FieldDesc->getPrimType();
- unsigned NumElems = MT->getNumElementsFlattened();
-
- SmallVector<APValue> Values;
- Values.reserve(NumElems);
- for (unsigned I = 0; I != NumElems; ++I) {
- TYPE_SWITCH(ElemT,
- { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
- }
+ assert(Values.size() == VT->getNumElements());
+ R = APValue(Values.data(), Values.size());
+ return true;
+ }
- R = APValue(Values.data(), MT->getNumRows(), MT->getNumColumns());
- return true;
+ // Constant Matrix types.
+ if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
+ if (!FieldDesc->isPrimitiveArray())
+ return false;
+ PrimType ElemT = FieldDesc->getPrimType();
+ unsigned NumElems = MT->getNumElementsFlattened();
+
+ SmallVector<APValue> Values;
+ Values.reserve(NumElems);
+ for (unsigned I = 0; I != NumElems; ++I) {
+ TYPE_SWITCH(ElemT,
+ { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
}
- llvm_unreachable("invalid value to return");
- };
+ R = APValue(Values.data(), MT->getNumRows(), MT->getNumColumns());
+ return true;
+ }
+
+ llvm_unreachable("invalid value to return");
+}
+
+std::optional<APValue> Pointer::toRValue(const Context &Ctx,
+ QualType ResultType) const {
+ const ASTContext &ASTCtx = Ctx.getASTContext();
+ assert(!ResultType.isNull());
// Can't return functions as rvalues.
if (ResultType->isFunctionType())
@@ -1165,6 +1164,9 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
if (isZero() || isIntegralPointer())
return toAPValue(ASTCtx);
+ if (!isBlockPointer())
+ return std::nullopt;
+
// Just load primitive types.
if (OptPrimType T = Ctx.classify(ResultType)) {
if (!canDeref(*T))
@@ -1172,12 +1174,9 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
TYPE_SWITCH(*T, return this->load<T>().toAPValue(ASTCtx));
}
- if (!isBlockPointer())
- return std::nullopt;
-
// Return the composite type.
APValue Result;
- if (!Composite(ResultType, view(), Result))
+ if (!::toRValue(Ctx, ResultType, view(), Result))
return std::nullopt;
return Result;
}
More information about the cfe-commits
mailing list