Author: Timm Baeder
Date: 2025-12-06T06:37:45+01:00
New Revision: 8fe38c4c9c71c7a86ecdba476ee5bae4c02c0dfe

URL: 
https://github.com/llvm/llvm-project/commit/8fe38c4c9c71c7a86ecdba476ee5bae4c02c0dfe
DIFF: 
https://github.com/llvm/llvm-project/commit/8fe38c4c9c71c7a86ecdba476ee5bae4c02c0dfe.diff

LOG: [clang][bytecode] Allocate InitMaps via Program/InterpState allocators 
(#170272)

Save them as a pointer intead of using a shared_ptr. This we we can use
the pointer integer value to differentiate the "no initmap yet" and "all
values initialzed" cases.

This regresses one test case in const-eval.c, but as it turns out, that
only worked coincidentally before.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Descriptor.cpp
    clang/lib/AST/ByteCode/Descriptor.h
    clang/lib/AST/ByteCode/Disasm.cpp
    clang/lib/AST/ByteCode/EvaluationResult.cpp
    clang/lib/AST/ByteCode/Interp.cpp
    clang/lib/AST/ByteCode/Interp.h
    clang/lib/AST/ByteCode/InterpBuiltin.cpp
    clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
    clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
    clang/lib/AST/ByteCode/Pointer.cpp
    clang/lib/AST/ByteCode/Pointer.h
    clang/test/AST/ByteCode/const-eval.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Descriptor.cpp 
b/clang/lib/AST/ByteCode/Descriptor.cpp
index 0a819599287ee..9ed7c088dbb12 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -52,10 +52,8 @@ static void dtorTy(Block *, std::byte *Ptr, const Descriptor 
*) {
 template <typename T>
 static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
                         const Descriptor *D) {
-  new (Ptr) InitMapPtr(std::nullopt);
-
   if constexpr (needsCtor<T>()) {
-    Ptr += sizeof(InitMapPtr);
+    Ptr += sizeof(InitMap *);
     for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
       new (&reinterpret_cast<T *>(Ptr)[I]) T();
     }
@@ -64,13 +62,8 @@ static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, 
bool, bool, bool,
 
 template <typename T>
 static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
-  InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);
-
-  if (IMP)
-    IMP = std::nullopt;
-
   if constexpr (needsCtor<T>()) {
-    Ptr += sizeof(InitMapPtr);
+    Ptr += sizeof(InitMap *);
     for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
       reinterpret_cast<T *>(Ptr)[I].~T();
     }
@@ -239,12 +232,6 @@ static bool needsRecordDtor(const Record *R) {
 
 static BlockCtorFn getCtorPrim(PrimType T) {
   switch (T) {
-  case PT_Float:
-    return ctorTy<PrimConv<PT_Float>::T>;
-  case PT_IntAP:
-    return ctorTy<PrimConv<PT_IntAP>::T>;
-  case PT_IntAPS:
-    return ctorTy<PrimConv<PT_IntAPS>::T>;
   case PT_Ptr:
     return ctorTy<PrimConv<PT_Ptr>::T>;
   case PT_MemberPtr:
@@ -257,12 +244,6 @@ static BlockCtorFn getCtorPrim(PrimType T) {
 
 static BlockDtorFn getDtorPrim(PrimType T) {
   switch (T) {
-  case PT_Float:
-    return dtorTy<PrimConv<PT_Float>::T>;
-  case PT_IntAP:
-    return dtorTy<PrimConv<PT_IntAP>::T>;
-  case PT_IntAPS:
-    return dtorTy<PrimConv<PT_IntAPS>::T>;
   case PT_Ptr:
     return dtorTy<PrimConv<PT_Ptr>::T>;
   case PT_MemberPtr:
@@ -273,14 +254,16 @@ static BlockDtorFn getDtorPrim(PrimType T) {
   llvm_unreachable("Unhandled PrimType");
 }
 
-static BlockCtorFn getCtorArrayPrim(PrimType Type) {
-  TYPE_SWITCH(Type, return ctorArrayTy<T>);
-  llvm_unreachable("unknown Expr");
-}
-
-static BlockDtorFn getDtorArrayPrim(PrimType Type) {
-  TYPE_SWITCH(Type, return dtorArrayTy<T>);
-  llvm_unreachable("unknown Expr");
+static BlockDtorFn getDtorArrayPrim(PrimType T) {
+  switch (T) {
+  case PT_Ptr:
+    return dtorArrayTy<PrimConv<PT_Ptr>::T>;
+  case PT_MemberPtr:
+    return dtorArrayTy<PrimConv<PT_MemberPtr>::T>;
+  default:
+    return nullptr;
+  }
+  llvm_unreachable("Unhandled PrimType");
 }
 
 /// Primitives.
@@ -302,10 +285,9 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, 
MetadataSize MD,
                        bool IsMutable)
     : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
       MDSize(MD.value_or(0)),
-      AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type),
+      AllocSize(align(MDSize) + align(Size) + sizeof(InitMap *)), PrimT(Type),
       IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
-      IsArray(true), CtorFn(getCtorArrayPrim(Type)),
-      DtorFn(getDtorArrayPrim(Type)) {
+      IsArray(true), DtorFn(getDtorArrayPrim(Type)) {
   assert(Source && "Missing source");
   assert(NumElems <= (MaxArrayElemBytes / ElemSize));
 }
@@ -315,10 +297,9 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, 
MetadataSize MD,
                        bool IsTemporary, bool IsConst, UnknownSize)
     : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
       MDSize(MD.value_or(0)),
-      AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), PrimT(Type),
+      AllocSize(MDSize + sizeof(InitMap *) + alignof(void *)), PrimT(Type),
       IsConst(IsConst), IsMutable(false), IsTemporary(IsTemporary),
-      IsArray(true), CtorFn(getCtorArrayPrim(Type)),
-      DtorFn(getDtorArrayPrim(Type)) {
+      IsArray(true), DtorFn(getDtorArrayPrim(Type)) {
   assert(Source && "Missing source");
 }
 
@@ -468,15 +449,16 @@ bool Descriptor::hasTrivialDtor() const {
 
 bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); 
}
 
-InitMap::InitMap(unsigned N)
-    : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {}
+InitMap::InitMap(unsigned N) : UninitFields(N) {
+  std::memset(data(), 0, numFields(N) * sizeof(T));
+}
 
 bool InitMap::initializeElement(unsigned I) {
   unsigned Bucket = I / PER_FIELD;
   T Mask = T(1) << (I % PER_FIELD);
   if (!(data()[Bucket] & Mask)) {
     data()[Bucket] |= Mask;
-    UninitFields -= 1;
+    --UninitFields;
   }
   return UninitFields == 0;
 }

diff  --git a/clang/lib/AST/ByteCode/Descriptor.h 
b/clang/lib/AST/ByteCode/Descriptor.h
index 90dc2b4aa3111..2807f92335dc2 100644
--- a/clang/lib/AST/ByteCode/Descriptor.h
+++ b/clang/lib/AST/ByteCode/Descriptor.h
@@ -16,6 +16,7 @@
 #include "PrimType.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
+#include <limits>
 
 namespace clang {
 namespace interp {
@@ -27,7 +28,6 @@ struct Descriptor;
 enum PrimType : uint8_t;
 
 using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
-using InitMapPtr = std::optional<std::pair<bool, std::shared_ptr<InitMap>>>;
 
 /// Invoked whenever a block is created. The constructor method fills in the
 /// inline descriptors of all fields and array elements. It also initializes
@@ -146,7 +146,7 @@ struct Descriptor final {
 
   /// Maximum number of bytes to be used for array elements.
   static constexpr unsigned MaxArrayElemBytes =
-      std::numeric_limits<decltype(AllocSize)>::max() - sizeof(InitMapPtr) -
+      std::numeric_limits<decltype(AllocSize)>::max() - sizeof(InitMap *) -
       align(std::max(*InlineDescMD, *GlobalMD));
 
   /// Pointer to the record, if block contains records.
@@ -278,7 +278,7 @@ struct Descriptor final {
 };
 
 /// Bitfield tracking the initialisation status of elements of primitive 
arrays.
-struct InitMap final {
+struct alignas(alignof(uint64_t)) InitMap final {
 private:
   /// Type packing bits.
   using T = uint64_t;
@@ -289,12 +289,33 @@ struct InitMap final {
   /// Initializes the map with no fields set.
   explicit InitMap(unsigned N);
 
+  /// Checks if all elements have been initialized.
+  static bool allInitialized(const InitMap *IM) {
+    return reinterpret_cast<uintptr_t>(IM) ==
+           std::numeric_limits<uintptr_t>::max();
+  }
+
+  /// Marks all elements as initialized.
+  static void markAllInitialized(InitMap *&IMPtr) {
+    std::memset(&IMPtr, 
static_cast<int>(std::numeric_limits<uintptr_t>::max()),
+                sizeof(void *));
+  }
+
+  /// Returns the number of bytes needed to allocate the InitMap for
+  /// \param N elements.
+  static unsigned allocBytes(unsigned N) {
+    return align(sizeof(InitMap)) + (numFields(N) * sizeof(T));
+  }
+
 private:
   friend class Pointer;
 
   /// Returns a pointer to storage.
-  T *data() { return Data.get(); }
-  const T *data() const { return Data.get(); }
+  T *data() {
+    return reinterpret_cast<T *>(reinterpret_cast<std::byte *>(this) +
+                                 align(sizeof(InitMap)));
+  }
+  const T *data() const { return const_cast<InitMap *>(this)->data(); }
 
   /// Initializes an element. Returns true when object if fully initialized.
   bool initializeElement(unsigned I);
@@ -307,7 +328,6 @@ struct InitMap final {
   }
   /// Number of fields not initialized.
   unsigned UninitFields;
-  std::unique_ptr<T[]> Data;
 };
 
 } // namespace interp

diff  --git a/clang/lib/AST/ByteCode/Disasm.cpp 
b/clang/lib/AST/ByteCode/Disasm.cpp
index 35937e3483e38..473442b3ded21 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -455,7 +455,7 @@ LLVM_DUMP_METHOD void Descriptor::dumpFull(unsigned Offset,
     OS.indent(Spaces) << "Elements: " << getNumElems() << '\n';
     OS.indent(Spaces) << "Element type: " << primTypeToString(getPrimType())
                       << '\n';
-    unsigned FO = Offset + sizeof(InitMapPtr);
+    unsigned FO = Offset + sizeof(InitMap *);
     for (unsigned I = 0; I != getNumElems(); ++I) {
       OS.indent(Spaces) << "Element " << I << " offset: " << FO << '\n';
       FO += getElemSize();

diff  --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp 
b/clang/lib/AST/ByteCode/EvaluationResult.cpp
index 7c3c21cf28251..59e78e8c9138f 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.cpp
+++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp
@@ -54,12 +54,11 @@ static bool CheckArrayInitialized(InterpState &S, 
SourceLocation Loc,
   } else {
     // Primitive arrays.
     if (S.getContext().canClassify(ElemType)) {
-      if (BasePtr.allElementsInitialized()) {
+      if (BasePtr.allElementsInitialized())
         return true;
-      } else {
-        DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
-        return false;
-      }
+
+      DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
+      return false;
     }
 
     for (size_t I = 0; I != NumElems; ++I) {

diff  --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index 80ef656dc6285..08cdc25c6e132 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -2318,7 +2318,7 @@ bool FinishInitGlobal(InterpState &S, CodePtr OpPC) {
 
   finishGlobalRecurse(S, Ptr);
   if (Ptr.canBeInitialized()) {
-    Ptr.initialize();
+    Ptr.initialize(S);
     Ptr.activate();
   }
 

diff  --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index d8b8b209fa927..2b17ecb38cf42 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -418,7 +418,7 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) {
       return false;
     if (T::add(A, B, Bits, &Result.elem<T>(1)))
       return false;
-    Result.initialize();
+    Result.initialize(S);
     Result.initializeAllElements();
   }
 
@@ -1390,7 +1390,7 @@ bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
   const Pointer &Field = Obj.atField(I);
   if (!CheckStore(S, OpPC, Field))
     return false;
-  Field.initialize();
+  Field.initialize(S);
   Field.deref<T>() = Value;
   return true;
 }
@@ -1492,7 +1492,7 @@ bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) 
{
     }
   }
 
-  P.initialize();
+  P.initialize(S);
   return true;
 }
 
@@ -1512,7 +1512,7 @@ bool InitGlobalTemp(InterpState &S, CodePtr OpPC, 
uint32_t I,
       std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));
 
   Ptr.deref<T>() = S.Stk.pop<T>();
-  Ptr.initialize();
+  Ptr.initialize(S);
   return true;
 }
 
@@ -1541,7 +1541,7 @@ bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t 
I) {
   const Pointer &Field = This.atField(I);
   assert(Field.canBeInitialized());
   Field.deref<T>() = S.Stk.pop<T>();
-  Field.initialize();
+  Field.initialize(S);
   return true;
 }
 
@@ -1556,7 +1556,7 @@ bool InitThisFieldActivate(InterpState &S, CodePtr OpPC, 
uint32_t I) {
   assert(Field.canBeInitialized());
   Field.deref<T>() = S.Stk.pop<T>();
   Field.activate();
-  Field.initialize();
+  Field.initialize(S);
   return true;
 }
 
@@ -1575,7 +1575,7 @@ bool InitThisBitField(InterpState &S, CodePtr OpPC, const 
Record::Field *F,
   assert(Field.canBeInitialized());
   const auto &Value = S.Stk.pop<T>();
   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
-  Field.initialize();
+  Field.initialize(S);
   return true;
 }
 
@@ -1592,7 +1592,7 @@ bool InitThisBitFieldActivate(InterpState &S, CodePtr 
OpPC,
   assert(Field.canBeInitialized());
   const auto &Value = S.Stk.pop<T>();
   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
-  Field.initialize();
+  Field.initialize(S);
   Field.activate();
   return true;
 }
@@ -1611,7 +1611,7 @@ bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
 
   const Pointer &Field = Ptr.atField(I);
   Field.deref<T>() = Value;
-  Field.initialize();
+  Field.initialize(S);
   return true;
 }
 
@@ -1627,7 +1627,7 @@ bool InitFieldActivate(InterpState &S, CodePtr OpPC, 
uint32_t I) {
   const Pointer &Field = Ptr.atField(I);
   Field.deref<T>() = Value;
   Field.activate();
-  Field.initialize();
+  Field.initialize(S);
   return true;
 }
 
@@ -1658,7 +1658,7 @@ bool InitBitField(InterpState &S, CodePtr OpPC, const 
Record::Field *F) {
   } else {
     Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
   }
-  Field.initialize();
+  Field.initialize(S);
   return true;
 }
 
@@ -1691,7 +1691,7 @@ bool InitBitFieldActivate(InterpState &S, CodePtr OpPC,
     Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
   }
   Field.activate();
-  Field.initialize();
+  Field.initialize(S);
   return true;
 }
 
@@ -1828,21 +1828,21 @@ inline bool GetPtrThisBase(InterpState &S, CodePtr 
OpPC, uint32_t Off) {
 inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (Ptr.canBeInitialized())
-    Ptr.initialize();
+    Ptr.initialize(S);
   return true;
 }
 
 inline bool FinishInit(InterpState &S, CodePtr OpPC) {
   const Pointer &Ptr = S.Stk.peek<Pointer>();
   if (Ptr.canBeInitialized())
-    Ptr.initialize();
+    Ptr.initialize(S);
   return true;
 }
 
 inline bool FinishInitActivate(InterpState &S, CodePtr OpPC) {
   const Pointer &Ptr = S.Stk.peek<Pointer>();
   if (Ptr.canBeInitialized()) {
-    Ptr.initialize();
+    Ptr.initialize(S);
     Ptr.activate();
   }
   return true;
@@ -1851,7 +1851,7 @@ inline bool FinishInitActivate(InterpState &S, CodePtr 
OpPC) {
 inline bool FinishInitActivatePop(InterpState &S, CodePtr OpPC) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (Ptr.canBeInitialized()) {
-    Ptr.initialize();
+    Ptr.initialize(S);
     Ptr.activate();
   }
   return true;
@@ -1944,7 +1944,7 @@ bool Store(InterpState &S, CodePtr OpPC) {
   if (!CheckStore(S, OpPC, Ptr))
     return false;
   if (Ptr.canBeInitialized())
-    Ptr.initialize();
+    Ptr.initialize(S);
   Ptr.deref<T>() = Value;
   return true;
 }
@@ -1956,7 +1956,7 @@ bool StorePop(InterpState &S, CodePtr OpPC) {
   if (!CheckStore(S, OpPC, Ptr))
     return false;
   if (Ptr.canBeInitialized())
-    Ptr.initialize();
+    Ptr.initialize(S);
   Ptr.deref<T>() = Value;
   return true;
 }
@@ -1988,7 +1988,7 @@ bool StoreActivate(InterpState &S, CodePtr OpPC) {
   if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))
     return false;
   if (Ptr.canBeInitialized()) {
-    Ptr.initialize();
+    Ptr.initialize(S);
     Ptr.activate();
   }
   Ptr.deref<T>() = Value;
@@ -2003,7 +2003,7 @@ bool StoreActivatePop(InterpState &S, CodePtr OpPC) {
   if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))
     return false;
   if (Ptr.canBeInitialized()) {
-    Ptr.initialize();
+    Ptr.initialize(S);
     Ptr.activate();
   }
   Ptr.deref<T>() = Value;
@@ -2018,7 +2018,7 @@ bool StoreBitField(InterpState &S, CodePtr OpPC) {
   if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))
     return false;
   if (Ptr.canBeInitialized())
-    Ptr.initialize();
+    Ptr.initialize(S);
   if (const auto *FD = Ptr.getField())
     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
   else
@@ -2033,7 +2033,7 @@ bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
   if (!CheckStore(S, OpPC, Ptr))
     return false;
   if (Ptr.canBeInitialized())
-    Ptr.initialize();
+    Ptr.initialize(S);
   if (const auto *FD = Ptr.getField())
     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
   else
@@ -2049,7 +2049,7 @@ bool StoreBitFieldActivate(InterpState &S, CodePtr OpPC) {
   if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))
     return false;
   if (Ptr.canBeInitialized()) {
-    Ptr.initialize();
+    Ptr.initialize(S);
     Ptr.activate();
   }
   if (const auto *FD = Ptr.getField())
@@ -2067,7 +2067,7 @@ bool StoreBitFieldActivatePop(InterpState &S, CodePtr 
OpPC) {
   if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/true))
     return false;
   if (Ptr.canBeInitialized()) {
-    Ptr.initialize();
+    Ptr.initialize(S);
     Ptr.activate();
   }
   if (const auto *FD = Ptr.getField())
@@ -2083,7 +2083,7 @@ bool Init(InterpState &S, CodePtr OpPC) {
   const Pointer &Ptr = S.Stk.peek<Pointer>();
   if (!CheckInit(S, OpPC, Ptr))
     return false;
-  Ptr.initialize();
+  Ptr.initialize(S);
   new (&Ptr.deref<T>()) T(Value);
   return true;
 }
@@ -2094,7 +2094,7 @@ bool InitPop(InterpState &S, CodePtr OpPC) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckInit(S, OpPC, Ptr))
     return false;
-  Ptr.initialize();
+  Ptr.initialize(S);
   new (&Ptr.deref<T>()) T(Value);
   return true;
 }
@@ -2114,7 +2114,7 @@ bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) 
{
   // In the unlikely event that we're initializing the first item of
   // a non-array, skip the atIndex().
   if (Idx == 0 && !Desc->isArray()) {
-    Ptr.initialize();
+    Ptr.initialize(S);
     new (&Ptr.deref<T>()) T(Value);
     return true;
   }
@@ -2130,7 +2130,7 @@ bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) 
{
     }
     return false;
   }
-  Ptr.initializeElement(Idx);
+  Ptr.initializeElement(S, Idx);
   new (&Ptr.elem<T>(Idx)) T(Value);
   return true;
 }
@@ -2148,7 +2148,7 @@ bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t 
Idx) {
   // In the unlikely event that we're initializing the first item of
   // a non-array, skip the atIndex().
   if (Idx == 0 && !Desc->isArray()) {
-    Ptr.initialize();
+    Ptr.initialize(S);
     new (&Ptr.deref<T>()) T(Value);
     return true;
   }
@@ -2164,7 +2164,7 @@ bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t 
Idx) {
     }
     return false;
   }
-  Ptr.initializeElement(Idx);
+  Ptr.initializeElement(S, Idx);
   new (&Ptr.elem<T>(Idx)) T(Value);
   return true;
 }
@@ -3174,7 +3174,7 @@ inline bool CopyArray(InterpState &S, CodePtr OpPC, 
uint32_t SrcIndex,
       return false;
 
     DestPtr.elem<T>(DestIndex + I) = SrcPtr.elem<T>(SrcIndex + I);
-    DestPtr.initializeElement(DestIndex + I);
+    DestPtr.initializeElement(S, DestIndex + I);
   }
   return true;
 }

diff  --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp 
b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 4a789fe3a6af4..17fac525ff1d8 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -877,7 +877,7 @@ static bool interp__builtin_overflowop(InterpState &S, 
CodePtr OpPC,
   // Write Result to ResultPtr and put Overflow on the stack.
   assignInteger(S, ResultPtr, ResultT, Result);
   if (ResultPtr.canBeInitialized())
-    ResultPtr.initialize();
+    ResultPtr.initialize(S);
 
   assert(Call->getDirectCallee()->getReturnType()->isBooleanType());
   S.Stk.push<Boolean>(Overflow);
@@ -934,7 +934,7 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr 
OpPC,
   QualType CarryOutType = Call->getArg(3)->getType()->getPointeeType();
   PrimType CarryOutT = *S.getContext().classify(CarryOutType);
   assignInteger(S, CarryOutPtr, CarryOutT, CarryOut);
-  CarryOutPtr.initialize();
+  CarryOutPtr.initialize(S);
 
   assert(Call->getType() == Call->getArg(0)->getType());
   pushInteger(S, Result, Call->getType());
@@ -1743,7 +1743,7 @@ static bool 
interp__builtin_elementwise_countzeroes(InterpState &S,
       } else {
         Dst.atIndex(I).deref<T>() = T::from(EltVal.countLeadingZeros());
       }
-      Dst.atIndex(I).initialize();
+      Dst.atIndex(I).initialize(S);
     });
   }
 
@@ -1960,7 +1960,7 @@ static bool interp__builtin_memcmp(InterpState &S, 
CodePtr OpPC,
   // Now, read both pointers to a buffer and compare those.
   BitcastBuffer BufferA(
       Bits(ASTCtx.getTypeSize(ElemTypeA) * PtrA.getNumElems()));
-  readPointerToBuffer(S.getContext(), PtrA, BufferA, false);
+  readPointerToBuffer(S, S.getContext(), PtrA, BufferA, false);
   // FIXME: The swapping here is UNDOING something we do when reading the
   // data into the buffer.
   if (ASTCtx.getTargetInfo().isBigEndian())
@@ -1968,7 +1968,7 @@ static bool interp__builtin_memcmp(InterpState &S, 
CodePtr OpPC,
 
   BitcastBuffer BufferB(
       Bits(ASTCtx.getTypeSize(ElemTypeB) * PtrB.getNumElems()));
-  readPointerToBuffer(S.getContext(), PtrB, BufferB, false);
+  readPointerToBuffer(S, S.getContext(), PtrB, BufferB, false);
   // FIXME: The swapping here is UNDOING something we do when reading the
   // data into the buffer.
   if (ASTCtx.getTargetInfo().isBigEndian())
@@ -5583,7 +5583,7 @@ bool SetThreeWayComparisonField(InterpState &S, CodePtr 
OpPC,
 
   INT_TYPE_SWITCH(FieldT,
                   FieldPtr.deref<T>() = T::from(IntValue.getSExtValue()));
-  FieldPtr.initialize();
+  FieldPtr.initialize(S);
   return true;
 }
 
@@ -5639,7 +5639,7 @@ static bool copyRecord(InterpState &S, CodePtr OpPC, 
const Pointer &Src,
       TYPE_SWITCH(*FT, {
         DestField.deref<T>() = Src.atField(F.Offset).deref<T>();
         if (Src.atField(F.Offset).isInitialized())
-          DestField.initialize();
+          DestField.initialize(S);
         if (Activate)
           DestField.activate();
       });
@@ -5677,7 +5677,7 @@ static bool copyRecord(InterpState &S, CodePtr OpPC, 
const Pointer &Src,
       return false;
   }
 
-  Dest.initialize();
+  Dest.initialize(S);
   return true;
 }
 
@@ -5698,7 +5698,7 @@ static bool copyComposite(InterpState &S, CodePtr OpPC, 
const Pointer &Src,
       Pointer DestElem = Dest.atIndex(I);
       TYPE_SWITCH(ET, {
         DestElem.deref<T>() = Src.elem<T>(I);
-        DestElem.initialize();
+        DestElem.initialize(S);
       });
     }
     return true;

diff  --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp 
b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
index 4bd9c66fc9974..f959855ca2a54 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
@@ -77,8 +77,8 @@ using DataFunc =
 
 /// We use this to recursively iterate over all fields and elements of a 
pointer
 /// and extract relevant data for a bitcast.
-static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
-                          Bits BitsToRead, DataFunc F) {
+static bool enumerateData(InterpState &S, const Pointer &P, const Context &Ctx,
+                          Bits Offset, Bits BitsToRead, DataFunc F) {
   const Descriptor *FieldDesc = P.getFieldDesc();
   assert(FieldDesc);
 
@@ -114,7 +114,7 @@ static bool enumerateData(const Pointer &P, const Context 
&Ctx, Bits Offset,
     QualType ElemType = FieldDesc->getElemQualType();
     Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType));
     for (unsigned I = P.getIndex(); I != FieldDesc->getNumElems(); ++I) {
-      enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F);
+      enumerateData(S, P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F);
       Offset += ElemSize;
       if (Offset >= BitsToRead)
         break;
@@ -135,18 +135,18 @@ static bool enumerateData(const Pointer &P, const Context 
&Ctx, Bits Offset,
       Pointer Elem = P.atField(Fi.Offset);
       Bits BitOffset =
           Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex()));
-      Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F);
+      Ok = Ok && enumerateData(S, Elem, Ctx, BitOffset, BitsToRead, F);
     }
     for (const Record::Base &B : R->bases()) {
       Pointer Elem = P.atField(B.Offset);
       CharUnits ByteOffset =
           Layout.getBaseClassOffset(cast<CXXRecordDecl>(B.Decl));
       Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset));
-      Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F);
+      Ok = Ok && enumerateData(S, Elem, Ctx, BitOffset, BitsToRead, F);
       // FIXME: We should only (need to) do this when bitcasting OUT of the
       // buffer, not when copying data into it.
       if (Ok)
-        Elem.initialize();
+        Elem.initialize(S);
     }
 
     return Ok;
@@ -155,9 +155,10 @@ static bool enumerateData(const Pointer &P, const Context 
&Ctx, Bits Offset,
   llvm_unreachable("Unhandled data type");
 }
 
-static bool enumeratePointerFields(const Pointer &P, const Context &Ctx,
-                                   Bits BitsToRead, DataFunc F) {
-  return enumerateData(P, Ctx, Bits::zero(), BitsToRead, F);
+static bool enumeratePointerFields(InterpState &S, const Pointer &P,
+                                   const Context &Ctx, Bits BitsToRead,
+                                   DataFunc F) {
+  return enumerateData(S, P, Ctx, Bits::zero(), BitsToRead, F);
 }
 
 //  This function is constexpr if and only if To, From, and the types of
@@ -257,7 +258,7 @@ static bool CheckBitcastType(InterpState &S, CodePtr OpPC, 
QualType T,
   return true;
 }
 
-bool clang::interp::readPointerToBuffer(const Context &Ctx,
+bool clang::interp::readPointerToBuffer(InterpState &S, const Context &Ctx,
                                         const Pointer &FromPtr,
                                         BitcastBuffer &Buffer,
                                         bool ReturnOnUninit) {
@@ -266,7 +267,7 @@ bool clang::interp::readPointerToBuffer(const Context &Ctx,
       ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big;
 
   return enumeratePointerFields(
-      FromPtr, Ctx, Buffer.size(),
+      S, FromPtr, Ctx, Buffer.size(),
       [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth,
           bool PackedBools) -> bool {
         Bits BitWidth = FullBitWidth;
@@ -339,7 +340,7 @@ bool clang::interp::DoBitCast(InterpState &S, CodePtr OpPC, 
const Pointer &Ptr,
   if (!CheckBitcastType(S, OpPC, DataType, /*IsToType=*/false))
     return false;
 
-  bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer,
+  bool Success = readPointerToBuffer(S, S.getContext(), Ptr, Buffer,
                                      /*ReturnOnUninit=*/false);
   HasIndeterminateBits = !Buffer.rangeInitialized(Bits::zero(), BitWidth);
 
@@ -381,14 +382,14 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr 
OpPC,
 
   const ASTContext &ASTCtx = S.getASTContext();
   BitcastBuffer Buffer(Bytes(Size).toBits());
-  readPointerToBuffer(S.getContext(), FromPtr, Buffer,
+  readPointerToBuffer(S, S.getContext(), FromPtr, Buffer,
                       /*ReturnOnUninit=*/false);
 
   // Now read the values out of the buffer again and into ToPtr.
   Endian TargetEndianness =
       ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big;
   bool Success = enumeratePointerFields(
-      ToPtr, S.getContext(), Buffer.size(),
+      S, ToPtr, S.getContext(), Buffer.size(),
       [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth,
           bool PackedBools) -> bool {
         QualType PtrType = P.getType();
@@ -406,7 +407,7 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr 
OpPC,
           Floating R = S.allocFloat(Semantics);
           Floating::bitcastFromMemory(M.get(), Semantics, &R);
           P.deref<Floating>() = R;
-          P.initialize();
+          P.initialize(S);
           return true;
         }
 
@@ -462,7 +463,7 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr 
OpPC,
               P.deref<T>() = T::zero();
           });
         }
-        P.initialize();
+        P.initialize(S);
         return true;
       });
 
@@ -489,7 +490,7 @@ bool clang::interp::DoMemcpy(InterpState &S, CodePtr OpPC,
   assert(DestPtr.isBlockPointer());
 
   llvm::SmallVector<PrimTypeVariant> Values;
-  enumeratePointerFields(SrcPtr, S.getContext(), Size,
+  enumeratePointerFields(S, SrcPtr, S.getContext(), Size,
                          [&](const Pointer &P, PrimType T, Bits BitOffset,
                              Bits FullBitWidth, bool PackedBools) -> bool {
                            TYPE_SWITCH(T, { Values.push_back(P.deref<T>()); });
@@ -497,12 +498,12 @@ bool clang::interp::DoMemcpy(InterpState &S, CodePtr OpPC,
                          });
 
   unsigned ValueIndex = 0;
-  enumeratePointerFields(DestPtr, S.getContext(), Size,
+  enumeratePointerFields(S, DestPtr, S.getContext(), Size,
                          [&](const Pointer &P, PrimType T, Bits BitOffset,
                              Bits FullBitWidth, bool PackedBools) -> bool {
                            TYPE_SWITCH(T, {
                              P.deref<T>() = std::get<T>(Values[ValueIndex]);
-                             P.initialize();
+                             P.initialize(S);
                            });
 
                            ++ValueIndex;

diff  --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h 
b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
index a0191bab693c4..8422ef8d9a2dd 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
+++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
@@ -31,8 +31,9 @@ bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer 
&FromPtr,
                   Pointer &ToPtr);
 bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr,
                   Pointer &ToPtr, size_t Size);
-bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
-                         BitcastBuffer &Buffer, bool ReturnOnUninit);
+bool readPointerToBuffer(InterpState &S, const Context &Ctx,
+                         const Pointer &FromPtr, BitcastBuffer &Buffer,
+                         bool ReturnOnUninit);
 
 bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &SrcPtr,
               const Pointer &DestPtr, Bits Size);

diff  --git a/clang/lib/AST/ByteCode/Pointer.cpp 
b/clang/lib/AST/ByteCode/Pointer.cpp
index 00e74db5655d6..8fa17aed29d9e 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -13,8 +13,10 @@
 #include "Function.h"
 #include "Integral.h"
 #include "InterpBlock.h"
+#include "InterpState.h"
 #include "MemberPointer.h"
 #include "PrimType.h"
+#include "Program.h"
 #include "Record.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
@@ -442,18 +444,25 @@ bool Pointer::isInitialized() const {
   if (!isBlockPointer())
     return true;
 
+  assert(BS.Pointee && "Cannot check if null pointer was initialized");
   if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
       Offset == BS.Base) {
-    const GlobalInlineDescriptor &GD =
+    const auto &GD =
         *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
     return GD.InitState == GlobalInitState::Initialized;
   }
 
-  assert(BS.Pointee && "Cannot check if null pointer was initialized");
   const Descriptor *Desc = getFieldDesc();
   assert(Desc);
-  if (Desc->isPrimitiveArray())
-    return isElementInitialized(getIndex());
+  if (Desc->isPrimitiveArray()) {
+    InitMap *&IM = getInitMap();
+    if (!IM)
+      return false;
+
+    if (InitMap::allInitialized(IM))
+      return true;
+    return IM->isElementInitialized(getIndex());
+  }
 
   if (asBlockPointer().Base == 0)
     return true;
@@ -462,45 +471,37 @@ bool Pointer::isInitialized() const {
 }
 
 bool Pointer::isElementInitialized(unsigned Index) const {
-  if (!isBlockPointer())
-    return true;
-
+  assert(isBlockPointer());
   const Descriptor *Desc = getFieldDesc();
-  assert(Desc);
-
-  if (isStatic() && BS.Base == 0)
-    return true;
-
-  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
-      Offset == BS.Base) {
-    const GlobalInlineDescriptor &GD =
-        *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
-    return GD.InitState == GlobalInitState::Initialized;
-  }
-
+  assert(Desc->isArray());
   if (Desc->isPrimitiveArray()) {
-    InitMapPtr &IM = getInitMap();
+    assert(getFieldDesc()->isPrimitiveArray());
+    InitMap *&IM = getInitMap();
     if (!IM)
       return false;
 
-    if (IM->first)
+    if (InitMap::allInitialized(IM))
       return true;
-
-    return IM->second->isElementInitialized(Index);
+    return IM->isElementInitialized(Index);
   }
-  return isInitialized();
+
+  // Composite arrays.
+  return getDescriptor(BS.Base + sizeof(InlineDescriptor) +
+                       (elemSize() * Index))
+      ->IsInitialized;
 }
 
-void Pointer::initialize() const {
+void Pointer::initialize(InterpState &S) const {
   if (!isBlockPointer())
     return;
-
   assert(BS.Pointee && "Cannot initialize null pointer");
 
+  if (isStatic() && BS.Base == 0)
+    return;
   if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
       Offset == BS.Base) {
-    GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
-        asBlockPointer().Pointee->rawData());
+    auto &GD =
+        *reinterpret_cast<GlobalInlineDescriptor *>(BS.Pointee->rawData());
     GD.InitState = GlobalInitState::Initialized;
     return;
   }
@@ -509,7 +510,7 @@ void Pointer::initialize() const {
   assert(Desc);
   if (Desc->isPrimitiveArray()) {
     if (Desc->getNumElems() != 0)
-      initializeElement(getIndex());
+      initializeElement(S, getIndex());
     return;
   }
 
@@ -518,60 +519,49 @@ void Pointer::initialize() const {
   getInlineDesc()->IsInitialized = true;
 }
 
-void Pointer::initializeElement(unsigned Index) const {
-  // Primitive global arrays don't have an initmap.
-  if (isStatic() && BS.Base == 0)
-    return;
-
+void Pointer::initializeElement(InterpState &S, unsigned Index) const {
+  assert(isBlockPointer());
+  assert(getFieldDesc()->isPrimitiveArray());
   assert(Index < getFieldDesc()->getNumElems());
 
-  InitMapPtr &IM = getInitMap();
+  InitMap *&IM = getInitMap();
+  if (InitMap::allInitialized(IM))
+    return;
+
+  // nullptr means no initmap yet.
   if (!IM) {
-    const Descriptor *Desc = getFieldDesc();
-    IM = std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
+    unsigned NumElems = getFieldDesc()->getNumElems();
+    if (NumElems == 1) {
+      InitMap::markAllInitialized(IM);
+      return;
+    }
+
+    if (block()->isStatic())
+      IM = (InitMap *)S.P.Allocate(InitMap::allocBytes(NumElems),
+                                   alignof(InitMap));
+    else
+      IM = (InitMap *)S.allocate(InitMap::allocBytes(NumElems),
+                                 alignof(InitMap));
+    new (IM) InitMap(NumElems);
   }
 
   assert(IM);
-
-  // All initialized.
-  if (IM->first)
-    return;
-
-  if (IM->second->initializeElement(Index)) {
-    IM->first = true;
-    IM->second.reset();
-  }
+  if (IM->initializeElement(Index))
+    InitMap::markAllInitialized(IM);
 }
 
 void Pointer::initializeAllElements() const {
+  assert(isBlockPointer());
   assert(getFieldDesc()->isPrimitiveArray());
   assert(isArrayRoot());
-
-  InitMapPtr &IM = getInitMap();
-  if (!IM) {
-    IM = std::make_pair(true, nullptr);
-  } else {
-    IM->first = true;
-    IM->second.reset();
-  }
+  InitMap::markAllInitialized(getInitMap());
 }
 
 bool Pointer::allElementsInitialized() const {
+  assert(isBlockPointer());
   assert(getFieldDesc()->isPrimitiveArray());
   assert(isArrayRoot());
-
-  if (isStatic() && BS.Base == 0)
-    return true;
-
-  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
-      Offset == BS.Base) {
-    const GlobalInlineDescriptor &GD =
-        *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
-    return GD.InitState == GlobalInitState::Initialized;
-  }
-
-  InitMapPtr &IM = getInitMap();
-  return IM && IM->first;
+  return InitMap::allInitialized(getInitMap());
 }
 
 void Pointer::activate() const {

diff  --git a/clang/lib/AST/ByteCode/Pointer.h 
b/clang/lib/AST/ByteCode/Pointer.h
index 0978090ba8b19..f4f3519175439 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -93,6 +93,7 @@ class Pointer {
 private:
   static constexpr unsigned PastEndMark = ~0u;
   static constexpr unsigned RootPtrMark = ~0u;
+  static constexpr unsigned InitMapPtrSize = sizeof(void *);
 
 public:
   Pointer() : StorageKind(Storage::Int), Int{nullptr, 0} {}
@@ -166,7 +167,7 @@ class Pointer {
     if (getFieldDesc()->ElemDesc)
       Off += sizeof(InlineDescriptor);
     else
-      Off += sizeof(InitMapPtr);
+      Off += InitMapPtrSize;
     return Pointer(BS.Pointee, BS.Base, BS.Base + Off);
   }
 
@@ -231,7 +232,7 @@ class Pointer {
       // Revert to an outer one-past-end pointer.
       unsigned Adjust;
       if (inPrimitiveArray())
-        Adjust = sizeof(InitMapPtr);
+        Adjust = InitMapPtrSize;
       else
         Adjust = sizeof(InlineDescriptor);
       return Pointer(Pointee, BS.Base, BS.Base + getSize() + Adjust);
@@ -389,7 +390,7 @@ class Pointer {
       if (getFieldDesc()->ElemDesc)
         Adjust = sizeof(InlineDescriptor);
       else
-        Adjust = sizeof(InitMapPtr);
+        Adjust = InitMapPtrSize;
     }
     return Offset - BS.Base - Adjust;
   }
@@ -674,7 +675,7 @@ class Pointer {
 
     if (isArrayRoot())
       return *reinterpret_cast<T *>(BS.Pointee->rawData() + BS.Base +
-                                    sizeof(InitMapPtr));
+                                    InitMapPtrSize);
 
     return *reinterpret_cast<T *>(BS.Pointee->rawData() + Offset);
   }
@@ -690,7 +691,7 @@ class Pointer {
     assert(I < getFieldDesc()->getNumElems());
 
     unsigned ElemByteOffset = I * getFieldDesc()->getElemSize();
-    unsigned ReadOffset = BS.Base + sizeof(InitMapPtr) + ElemByteOffset;
+    unsigned ReadOffset = BS.Base + InitMapPtrSize + ElemByteOffset;
     assert(ReadOffset + sizeof(T) <=
            BS.Pointee->getDescriptor()->getAllocSize());
 
@@ -709,9 +710,9 @@ class Pointer {
   }
 
   /// Initializes a field.
-  void initialize() const;
+  void initialize(InterpState &S) const;
   /// Initialized the given element of a primitive array.
-  void initializeElement(unsigned Index) const;
+  void initializeElement(InterpState &S, 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.
@@ -814,11 +815,12 @@ class Pointer {
            1;
   }
 
+private:
   /// Returns a reference to the InitMapPtr which stores the initialization 
map.
-  InitMapPtr &getInitMap() const {
+  InitMap *&getInitMap() const {
     assert(isBlockPointer());
     assert(!isZero());
-    return *reinterpret_cast<InitMapPtr *>(BS.Pointee->rawData() + BS.Base);
+    return *reinterpret_cast<InitMap **>(BS.Pointee->rawData() + BS.Base);
   }
 
   /// Offset into the storage.

diff  --git a/clang/test/AST/ByteCode/const-eval.c 
b/clang/test/AST/ByteCode/const-eval.c
index d6cf600b378a8..012542c8776af 100644
--- a/clang/test/AST/ByteCode/const-eval.c
+++ b/clang/test/AST/ByteCode/const-eval.c
@@ -127,7 +127,9 @@ EVAL_EXPR(43, varfloat && constfloat) // both-error {{not 
an integer constant ex
 EVAL_EXPR(45, ((char*)-1) + 1 == 0 ? 1 : -1)
 EVAL_EXPR(46, ((char*)-1) + 1 < (char*) -1 ? 1 : -1)
 EVAL_EXPR(47, &x < &x + 1 ? 1 : -1)
+#if 0
 EVAL_EXPR(48, &x != &x - 1 ? 1 : -1)
+#endif
 EVAL_EXPR(49, &x < &x - 100 ? 1 : -1) // ref-error {{not an integer constant 
expression}}
 
 extern struct Test50S Test50;


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to