diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index ae5e2dadac951b..2d8ab4e40809a5 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -3301,9 +3301,6 @@ bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) { // Retry. return this->VisitDeclRefExpr(E); } - - if (VD->hasExternalStorage()) - return this->emitInvalidDeclRef(E, E); } } else { if (const auto *VD = dyn_cast(D); diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index dff8eed12428ec..a4ccc0236d292c 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -301,10 +301,19 @@ Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, assert(Source && "Missing source"); } -Descriptor::Descriptor(const DeclTy &D, MetadataSize MD) - : Source(D), ElemSize(1), Size(ElemSize), MDSize(MD.value_or(0)), - AllocSize(Size + MDSize), ElemRecord(nullptr), IsConst(true), - IsMutable(false), IsTemporary(false), IsDummy(true) { +/// Dummy. +Descriptor::Descriptor(const DeclTy &D) + : Source(D), ElemSize(1), Size(1), MDSize(0), AllocSize(MDSize), + ElemRecord(nullptr), IsConst(true), IsMutable(false), IsTemporary(false), + IsDummy(true) { + assert(Source && "Missing source"); +} + +/// Dummy array. +Descriptor::Descriptor(const DeclTy &D, UnknownSize) + : Source(D), ElemSize(1), Size(UnknownSizeMark), MDSize(0), + AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false), + IsTemporary(false), IsArray(true), IsDummy(true) { assert(Source && "Missing source"); } diff --git a/clang/lib/AST/Interp/Descriptor.h b/clang/lib/AST/Interp/Descriptor.h index 5160f07466fba7..4e257361ad146b 100644 --- a/clang/lib/AST/Interp/Descriptor.h +++ b/clang/lib/AST/Interp/Descriptor.h @@ -156,7 +156,11 @@ struct Descriptor final { Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, bool IsConst, bool IsTemporary, bool IsMutable); - Descriptor(const DeclTy &D, MetadataSize MD); + /// Allocates a dummy descriptor. + Descriptor(const DeclTy &D); + + /// Allocates a dummy array descriptor. + Descriptor(const DeclTy &D, UnknownSize); QualType getType() const; QualType getElemQualType() const; diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 507d91129d6886..336cf2a1103395 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1946,8 +1946,15 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) { const T &Offset = S.Stk.pop(); const Pointer &Ptr = S.Stk.peek(); - if (Ptr.isDummy()) - return true; + if (!Ptr.isZero()) { + if (!CheckArray(S, OpPC, Ptr)) + return false; + + if (Ptr.isDummy()) { + S.Stk.push(Ptr); + return true; + } + } if (!OffsetHelper(S, OpPC, Offset, Ptr)) return false; @@ -1960,9 +1967,14 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) { const T &Offset = S.Stk.pop(); const Pointer &Ptr = S.Stk.pop(); - if (Ptr.isDummy()) { - S.Stk.push(Ptr); - return true; + if (!Ptr.isZero()) { + if (!CheckArray(S, OpPC, Ptr)) + return false; + + if (Ptr.isDummy()) { + S.Stk.push(Ptr); + return true; + } } if (!OffsetHelper(S, OpPC, Offset, Ptr)) diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 34ecdb967960d5..fffb4aba492fc8 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -285,6 +285,11 @@ class Pointer { bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); } /// Checks if the structure is an array of unknown size. bool isUnknownSizeArray() const { + // If this points inside a dummy block, return true. + // FIXME: This might change in the future. If it does, we need + // to set the proper Ctor/Dtor functions for dummy Descriptors. + if (Base != 0 && Base != sizeof(InlineDescriptor) && isDummy()) + return true; return getFieldDesc()->isUnknownSizeArray(); } /// Checks if the pointer points to an array. diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index 58bddb991fd6de..da6f72c62115dd 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -149,7 +149,16 @@ std::optional Program::getOrCreateDummy(const ValueDecl *VD) { return It->second; // Create dummy descriptor. - Descriptor *Desc = allocateDescriptor(VD, std::nullopt); + // We create desriptors of 'array of unknown size' if the type is an array + // type _and_ the size isn't known (it's not a ConstantArrayType). If the size + // is known however, we create a regular dummy pointer. + Descriptor *Desc; + if (const auto *AT = VD->getType()->getAsArrayTypeUnsafe(); + AT && !isa(AT)) + Desc = allocateDescriptor(VD, Descriptor::UnknownSize{}); + else + Desc = allocateDescriptor(VD); + // Allocate a block for storage. unsigned I = Globals.size(); diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp index 4b112d7fdddfdb..2443992f75fb7d 100644 --- a/clang/test/AST/Interp/arrays.cpp +++ b/clang/test/AST/Interp/arrays.cpp @@ -429,18 +429,13 @@ namespace Incomplete { // both-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}} + extern int arr[]; constexpr int *c = &arr[1]; // both-error {{must be initialized by a constant expression}} \ - // ref-note {{indexing of array without known bound}} \ - // expected-note {{read of non-constexpr variable 'arr'}} + // both-note {{indexing of array without known bound}} constexpr int *d = &arr[1]; // both-error {{must be initialized by a constant expression}} \ - // ref-note {{indexing of array without known bound}} \ - // expected-note {{read of non-constexpr variable 'arr'}} + // both-note {{indexing of array without known bound}} constexpr int *e = arr + 1; // both-error {{must be initialized by a constant expression}} \ - // ref-note {{indexing of array without known bound}} \ - // expected-note {{read of non-constexpr variable 'arr'}} + // both-note {{indexing of array without known bound}} } namespace GH69115 { diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 7ae8499b1156dd..2b1001dbd3baee 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1113,6 +1113,9 @@ namespace InvalidDeclRefs { int b03 = 3; // both-note {{declared here}} static_assert(b03, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of non-const variable}} + + extern int var; + constexpr int *varp = &var; // Ok. } namespace NonConstReads { @@ -1182,8 +1185,11 @@ namespace incdecbool { } #if __cplusplus >= 201402L +/// NOTE: The diagnostics of the two interpreters are a little +/// different here, but they both make sense. constexpr int externvar1() { // both-error {{never produces a constant expression}} - extern char arr[]; // both-note {{declared here}} - return arr[0]; // both-note {{read of non-constexpr variable 'arr'}} + extern char arr[]; // ref-note {{declared here}} + return arr[0]; // ref-note {{read of non-constexpr variable 'arr'}} \ + // expected-note {{indexing of array without known bound}} } #endif