[clang] [clang][Interp] Handle unknown-size arrays better (PR #68868)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 26 04:08:13 PDT 2023
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/68868
>From 85f045fc4a84ef308bd7e2ca3e51889b37e48333 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Thu, 12 Oct 2023 11:50:16 +0200
Subject: [PATCH] [clang][Interp] Handle unknown-size arrays better
We unfortunately actually need to do some checks for array-to-pointer
decays it seems.
---
clang/lib/AST/Interp/ByteCodeExprGen.cpp | 14 +++++++-
clang/lib/AST/Interp/EvalEmitter.cpp | 6 ++++
clang/lib/AST/Interp/Interp.cpp | 2 ++
clang/lib/AST/Interp/Interp.h | 20 +++++++++++
clang/lib/AST/Interp/Opcodes.td | 2 ++
clang/test/AST/Interp/arrays.cpp | 42 ++++++++++++++++++++++++
6 files changed, 85 insertions(+), 1 deletion(-)
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 1b33c69b93aa4b9..1e508f8998abefb 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -168,7 +168,16 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitCastPointerIntegral(T, CE);
}
- case CK_ArrayToPointerDecay:
+ case CK_ArrayToPointerDecay: {
+ if (!this->visit(SubExpr))
+ return false;
+ if (!this->emitArrayDecay(CE))
+ return false;
+ if (DiscardResult)
+ return this->emitPopPtr(CE);
+ return true;
+ }
+
case CK_AtomicToNonAtomic:
case CK_ConstructorConversion:
case CK_FunctionToPointerDecay:
@@ -505,6 +514,9 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni
if (QT->isRecordType())
return false;
+ if (QT->isIncompleteArrayType())
+ return true;
+
if (QT->isArrayType()) {
const ArrayType *AT = QT->getAsArrayTypeUnsafe();
assert(AT);
diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index f8942291b3b162d..9bc42057c5f5782 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -185,6 +185,12 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
}
return Ok;
}
+
+ if (Ty->isIncompleteArrayType()) {
+ R = APValue(APValue::UninitArray(), 0, 0);
+ return true;
+ }
+
if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
const size_t NumElems = Ptr.getNumElems();
QualType ElemTy = AT->getElementType();
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index c87bb2fa6b02f16..4a4c0922758c915 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -483,6 +483,8 @@ static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
if (FieldType->isRecordType()) {
Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord());
+ } else if (FieldType->isIncompleteArrayType()) {
+ // Nothing to do here.
} else if (FieldType->isArrayType()) {
const auto *CAT =
cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 2132e8b0a8cfa29..86cc26765295118 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1802,17 +1802,37 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.peek<Pointer>();
+ if (!CheckArray(S, OpPC, Ptr))
+ return false;
+
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
return false;
return NarrowPtr(S, OpPC);
}
+/// Just takes a pointer and checks if its' an incomplete
+/// array type.
+inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+
+ if (!Ptr.isUnknownSizeArray())
+ return true;
+
+ const SourceInfo &E = S.Current->getSource(OpPC);
+ S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
+
+ return false;
+}
+
template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckArray(S, OpPC, Ptr))
+ return false;
+
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
return false;
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index e1e7e5e2efbb059..69068e87d5720ab 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -687,3 +687,5 @@ def InvalidCast : Opcode {
def InvalidDeclRef : Opcode {
let Args = [ArgDeclRef];
}
+
+def ArrayDecay : Opcode;
diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp
index 7110785ea4c662a..d1673094c26606a 100644
--- a/clang/test/AST/Interp/arrays.cpp
+++ b/clang/test/AST/Interp/arrays.cpp
@@ -455,3 +455,45 @@ namespace NoInitMapLeak {
// ref-error {{not an integral constant expression}} \
// ref-note {{in call to}}
}
+
+namespace Incomplete {
+ struct Foo {
+ char c;
+ int a[];
+ };
+
+ constexpr Foo F{};
+ constexpr const int *A = F.a; // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{array-to-pointer decay of array member without known bound}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{array-to-pointer decay of array member without known bound}}
+
+ constexpr const int *B = F.a + 1; // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{array-to-pointer decay of array member without known bound}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{array-to-pointer decay of array member without known bound}}
+
+ constexpr int C = *F.a; // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{array-to-pointer decay of array member without known bound}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{array-to-pointer decay of array member without known bound}}
+
+
+
+ /// These are from test/SemaCXX/constant-expression-cxx11.cpp
+ /// and are the only tests using the 'indexing of array without known bound' diagnostic.
+ /// We currently diagnose them differently.
+ extern int arr[]; // expected-note 3{{declared here}}
+ constexpr int *c = &arr[1]; // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{indexing of array without known bound}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{read of non-constexpr variable 'arr'}}
+ constexpr int *d = &arr[1]; // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{indexing of array without known bound}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{read of non-constexpr variable 'arr'}}
+ constexpr int *e = arr + 1; // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{indexing of array without known bound}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{read of non-constexpr variable 'arr'}}
+}
More information about the cfe-commits
mailing list