Skip to content

Commit ceaf6e9

Browse files
authored
[clang][bytecode] Support ImplicitValueInitExpr for multi-dim arrays (#117312)
The attached test case from #117294 used to cause an assertion because we called classifPrim() on an array type. The new result doesn't crash but isn't exactly perfect either. Since the problem arises when evaluating an ImplicitValueInitExpr, we have no proper source location to point to. Point to the caller instead.
1 parent e477989 commit ceaf6e9

File tree

4 files changed

+73
-30
lines changed

4 files changed

+73
-30
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,22 +1642,8 @@ bool Compiler<Emitter>::VisitImplicitValueInitExpr(
16421642
if (QT->isIncompleteArrayType())
16431643
return true;
16441644

1645-
if (QT->isArrayType()) {
1646-
const ArrayType *AT = QT->getAsArrayTypeUnsafe();
1647-
assert(AT);
1648-
const auto *CAT = cast<ConstantArrayType>(AT);
1649-
size_t NumElems = CAT->getZExtSize();
1650-
PrimType ElemT = classifyPrim(CAT->getElementType());
1651-
1652-
for (size_t I = 0; I != NumElems; ++I) {
1653-
if (!this->visitZeroInitializer(ElemT, CAT->getElementType(), E))
1654-
return false;
1655-
if (!this->emitInitElem(ElemT, I, E))
1656-
return false;
1657-
}
1658-
1659-
return true;
1660-
}
1645+
if (QT->isArrayType())
1646+
return this->visitZeroArrayInitializer(QT, E);
16611647

16621648
if (const auto *ComplexTy = E->getType()->getAs<ComplexType>()) {
16631649
assert(Initializing);
@@ -3916,18 +3902,9 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
39163902
return false;
39173903
}
39183904
} else if (D->isCompositeArray()) {
3919-
const Record *ElemRecord = D->ElemDesc->ElemRecord;
3920-
assert(D->ElemDesc->ElemRecord);
3921-
for (uint32_t I = 0, N = D->getNumElems(); I != N; ++I) {
3922-
if (!this->emitConstUint32(I, E))
3923-
return false;
3924-
if (!this->emitArrayElemPtr(PT_Uint32, E))
3925-
return false;
3926-
if (!this->visitZeroRecordInitializer(ElemRecord, E))
3927-
return false;
3928-
if (!this->emitPopPtr(E))
3929-
return false;
3930-
}
3905+
// Can't be a vector or complex field.
3906+
if (!this->visitZeroArrayInitializer(D->getType(), E))
3907+
return false;
39313908
} else if (D->isRecord()) {
39323909
if (!this->visitZeroRecordInitializer(D->ElemRecord, E))
39333910
return false;
@@ -3958,6 +3935,52 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
39583935
return true;
39593936
}
39603937

3938+
template <class Emitter>
3939+
bool Compiler<Emitter>::visitZeroArrayInitializer(QualType T, const Expr *E) {
3940+
assert(T->isArrayType() || T->isAnyComplexType() || T->isVectorType());
3941+
const ArrayType *AT = T->getAsArrayTypeUnsafe();
3942+
QualType ElemType = AT->getElementType();
3943+
size_t NumElems = cast<ConstantArrayType>(AT)->getZExtSize();
3944+
3945+
if (std::optional<PrimType> ElemT = classify(ElemType)) {
3946+
for (size_t I = 0; I != NumElems; ++I) {
3947+
if (!this->visitZeroInitializer(*ElemT, ElemType, E))
3948+
return false;
3949+
if (!this->emitInitElem(*ElemT, I, E))
3950+
return false;
3951+
}
3952+
return true;
3953+
} else if (ElemType->isRecordType()) {
3954+
const Record *R = getRecord(ElemType);
3955+
3956+
for (size_t I = 0; I != NumElems; ++I) {
3957+
if (!this->emitConstUint32(I, E))
3958+
return false;
3959+
if (!this->emitArrayElemPtr(PT_Uint32, E))
3960+
return false;
3961+
if (!this->visitZeroRecordInitializer(R, E))
3962+
return false;
3963+
if (!this->emitPopPtr(E))
3964+
return false;
3965+
}
3966+
return true;
3967+
} else if (ElemType->isArrayType()) {
3968+
for (size_t I = 0; I != NumElems; ++I) {
3969+
if (!this->emitConstUint32(I, E))
3970+
return false;
3971+
if (!this->emitArrayElemPtr(PT_Uint32, E))
3972+
return false;
3973+
if (!this->visitZeroArrayInitializer(ElemType, E))
3974+
return false;
3975+
if (!this->emitPopPtr(E))
3976+
return false;
3977+
}
3978+
return true;
3979+
}
3980+
3981+
return false;
3982+
}
3983+
39613984
template <class Emitter>
39623985
template <typename T>
39633986
bool Compiler<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {

clang/lib/AST/ByteCode/Compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
325325
/// Emits a zero initializer.
326326
bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
327327
bool visitZeroRecordInitializer(const Record *R, const Expr *E);
328+
bool visitZeroArrayInitializer(QualType T, const Expr *E);
328329

329330
/// Emits an APSInt constant.
330331
bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);

clang/lib/AST/ByteCode/InterpFrame.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,12 @@ SourceInfo InterpFrame::getSource(CodePtr PC) const {
234234
if (Func && !funcHasUsableBody(Func) && Caller)
235235
return Caller->getSource(RetPC);
236236

237-
return S.getSource(Func, PC);
237+
// Similarly, if the resulting source location is invalid anyway,
238+
// point to the caller instead.
239+
SourceInfo Result = S.getSource(Func, PC);
240+
if (Result.getLoc().isInvalid() && Caller)
241+
return Caller->getSource(RetPC);
242+
return Result;
238243
}
239244

240245
const Expr *InterpFrame::getExpr(CodePtr PC) const {

clang/test/AST/ByteCode/placement-new.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -fexperimental-new-constant-interpreter -verify=expected,both %s
1+
// RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -fexperimental-new-constant-interpreter -verify=expected,both %s -DBYTECODE
22
// RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -verify=ref,both %s
33

44
namespace std {
@@ -338,3 +338,17 @@ namespace PR48606 {
338338
}
339339
static_assert(f());
340340
}
341+
342+
#ifdef BYTECODE
343+
constexpr int N = [] // expected-error {{must be initialized by a constant expression}} \
344+
// expected-note {{assignment to dereferenced one-past-the-end pointer is not allowed in a constant expression}} \
345+
// expected-note {{in call to}}
346+
{
347+
struct S {
348+
int a[1];
349+
};
350+
S s;
351+
::new (s.a) int[1][2][3][4]();
352+
return s.a[0];
353+
}();
354+
#endif

0 commit comments

Comments
 (0)