Skip to content

Commit e0db416

Browse files
authored
[clang][bytecode] Fix initializing array struct fields from an APValue (#131983)
We need to recurse once more here and move the array case into the bigger if chain.
1 parent 5b6b4fd commit e0db416

File tree

3 files changed

+59
-32
lines changed

3 files changed

+59
-32
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3654,7 +3654,7 @@ bool Compiler<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
36543654

36553655
assert(V.isStruct());
36563656
assert(V.getStructNumBases() == 0);
3657-
if (!this->visitAPValueInitializer(V, E))
3657+
if (!this->visitAPValueInitializer(V, E, E->getType()))
36583658
return false;
36593659

36603660
return this->emitFinishInit(E);
@@ -4641,48 +4641,27 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType,
46414641

46424642
template <class Emitter>
46434643
bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
4644-
const Expr *E) {
4645-
4644+
const Expr *E, QualType T) {
46464645
if (Val.isStruct()) {
4647-
const Record *R = this->getRecord(E->getType());
4646+
const Record *R = this->getRecord(T);
46484647
assert(R);
46494648
for (unsigned I = 0, N = Val.getStructNumFields(); I != N; ++I) {
46504649
const APValue &F = Val.getStructField(I);
46514650
const Record::Field *RF = R->getField(I);
4651+
QualType FieldType = RF->Decl->getType();
46524652

4653-
if (F.isInt() || F.isFloat() || F.isLValue() || F.isMemberPointer()) {
4654-
PrimType T = classifyPrim(RF->Decl->getType());
4655-
if (!this->visitAPValue(F, T, E))
4656-
return false;
4657-
if (!this->emitInitField(T, RF->Offset, E))
4658-
return false;
4659-
} else if (F.isArray()) {
4660-
assert(RF->Desc->isPrimitiveArray());
4661-
const auto *ArrType = RF->Decl->getType()->getAsArrayTypeUnsafe();
4662-
PrimType ElemT = classifyPrim(ArrType->getElementType());
4663-
assert(ArrType);
4664-
4665-
if (!this->emitGetPtrField(RF->Offset, E))
4653+
if (std::optional<PrimType> PT = classify(FieldType)) {
4654+
if (!this->visitAPValue(F, *PT, E))
46664655
return false;
4667-
4668-
for (unsigned A = 0, AN = F.getArraySize(); A != AN; ++A) {
4669-
if (!this->visitAPValue(F.getArrayInitializedElt(A), ElemT, E))
4670-
return false;
4671-
if (!this->emitInitElem(ElemT, A, E))
4672-
return false;
4673-
}
4674-
4675-
if (!this->emitPopPtr(E))
4656+
if (!this->emitInitField(*PT, RF->Offset, E))
46764657
return false;
4677-
} else if (F.isStruct() || F.isUnion()) {
4658+
} else {
46784659
if (!this->emitGetPtrField(RF->Offset, E))
46794660
return false;
4680-
if (!this->visitAPValueInitializer(F, E))
4661+
if (!this->visitAPValueInitializer(F, E, FieldType))
46814662
return false;
46824663
if (!this->emitPopPtr(E))
46834664
return false;
4684-
} else {
4685-
assert(false && "I don't think this should be possible");
46864665
}
46874666
}
46884667
return true;
@@ -4696,6 +4675,28 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
46964675
if (!this->visitAPValue(F, T, E))
46974676
return false;
46984677
return this->emitInitField(T, RF->Offset, E);
4678+
} else if (Val.isArray()) {
4679+
const auto *ArrType = T->getAsArrayTypeUnsafe();
4680+
QualType ElemType = ArrType->getElementType();
4681+
for (unsigned A = 0, AN = Val.getArraySize(); A != AN; ++A) {
4682+
const APValue &Elem = Val.getArrayInitializedElt(A);
4683+
if (std::optional<PrimType> ElemT = classify(ElemType)) {
4684+
if (!this->visitAPValue(Elem, *ElemT, E))
4685+
return false;
4686+
if (!this->emitInitElem(*ElemT, A, E))
4687+
return false;
4688+
} else {
4689+
if (!this->emitConstUint32(A, E))
4690+
return false;
4691+
if (!this->emitArrayElemPtrUint32(E))
4692+
return false;
4693+
if (!this->visitAPValueInitializer(Elem, E, ElemType))
4694+
return false;
4695+
if (!this->emitPopPtr(E))
4696+
return false;
4697+
}
4698+
}
4699+
return true;
46994700
}
47004701
// TODO: Other types.
47014702

@@ -6385,7 +6386,8 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
63856386
return false;
63866387
return this->emitInitGlobal(*T, *Index, E);
63876388
}
6388-
return this->visitAPValueInitializer(TPOD->getValue(), E);
6389+
return this->visitAPValueInitializer(TPOD->getValue(), E,
6390+
TPOD->getType());
63896391
}
63906392
return false;
63916393
}

clang/lib/AST/ByteCode/Compiler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
290290
VarCreationState visitDecl(const VarDecl *VD);
291291
/// Visit an APValue.
292292
bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
293-
bool visitAPValueInitializer(const APValue &Val, const Expr *E);
293+
bool visitAPValueInitializer(const APValue &Val, const Expr *E, QualType T);
294294
/// Visit the given decl as if we have a reference to it.
295295
bool visitDeclRef(const ValueDecl *D, const Expr *E);
296296

clang/test/AST/ByteCode/cxx20.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,3 +964,28 @@ namespace PseudoDtor {
964964
static_assert(f3() == 0);
965965
#endif
966966
}
967+
968+
namespace NastyChar {
969+
struct nasty_char {
970+
template <typename T> friend auto operator<=>(T, T) = delete;
971+
template <typename T> friend void operator+(T &&) = delete;
972+
template <typename T> friend void operator-(T &&) = delete;
973+
template <typename T> friend void operator&(T &&) = delete;
974+
975+
char c;
976+
};
977+
978+
979+
template <unsigned N> struct ToNastyChar {
980+
constexpr ToNastyChar(const char (&r)[N]) {
981+
for (unsigned I = 0; I != N; ++I)
982+
text[I] = nasty_char{r[I]};
983+
}
984+
nasty_char text[N];
985+
};
986+
987+
template <unsigned N> ToNastyChar(const char (&)[N]) -> ToNastyChar<N>;
988+
989+
template <ToNastyChar t> constexpr auto to_nasty_char() { return t; }
990+
constexpr auto result = to_nasty_char<"12345">();
991+
}

0 commit comments

Comments
 (0)