diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index d8362ee3176a0..5b097d6f062b7 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -2127,19 +2127,28 @@ bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) { if (Ptr.isUnknownSizeArray()) return false; + const Descriptor *Desc = Ptr.getFieldDesc(); // In the unlikely event that we're initializing the first item of // a non-array, skip the atIndex(). - if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) { + if (Idx == 0 && !Desc->isArray()) { Ptr.initialize(); new (&Ptr.deref()) T(Value); return true; } - const Pointer &ElemPtr = Ptr.atIndex(Idx); - if (!CheckInit(S, OpPC, ElemPtr)) + if (!CheckLive(S, OpPC, Ptr, AK_Assign)) return false; - ElemPtr.initialize(); - new (&ElemPtr.deref()) T(Value); + if (Idx >= Desc->getNumElems()) { + // CheckRange. + if (S.getLangOpts().CPlusPlus) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_access_past_end) + << AK_Assign << S.Current->getRange(OpPC); + } + return false; + } + Ptr.initializeElement(Idx); + new (&Ptr.elem(Idx)) T(Value); return true; } @@ -2148,22 +2157,32 @@ template ::T> bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) { const T &Value = S.Stk.pop(); const Pointer &Ptr = S.Stk.pop(); + if (Ptr.isUnknownSizeArray()) return false; + const Descriptor *Desc = Ptr.getFieldDesc(); // In the unlikely event that we're initializing the first item of // a non-array, skip the atIndex(). - if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) { + if (Idx == 0 && !Desc->isArray()) { Ptr.initialize(); new (&Ptr.deref()) T(Value); return true; } - const Pointer &ElemPtr = Ptr.atIndex(Idx); - if (!CheckInit(S, OpPC, ElemPtr)) + if (!CheckLive(S, OpPC, Ptr, AK_Assign)) return false; - ElemPtr.initialize(); - new (&ElemPtr.deref()) T(Value); + if (Idx >= Desc->getNumElems()) { + // CheckRange. + if (S.getLangOpts().CPlusPlus) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_access_past_end) + << AK_Assign << S.Current->getRange(OpPC); + } + return false; + } + Ptr.initializeElement(Idx); + new (&Ptr.elem(Idx)) T(Value); return true; } diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index ef75b0ded4f1f..81d4ce14f9310 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -433,7 +433,8 @@ bool Pointer::isInitialized() const { if (!isBlockPointer()) return true; - if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) { + if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) && + Offset == BS.Base) { const GlobalInlineDescriptor &GD = *reinterpret_cast(block()->rawData()); return GD.InitState == GlobalInitState::Initialized; @@ -461,7 +462,8 @@ bool Pointer::isElementInitialized(unsigned Index) const { if (isStatic() && BS.Base == 0) return true; - if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) { + if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) && + Offset == BS.Base) { const GlobalInlineDescriptor &GD = *reinterpret_cast(block()->rawData()); return GD.InitState == GlobalInitState::Initialized; @@ -486,7 +488,8 @@ void Pointer::initialize() const { assert(BS.Pointee && "Cannot initialize null pointer"); - if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) { + if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) && + Offset == BS.Base) { GlobalInlineDescriptor &GD = *reinterpret_cast( asBlockPointer().Pointee->rawData()); GD.InitState = GlobalInitState::Initialized; @@ -496,35 +499,39 @@ void Pointer::initialize() const { const Descriptor *Desc = getFieldDesc(); assert(Desc); if (Desc->isPrimitiveArray()) { - // Primitive global arrays don't have an initmap. - if (isStatic() && BS.Base == 0) - return; + if (Desc->getNumElems() != 0) + initializeElement(getIndex()); + return; + } - // Nothing to do for these. - if (Desc->getNumElems() == 0) - return; + // Field has its bit in an inline descriptor. + assert(BS.Base != 0 && "Only composite fields can be initialised"); + getInlineDesc()->IsInitialized = true; +} - InitMapPtr &IM = getInitMap(); - if (!IM) - IM = - std::make_pair(false, std::make_shared(Desc->getNumElems())); +void Pointer::initializeElement(unsigned Index) const { + // Primitive global arrays don't have an initmap. + if (isStatic() && BS.Base == 0) + return; - assert(IM); + assert(Index < getFieldDesc()->getNumElems()); - // All initialized. - if (IM->first) - return; + InitMapPtr &IM = getInitMap(); + if (!IM) { + const Descriptor *Desc = getFieldDesc(); + IM = std::make_pair(false, std::make_shared(Desc->getNumElems())); + } - if (IM->second->initializeElement(getIndex())) { - IM->first = true; - IM->second.reset(); - } + assert(IM); + + // All initialized. + if (IM->first) return; - } - // Field has its bit in an inline descriptor. - assert(BS.Base != 0 && "Only composite fields can be initialised"); - getInlineDesc()->IsInitialized = true; + if (IM->second->initializeElement(Index)) { + IM->first = true; + IM->second.reset(); + } } void Pointer::initializeAllElements() const { @@ -547,7 +554,8 @@ bool Pointer::allElementsInitialized() const { if (isStatic() && BS.Base == 0) return true; - if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) { + if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) && + Offset == BS.Base) { const GlobalInlineDescriptor &GD = *reinterpret_cast(block()->rawData()); return GD.InitState == GlobalInitState::Initialized; diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 9e67374c3354f..bbf20801ce923 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -702,6 +702,8 @@ class Pointer { /// Initializes a field. void initialize() const; + /// Initialized the given element of a primitive array. + void initializeElement(unsigned Index) const; /// Initialize all elements of a primitive array at once. This can be /// used in situations where we *know* we have initialized *all* elements /// of a primtive array.