[clang] [clang][bytecode] Don't add an LValuePath to APValues with invalid bases (PR #226096)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 24 03:03:21 PDT 2026
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/226096
If the APValue is created for an opaque pointer, check first if the base is valid. If not, we're not supposed to provide an LValuePath at all.
>From c037847fa56760b3daa58dc37c97bbae80c2711c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Thu, 24 Sep 2026 09:19:58 +0200
Subject: [PATCH] asdf
---
clang/lib/AST/ByteCode/Compiler.cpp | 62 +++++++++++----------
clang/lib/AST/ByteCode/Pointer.cpp | 46 ++++++++++-----
clang/lib/AST/ByteCode/Pointer.h | 1 +
clang/test/CodeGenCXX/mangle-class-nttp.cpp | 3 +
4 files changed, 67 insertions(+), 45 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 16f2a768fe06c..81c8fb0b9f17d 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5922,7 +5922,6 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType,
return this->emitNull(ValType, 0, nullptr, Info);
APValue::LValueBase Base = Val.getLValueBase();
- ArrayRef<APValue::LValuePathEntry> Path = Val.getLValuePath();
if (const Expr *BaseExpr = Base.dyn_cast<const Expr *>())
return this->visit(BaseExpr);
@@ -5931,40 +5930,43 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType,
return false;
QualType EntryType = VD->getType();
- for (auto &Entry : Path) {
- if (EntryType->isArrayType()) {
- uint64_t Index = Entry.getAsArrayIndex();
- QualType ElemType =
- EntryType->getAsArrayTypeUnsafe()->getElementType();
- if (!this->emitConst(Index, PT_Uint64, Info))
- return false;
- if (!this->emitArrayElemPtrPop(PT_Uint64, Info))
- return false;
- EntryType = ElemType;
- } else {
- assert(EntryType->isRecordType());
- const Record *EntryRecord = getRecord(EntryType);
- if (!EntryRecord)
- return false;
-
- const Decl *BaseOrMember = Entry.getAsBaseOrMember().getPointer();
- if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
- unsigned EntryOffset = EntryRecord->getField(FD)->Offset;
- if (!this->emitGetPtrFieldPop(EntryOffset, Info))
+ if (Val.hasLValuePath()) {
+ ArrayRef<APValue::LValuePathEntry> Path = Val.getLValuePath();
+ for (auto &Entry : Path) {
+ if (EntryType->isArrayType()) {
+ uint64_t Index = Entry.getAsArrayIndex();
+ QualType ElemType =
+ EntryType->getAsArrayTypeUnsafe()->getElementType();
+ if (!this->emitConst(Index, PT_Uint64, Info))
+ return false;
+ if (!this->emitArrayElemPtrPop(PT_Uint64, Info))
return false;
- EntryType = FD->getType();
+ EntryType = ElemType;
} else {
- const auto *Base = cast<CXXRecordDecl>(BaseOrMember);
- if (const Record::Base *B = EntryRecord->getBaseOrNull(Base)) {
- if (!this->emitGetPtrBasePop(B->Offset, /*NullOK=*/false, Info))
+ assert(EntryType->isRecordType());
+ const Record *EntryRecord = getRecord(EntryType);
+ if (!EntryRecord)
+ return false;
+
+ const Decl *BaseOrMember = Entry.getAsBaseOrMember().getPointer();
+ if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
+ unsigned EntryOffset = EntryRecord->getField(FD)->Offset;
+ if (!this->emitGetPtrFieldPop(EntryOffset, Info))
return false;
+ EntryType = FD->getType();
} else {
- // Must be a virtual base.
- assert(EntryRecord->findVirtualBase(Base));
- if (!this->emitGetPtrVirtBasePop(Base, Info))
- return false;
+ const auto *Base = cast<CXXRecordDecl>(BaseOrMember);
+ if (const Record::Base *B = EntryRecord->getBaseOrNull(Base)) {
+ if (!this->emitGetPtrBasePop(B->Offset, /*NullOK=*/false, Info))
+ return false;
+ } else {
+ // Must be a virtual base.
+ assert(EntryRecord->findVirtualBase(Base));
+ if (!this->emitGetPtrVirtBasePop(Base, Info))
+ return false;
+ }
+ EntryType = Ctx.getASTContext().getCanonicalTagType(Base);
}
- EntryType = Ctx.getASTContext().getCanonicalTagType(Base);
}
}
}
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index bf9900cdab21f..552cdf1bf8ec7 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -289,7 +289,24 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
CharUnits::fromQuantity(Offset * elemSize()), Path,
/*OnePastTheEnd=*/false, /*IsNull=*/false);
case Storage::Opaque: {
- if (!Opaque.Base.getType()->isPointerType()) {
+ bool ValidBase = Opaque.hasValidBase() || this->Offset <= 1;
+
+ size_t LayoutOffset = Opaque.computeLayoutOffset(ASTCtx).value_or(0);
+ size_t ElemSize = 0;
+ if (validType(Opaque.getFieldType()))
+ ElemSize = ASTCtx.getTypeSizeInChars(Opaque.getFieldType()).getQuantity();
+
+ auto LValueOffset =
+ CharUnits::fromQuantity(LayoutOffset + (this->Offset * ElemSize));
+ APValue::LValueBase Base;
+ if (const Expr *E = Opaque.Base.asExpr())
+ Base = E;
+ else
+ Base = Opaque.Base.asValueDecl();
+
+ // For valid bases, assemble the LValuePath.
+ APValue Result;
+ if (ValidBase) {
for (const PointerPathEntry &Entry : Opaque.path()) {
switch (Entry.Kind) {
case PointerPathEntry::Field:
@@ -307,21 +324,13 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
break;
}
}
- }
- size_t LayoutOffset = Opaque.computeLayoutOffset(ASTCtx).value_or(0);
- size_t ElemSize = 0;
- if (validType(Opaque.getFieldType()))
- ElemSize = ASTCtx.getTypeSizeInChars(Opaque.getFieldType()).getQuantity();
- auto Offset =
- CharUnits::fromQuantity(LayoutOffset + (this->Offset * ElemSize));
- APValue::LValueBase Base;
- if (const Expr *E = Opaque.Base.asExpr())
- Base = E;
- else
- Base = Opaque.Base.asValueDecl();
- APValue Result =
- APValue(Base, Offset, Path, Opaque.isOnePastEnd(), /*IsNullPtr=*/false);
+ Result = APValue(Base, LValueOffset, Path, Opaque.isOnePastEnd(),
+ /*IsNullPtr=*/false);
+
+ } else {
+ Result = APValue(Base, LValueOffset, APValue::NoLValuePath{});
+ }
Result.setConstexprUnknown(Opaque.isConstexprUnknown());
return Result;
}
@@ -1575,3 +1584,10 @@ bool OpaquePointer::isOnePastEndOrElementPastEnd() const {
return false;
}
+
+bool OpaquePointer::hasValidBase() const {
+ if (const VarDecl *VD = Base.asVarDecl())
+ return !VD->hasExternalStorage();
+
+ return !Base.getType()->isPointerType();
+}
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 35a0645ff34c6..207ec06a32a34 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -447,6 +447,7 @@ struct OpaquePointer {
bool hasDeclBase() const { return Base.isDecl(); }
const VarDecl *getBaseDecl() const { return Base.asVarDecl(); }
const Expr *getBaseExpr() const { return Base.asExpr(); }
+ bool hasValidBase() const;
OpaquePointer
withFieldType(const Type *FieldTy,
diff --git a/clang/test/CodeGenCXX/mangle-class-nttp.cpp b/clang/test/CodeGenCXX/mangle-class-nttp.cpp
index 536592c6a9308..f818679d8bca8 100644
--- a/clang/test/CodeGenCXX/mangle-class-nttp.cpp
+++ b/clang/test/CodeGenCXX/mangle-class-nttp.cpp
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-windows -emit-llvm -o - | FileCheck %s --check-prefix=MSABI
+// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexperimental-new-constant-interpreter | FileCheck %s
+// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-windows -emit-llvm -o - -fexperimental-new-constant-interpreter | FileCheck %s --check-prefix=MSABI
+
#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
More information about the cfe-commits
mailing list