[clang] ad71e87 - [clang][bytecode] Don't add an LValuePath to APValues with invalid bases (#226096)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 24 05:28:57 PDT 2026
Author: Timm Baeder
Date: 2026-09-24T14:28:50+02:00
New Revision: ad71e8769e21715555f0e8fb0094f3d2d00557dd
URL: https://github.com/llvm/llvm-project/commit/ad71e8769e21715555f0e8fb0094f3d2d00557dd
DIFF: https://github.com/llvm/llvm-project/commit/ad71e8769e21715555f0e8fb0094f3d2d00557dd.diff
LOG: [clang][bytecode] Don't add an LValuePath to APValues with invalid bases (#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.
Added:
Modified:
clang/lib/AST/ByteCode/Compiler.cpp
clang/lib/AST/ByteCode/Pointer.cpp
clang/lib/AST/ByteCode/Pointer.h
clang/test/CodeGenCXX/mangle-class-nttp.cpp
Removed:
################################################################################
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