diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 1b33c69b93aa4..1e508f8998abe 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -168,7 +168,16 @@ bool ByteCodeExprGen::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::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 f8942291b3b16..9bc42057c5f57 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 c87bb2fa6b02f..4a4c0922758c9 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(FieldType->getAsArrayTypeUnsafe()); diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 2132e8b0a8cfa..86cc267652951 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(); const Pointer &Ptr = S.Stk.peek(); + if (!CheckArray(S, OpPC, Ptr)) + return false; + if (!OffsetHelper(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(); + + if (!Ptr.isUnknownSizeArray()) + return true; + + const SourceInfo &E = S.Current->getSource(OpPC); + S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array); + + return false; +} + template ::T> inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) { const T &Offset = S.Stk.pop(); const Pointer &Ptr = S.Stk.pop(); + if (!CheckArray(S, OpPC, Ptr)) + return false; + if (!OffsetHelper(S, OpPC, Offset, Ptr)) return false; diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index e1e7e5e2efbb0..69068e87d5720 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 7110785ea4c66..d1673094c2660 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'}} +}