[clang] [clang][Interp] Handle unknown-size arrays better (PR #68868)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 12 02:53:15 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
We unfortunately actually need to do some checks for array-to-pointer decays it seems.
---
Full diff: https://github.com/llvm/llvm-project/pull/68868.diff
6 Files Affected:
- (modified) clang/lib/AST/Interp/ByteCodeExprGen.cpp (+13-1)
- (modified) clang/lib/AST/Interp/EvalEmitter.cpp (+6)
- (modified) clang/lib/AST/Interp/Interp.cpp (+2)
- (modified) clang/lib/AST/Interp/Interp.h (+20)
- (modified) clang/lib/AST/Interp/Opcodes.td (+2)
- (modified) clang/test/AST/Interp/arrays.cpp (+45)
``````````diff
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 2b745d6a1509868..da4e4a58207cfce 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -162,7 +162,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:
@@ -499,6 +508,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 f46ef1067cf52a0..466327e2c7c7b86 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -177,6 +177,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 a4d6844ebe61722..41edbfe0da3f381 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -454,6 +454,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 1ad3b8bfc7711d3..bf285e2701814ca 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1797,17 +1797,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 9d390fed152417f..29c83e7ba9efc64 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -674,3 +674,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 281835f828bbd7c..919e3407d3afa05 100644
--- a/clang/test/AST/Interp/arrays.cpp
+++ b/clang/test/AST/Interp/arrays.cpp
@@ -390,3 +390,48 @@ namespace StringZeroFill {
static_assert(b[4] == '\0', "");
static_assert(b[5] == '\0', "");
}
+
+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'}}
+
+
+
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/68868
More information about the cfe-commits
mailing list