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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits