[clang] [clang][bytecode] Fix initialing array struct fields from an APValue (PR #131983)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 19 00:56:46 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
We need to recurse once more here and move the array case into the bigger if chain.
---
Full diff: https://github.com/llvm/llvm-project/pull/131983.diff
3 Files Affected:
- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+33-31)
- (modified) clang/lib/AST/ByteCode/Compiler.h (+1-1)
- (modified) clang/test/AST/ByteCode/cxx20.cpp (+25)
``````````diff
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 3524ab5f86de8..6c846c01fc848 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3650,7 +3650,7 @@ bool Compiler<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
assert(V.isStruct());
assert(V.getStructNumBases() == 0);
- if (!this->visitAPValueInitializer(V, E))
+ if (!this->visitAPValueInitializer(V, E, E->getType()))
return false;
return this->emitFinishInit(E);
@@ -4637,48 +4637,27 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType,
template <class Emitter>
bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
- const Expr *E) {
-
+ const Expr *E, QualType T) {
if (Val.isStruct()) {
- const Record *R = this->getRecord(E->getType());
+ const Record *R = this->getRecord(T);
assert(R);
for (unsigned I = 0, N = Val.getStructNumFields(); I != N; ++I) {
const APValue &F = Val.getStructField(I);
const Record::Field *RF = R->getField(I);
+ QualType FieldType = RF->Decl->getType();
- if (F.isInt() || F.isFloat() || F.isLValue() || F.isMemberPointer()) {
- PrimType T = classifyPrim(RF->Decl->getType());
- if (!this->visitAPValue(F, T, E))
- return false;
- if (!this->emitInitField(T, RF->Offset, E))
- return false;
- } else if (F.isArray()) {
- assert(RF->Desc->isPrimitiveArray());
- const auto *ArrType = RF->Decl->getType()->getAsArrayTypeUnsafe();
- PrimType ElemT = classifyPrim(ArrType->getElementType());
- assert(ArrType);
-
- if (!this->emitGetPtrField(RF->Offset, E))
+ if (std::optional<PrimType> PT = classify(FieldType)) {
+ if (!this->visitAPValue(F, *PT, E))
return false;
-
- for (unsigned A = 0, AN = F.getArraySize(); A != AN; ++A) {
- if (!this->visitAPValue(F.getArrayInitializedElt(A), ElemT, E))
- return false;
- if (!this->emitInitElem(ElemT, A, E))
- return false;
- }
-
- if (!this->emitPopPtr(E))
+ if (!this->emitInitField(*PT, RF->Offset, E))
return false;
- } else if (F.isStruct() || F.isUnion()) {
+ } else {
if (!this->emitGetPtrField(RF->Offset, E))
return false;
- if (!this->visitAPValueInitializer(F, E))
+ if (!this->visitAPValueInitializer(F, E, FieldType))
return false;
if (!this->emitPopPtr(E))
return false;
- } else {
- assert(false && "I don't think this should be possible");
}
}
return true;
@@ -4692,6 +4671,28 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
if (!this->visitAPValue(F, T, E))
return false;
return this->emitInitField(T, RF->Offset, E);
+ } else if (Val.isArray()) {
+ const auto *ArrType = T->getAsArrayTypeUnsafe();
+ QualType ElemType = ArrType->getElementType();
+ for (unsigned A = 0, AN = Val.getArraySize(); A != AN; ++A) {
+ const APValue &Elem = Val.getArrayInitializedElt(A);
+ if (std::optional<PrimType> ElemT = classify(ElemType)) {
+ if (!this->visitAPValue(Elem, *ElemT, E))
+ return false;
+ if (!this->emitInitElem(*ElemT, A, E))
+ return false;
+ } else {
+ if (!this->emitConstUint32(A, E))
+ return false;
+ if (!this->emitArrayElemPtrUint32(E))
+ return false;
+ if (!this->visitAPValueInitializer(Elem, E, ElemType))
+ return false;
+ if (!this->emitPopPtr(E))
+ return false;
+ }
+ }
+ return true;
}
// TODO: Other types.
@@ -6374,7 +6375,8 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
return false;
return this->emitInitGlobal(*T, *Index, E);
}
- return this->visitAPValueInitializer(TPOD->getValue(), E);
+ return this->visitAPValueInitializer(TPOD->getValue(), E,
+ TPOD->getType());
}
return false;
}
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 902da8ffdd330..256e917728886 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -290,7 +290,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
VarCreationState visitDecl(const VarDecl *VD);
/// Visit an APValue.
bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
- bool visitAPValueInitializer(const APValue &Val, const Expr *E);
+ bool visitAPValueInitializer(const APValue &Val, const Expr *E, QualType T);
/// Visit the given decl as if we have a reference to it.
bool visitDeclRef(const ValueDecl *D, const Expr *E);
diff --git a/clang/test/AST/ByteCode/cxx20.cpp b/clang/test/AST/ByteCode/cxx20.cpp
index 06501de64916a..42e6ae33e92e4 100644
--- a/clang/test/AST/ByteCode/cxx20.cpp
+++ b/clang/test/AST/ByteCode/cxx20.cpp
@@ -964,3 +964,28 @@ namespace PseudoDtor {
static_assert(f3() == 0);
#endif
}
+
+namespace NastyChar {
+ struct nasty_char {
+ template <typename T> friend auto operator<=>(T, T) = delete;
+ template <typename T> friend void operator+(T &&) = delete;
+ template <typename T> friend void operator-(T &&) = delete;
+ template <typename T> friend void operator&(T &&) = delete;
+
+ char c;
+ };
+
+
+ template <unsigned N> struct ToNastyChar {
+ constexpr ToNastyChar(const char (&r)[N]) {
+ for (unsigned I = 0; I != N; ++I)
+ text[I] = nasty_char{r[I]};
+ }
+ nasty_char text[N];
+ };
+
+ template <unsigned N> ToNastyChar(const char (&)[N]) -> ToNastyChar<N>;
+
+ template <ToNastyChar t> constexpr auto to_nasty_char() { return t; }
+ constexpr auto result = to_nasty_char<"12345">();
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/131983
More information about the cfe-commits
mailing list