[clang] [clang][bytecode] Support ImplicitValueInitExpr for multi-dim arrays (PR #117312)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 22 02:18:22 PST 2024
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/117312
The attached test case from https://github.com/llvm/llvm-project/issues/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.
>From a1c94470dc152ecfe005bbc08e3b0641e9b957a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 22 Nov 2024 11:12:46 +0100
Subject: [PATCH] [clang][bytecode] Support ImplicitValueInitExpr for multi-dim
arrays
The attached test case from https://github.com/llvm/llvm-project/issues/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.
---
clang/lib/AST/ByteCode/Compiler.cpp | 79 +++++++++++++++--------
clang/lib/AST/ByteCode/Compiler.h | 1 +
clang/lib/AST/ByteCode/InterpFrame.cpp | 7 +-
clang/test/AST/ByteCode/placement-new.cpp | 16 ++++-
4 files changed, 73 insertions(+), 30 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 7cf2519d6a71fb..eb619e65a7bfce 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -1642,22 +1642,8 @@ bool Compiler<Emitter>::VisitImplicitValueInitExpr(
if (QT->isIncompleteArrayType())
return true;
- if (QT->isArrayType()) {
- const ArrayType *AT = QT->getAsArrayTypeUnsafe();
- assert(AT);
- const auto *CAT = cast<ConstantArrayType>(AT);
- size_t NumElems = CAT->getZExtSize();
- PrimType ElemT = classifyPrim(CAT->getElementType());
-
- for (size_t I = 0; I != NumElems; ++I) {
- if (!this->visitZeroInitializer(ElemT, CAT->getElementType(), E))
- return false;
- if (!this->emitInitElem(ElemT, I, E))
- return false;
- }
-
- return true;
- }
+ if (QT->isArrayType())
+ return this->visitZeroArrayInitializer(QT, E);
if (const auto *ComplexTy = E->getType()->getAs<ComplexType>()) {
assert(Initializing);
@@ -3916,18 +3902,9 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
return false;
}
} else if (D->isCompositeArray()) {
- const Record *ElemRecord = D->ElemDesc->ElemRecord;
- assert(D->ElemDesc->ElemRecord);
- for (uint32_t I = 0, N = D->getNumElems(); I != N; ++I) {
- if (!this->emitConstUint32(I, E))
- return false;
- if (!this->emitArrayElemPtr(PT_Uint32, E))
- return false;
- if (!this->visitZeroRecordInitializer(ElemRecord, E))
- return false;
- if (!this->emitPopPtr(E))
- return false;
- }
+ // Can't be a vector or complex field.
+ if (!this->visitZeroArrayInitializer(D->getType(), E))
+ return false;
} else if (D->isRecord()) {
if (!this->visitZeroRecordInitializer(D->ElemRecord, E))
return false;
@@ -3958,6 +3935,52 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
return true;
}
+template <class Emitter>
+bool Compiler<Emitter>::visitZeroArrayInitializer(QualType T, const Expr *E) {
+ assert(T->isArrayType() || T->isAnyComplexType() || T->isVectorType());
+ const ArrayType *AT = T->getAsArrayTypeUnsafe();
+ QualType ElemType = AT->getElementType();
+ size_t NumElems = cast<ConstantArrayType>(AT)->getZExtSize();
+
+ if (std::optional<PrimType> ElemT = classify(ElemType)) {
+ for (size_t I = 0; I != NumElems; ++I) {
+ if (!this->visitZeroInitializer(*ElemT, ElemType, E))
+ return false;
+ if (!this->emitInitElem(*ElemT, I, E))
+ return false;
+ }
+ return true;
+ } else if (ElemType->isRecordType()) {
+ const Record *R = getRecord(ElemType);
+
+ for (size_t I = 0; I != NumElems; ++I) {
+ if (!this->emitConstUint32(I, E))
+ return false;
+ if (!this->emitArrayElemPtr(PT_Uint32, E))
+ return false;
+ if (!this->visitZeroRecordInitializer(R, E))
+ return false;
+ if (!this->emitPopPtr(E))
+ return false;
+ }
+ return true;
+ } else if (ElemType->isArrayType()) {
+ for (size_t I = 0; I != NumElems; ++I) {
+ if (!this->emitConstUint32(I, E))
+ return false;
+ if (!this->emitArrayElemPtr(PT_Uint32, E))
+ return false;
+ if (!this->visitZeroArrayInitializer(ElemType, E))
+ return false;
+ if (!this->emitPopPtr(E))
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
template <class Emitter>
template <typename T>
bool Compiler<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index d1b624daba6b99..2a94f5ec76b6c5 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -325,6 +325,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
/// Emits a zero initializer.
bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
bool visitZeroRecordInitializer(const Record *R, const Expr *E);
+ bool visitZeroArrayInitializer(QualType T, const Expr *E);
/// Emits an APSInt constant.
bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);
diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp
index 7f02464a1c0f14..20f67d9b1fd425 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -234,7 +234,12 @@ SourceInfo InterpFrame::getSource(CodePtr PC) const {
if (Func && !funcHasUsableBody(Func) && Caller)
return Caller->getSource(RetPC);
- return S.getSource(Func, PC);
+ // Similarly, if the resulting source location is invalid anyway,
+ // point to the caller instead.
+ SourceInfo Result = S.getSource(Func, PC);
+ if (Result.getLoc().isInvalid() && Caller)
+ return Caller->getSource(RetPC);
+ return Result;
}
const Expr *InterpFrame::getExpr(CodePtr PC) const {
diff --git a/clang/test/AST/ByteCode/placement-new.cpp b/clang/test/AST/ByteCode/placement-new.cpp
index 56f54ff168f3e8..7a4fc89a27daca 100644
--- a/clang/test/AST/ByteCode/placement-new.cpp
+++ b/clang/test/AST/ByteCode/placement-new.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -fexperimental-new-constant-interpreter -verify=expected,both %s
+// RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -fexperimental-new-constant-interpreter -verify=expected,both %s -DBYTECODE
// RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -verify=ref,both %s
namespace std {
@@ -338,3 +338,17 @@ namespace PR48606 {
}
static_assert(f());
}
+
+#ifdef BYTECODE
+constexpr int N = [] // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{assignment to dereferenced one-past-the-end pointer is not allowed in a constant expression}} \
+ // expected-note {{in call to}}
+{
+ struct S {
+ int a[1];
+ };
+ S s;
+ ::new (s.a) int[1][2][3][4]();
+ return s.a[0];
+}();
+#endif
More information about the cfe-commits
mailing list