https://github.com/tbaederr updated 
https://github.com/llvm/llvm-project/pull/200342

>From c3f0c543c9c822c8a0f16d25e8f0e9ab4fdcc6a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Fri, 29 May 2026 09:29:50 +0200
Subject: [PATCH] gettype

---
 clang/lib/AST/ByteCode/Descriptor.cpp       |  53 ++--
 clang/lib/AST/ByteCode/Descriptor.h         |   6 +-
 clang/lib/AST/ByteCode/DynamicAllocator.cpp |   8 +-
 clang/lib/AST/ByteCode/Pointer.h            |  25 +-
 clang/lib/AST/ByteCode/Program.cpp          |  29 ++-
 clang/unittests/AST/ByteCode/CMakeLists.txt |   1 +
 clang/unittests/AST/ByteCode/Pointer.cpp    | 274 ++++++++++++++++++++
 7 files changed, 348 insertions(+), 48 deletions(-)
 create mode 100644 clang/unittests/AST/ByteCode/Pointer.cpp

diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp 
b/clang/lib/AST/ByteCode/Descriptor.cpp
index 2d7561480f645..dfe539ca85e04 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -301,14 +301,14 @@ Descriptor::Descriptor(const DeclTy &D, const Type 
*SourceTy, PrimType Type,
 }
 
 /// Primitive arrays.
-Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
-                       size_t NumElems, bool IsConst, bool IsTemporary,
-                       bool IsMutable)
-    : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
-      MDSize(MD.value_or(0)),
+Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type,
+                       MetadataSize MD, size_t NumElems, bool IsConst,
+                       bool IsTemporary, bool IsMutable, bool IsVolatile)
+    : Source(D), SourceType(SourceTy), ElemSize(primSize(Type)),
+      Size(ElemSize * NumElems), MDSize(MD.value_or(0)),
       AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type),
       IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
-      IsArray(true), CtorFn(getCtorArrayPrim(Type)),
+      IsVolatile(IsVolatile), IsArray(true), CtorFn(getCtorArrayPrim(Type)),
       DtorFn(getDtorArrayPrim(Type)) {
   assert(Source && "Missing source");
   assert(NumElems <= (MaxArrayElemBytes / ElemSize));
@@ -375,8 +375,7 @@ Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)
 QualType Descriptor::getType() const {
   if (SourceType)
     return QualType(SourceType, 0);
-  if (const auto *D = asValueDecl())
-    return D->getType();
+
   if (const auto *T = dyn_cast_if_present<TypeDecl>(asDecl()))
     return T->getASTContext().getTypeDeclType(T);
 
@@ -384,10 +383,28 @@ QualType Descriptor::getType() const {
   // we really save. Try to consult the Record first.
   if (isRecord()) {
     const RecordDecl *RD = ElemRecord->getDecl();
-    return RD->getASTContext().getCanonicalTagType(RD);
+    QualType T = RD->getASTContext().getTagType(ElaboratedTypeKeyword::None,
+                                                std::nullopt, RD, false);
+    if (IsConst)
+      return T.withConst();
+    return T;
   }
-  if (const auto *E = asExpr())
+
+  if (const auto *E = asExpr()) {
+    if (isa<CXXNewExpr>(E))
+      return E->getType()->getPointeeType();
+
+    // std::allocator.allocate() call.
+    if (const auto *ME = dyn_cast<CXXMemberCallExpr>(E);
+        ME && ME->getRecordDecl()->getName() == "allocator" &&
+        ME->getMethodDecl()->getName() == "allocate")
+      return E->getType()->getPointeeType();
     return E->getType();
+  }
+
+  if (const auto *D = asValueDecl())
+    return D->getType();
+
   llvm_unreachable("Invalid descriptor type");
 }
 
@@ -441,22 +458,6 @@ QualType Descriptor::getDataType(const ASTContext &Ctx) 
const {
   return getType();
 }
 
-QualType Descriptor::getDataElemType() const {
-  if (const auto *E = asExpr()) {
-    if (isa<CXXNewExpr>(E))
-      return E->getType()->getPointeeType();
-
-    // std::allocator.allocate() call.
-    if (const auto *ME = dyn_cast<CXXMemberCallExpr>(E);
-        ME && ME->getRecordDecl()->getName() == "allocator" &&
-        ME->getMethodDecl()->getName() == "allocate")
-      return E->getType()->getPointeeType();
-    return E->getType();
-  }
-
-  return getType();
-}
-
 SourceLocation Descriptor::getLocation() const {
   if (auto *D = dyn_cast<const Decl *>(Source))
     return D->getLocation();
diff --git a/clang/lib/AST/ByteCode/Descriptor.h 
b/clang/lib/AST/ByteCode/Descriptor.h
index 498a01e8f070c..a2df48cf1e7fb 100644
--- a/clang/lib/AST/ByteCode/Descriptor.h
+++ b/clang/lib/AST/ByteCode/Descriptor.h
@@ -179,8 +179,9 @@ struct Descriptor final {
              bool IsVolatile);
 
   /// Allocates a descriptor for an array of primitives.
-  Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, size_t NumElems,
-             bool IsConst, bool IsTemporary, bool IsMutable);
+  Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type,
+             MetadataSize MD, size_t NumElems, bool IsConst, bool IsTemporary,
+             bool IsMutable, bool IsVolatile);
 
   /// Allocates a descriptor for an array of primitives of unknown size.
   Descriptor(const DeclTy &D, PrimType Type, MetadataSize MDSize, bool IsConst,
@@ -205,7 +206,6 @@ struct Descriptor final {
   QualType getType() const;
   QualType getElemQualType() const;
   QualType getDataType(const ASTContext &Ctx) const;
-  QualType getDataElemType() const;
   SourceLocation getLocation() const;
   SourceInfo getLoc() const;
 
diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp 
b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
index 5f53fac923682..36e0bfd666b74 100644
--- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp
+++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
@@ -39,9 +39,11 @@ Block *DynamicAllocator::allocate(const Expr *Source, 
PrimType T,
                                   Form AllocForm) {
   // Create a new descriptor for an array of the specified size and
   // element type.
-  const Descriptor *D = allocateDescriptor(
-      Source, T, Descriptor::InlineDescMD, NumElements, /*IsConst=*/false,
-      /*IsTemporary=*/false, /*IsMutable=*/false);
+  const Descriptor *D =
+      allocateDescriptor(Source, nullptr, T, Descriptor::InlineDescMD,
+                         NumElements, /*IsConst=*/false,
+                         /*IsTemporary=*/false, /*IsMutable=*/false,
+                         /*IsVolatile=*/false);
 
   return allocate(D, EvalID, AllocForm);
 }
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 3eb9cfc4e53db..1a4aa48e55161 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -349,6 +349,15 @@ class Pointer {
     if (isFunctionPointer())
       return Fn.Func->getDecl()->getType();
 
+    if (isRoot() && BS.Base == Offset) {
+      // If this pointer points to the root of a declaration, try to consult
+      // the ValueDecl directly, since that has a type with more information,
+      // e.g. the correct ElaboratedTypeKeyword.
+      if (const ValueDecl *VD = getDeclDesc()->asValueDecl())
+        return VD->getType();
+      return getDeclDesc()->getType();
+    }
+
     if (inPrimitiveArray() && Offset != BS.Base) {
       // Unfortunately, complex and vector types are not array types in clang,
       // but they are for us.
@@ -360,7 +369,7 @@ class Pointer {
         return CT->getElementType();
     }
 
-    return getFieldDesc()->getDataElemType();
+    return getFieldDesc()->getType();
   }
 
   [[nodiscard]] Pointer getDeclPtr() const { return Pointer(BS.Pointee); }
@@ -902,8 +911,18 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream 
&OS, const Pointer &P) {
   if (P.isArrayElement()) {
     if (P.isOnePastEnd())
       OS << " one-past-the-end";
-    else
-      OS << " index " << P.getIndex();
+    else {
+      OS << ' ';
+      std::string Indices;
+      llvm::raw_string_ostream SS(Indices);
+      Pointer K = P;
+      while (K.isArrayElement()) {
+        SS << ']' << K.expand().getIndex() << '[';
+        K = K.expand().getArray();
+      }
+      std::reverse(Indices.begin(), Indices.end());
+      OS << Indices;
+    }
   } else if (P.isArrayRoot())
     OS << " arrayroot";
 
diff --git a/clang/lib/AST/ByteCode/Program.cpp 
b/clang/lib/AST/ByteCode/Program.cpp
index 1f251fef8a36d..28ebb21ccbe69 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -45,11 +45,13 @@ unsigned Program::createGlobalString(const StringLiteral 
*S, const Expr *Base) {
     Base = S;
 
   // Create a descriptor for the string.
-  Descriptor *Desc = allocateDescriptor(Base, *CharType, Descriptor::GlobalMD,
-                                        StringLength + 1,
-                                        /*IsConst=*/true,
-                                        /*isTemporary=*/false,
-                                        /*isMutable=*/false);
+  Descriptor *Desc =
+      allocateDescriptor(Base, S->getType().getTypePtr(), *CharType,
+                         Descriptor::GlobalMD, StringLength + 1,
+                         /*IsConst=*/true,
+                         /*isTemporary=*/false,
+                         /*isMutable=*/false,
+                         /*IsVolatile=*/false);
 
   // Allocate storage for the string.
   // The byte length does not include the null terminator.
@@ -426,8 +428,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, 
const Type *Ty,
         if ((Descriptor::MaxArrayElemBytes / ElemSize) < NumElems) {
           return nullptr;
         }
-        return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, 
IsTemporary,
-                                  IsMutable);
+        return allocateDescriptor(D, CAT, *T, MDSize, NumElems, IsConst,
+                                  IsTemporary, IsMutable, IsVolatile);
       }
         // Arrays of composites. In this case, the array is a list of pointers,
         // followed by the actual elements.
@@ -472,8 +474,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, 
const Type *Ty,
     if (!ElemTy)
       return nullptr;
 
-    return allocateDescriptor(D, *ElemTy, MDSize, 2, IsConst, IsTemporary,
-                              IsMutable);
+    return allocateDescriptor(D, CT, *ElemTy, MDSize, 2, IsConst, IsTemporary,
+                              IsMutable, IsVolatile);
   }
 
   // Same with vector types.
@@ -482,8 +484,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, 
const Type *Ty,
     if (!ElemTy)
       return nullptr;
 
-    return allocateDescriptor(D, *ElemTy, MDSize, VT->getNumElements(), 
IsConst,
-                              IsTemporary, IsMutable);
+    return allocateDescriptor(D, VT, *ElemTy, MDSize, VT->getNumElements(),
+                              IsConst, IsTemporary, IsMutable, IsVolatile);
   }
 
   // Same with constant matrix types.
@@ -492,8 +494,9 @@ Descriptor *Program::createDescriptor(const DeclTy &D, 
const Type *Ty,
     if (!ElemTy)
       return nullptr;
 
-    return allocateDescriptor(D, *ElemTy, MDSize, 
MT->getNumElementsFlattened(),
-                              IsConst, IsTemporary, IsMutable);
+    return allocateDescriptor(D, MT, *ElemTy, MDSize,
+                              MT->getNumElementsFlattened(), IsConst,
+                              IsTemporary, IsMutable, IsVolatile);
   }
 
   return nullptr;
diff --git a/clang/unittests/AST/ByteCode/CMakeLists.txt 
b/clang/unittests/AST/ByteCode/CMakeLists.txt
index 1469cd6b2a8ea..0d49aa3eec30d 100644
--- a/clang/unittests/AST/ByteCode/CMakeLists.txt
+++ b/clang/unittests/AST/ByteCode/CMakeLists.txt
@@ -2,6 +2,7 @@ add_clang_unittest(InterpTests
   BitcastBuffer.cpp
   Descriptor.cpp
   toAPValue.cpp
+  Pointer.cpp
   CLANG_LIBS
   clangAST
   clangASTMatchers
diff --git a/clang/unittests/AST/ByteCode/Pointer.cpp 
b/clang/unittests/AST/ByteCode/Pointer.cpp
new file mode 100644
index 0000000000000..0b93c40aaa202
--- /dev/null
+++ b/clang/unittests/AST/ByteCode/Pointer.cpp
@@ -0,0 +1,274 @@
+#include "../../../lib/AST/ByteCode/Context.h"
+#include "../../../lib/AST/ByteCode/Descriptor.h"
+#include "../../../lib/AST/ByteCode/Integral.h"
+#include "../../../lib/AST/ByteCode/Program.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace clang::interp;
+using namespace clang::ast_matchers;
+
+TEST(Pointer, TypesRecord) {
+  constexpr char Code[] = "struct A { bool a; bool b; };\n"
+                          "constexpr A arr[3][2] = {\n"
+                          "  {{ false, false }, {false, true} },\n"
+                          "  {{ false, false }, {false, true} },\n"
+                          "  {{ false, false }, {false, true} },\n"
+                          "};\n";
+
+  auto AST = tooling::buildASTFromCodeWithArgs(
+      Code, {"-fexperimental-new-constant-interpreter"});
+  ASTContext &ASTCtx = AST->getASTContext();
+  const VarDecl *D =
+      selectFirst<VarDecl>("arr", match(varDecl().bind("arr"), ASTCtx));
+  ASSERT_NE(D, nullptr);
+
+  const auto &Ctx = AST->getASTContext().getInterpContext();
+  Program &Prog = Ctx.getProgram();
+  // Global is registered.
+  ASSERT_TRUE(Prog.getGlobal(D));
+
+  // Get a Pointer to the global.
+  const Pointer &GlobalPtr = Prog.getPtrGlobal(*Prog.getGlobal(D));
+
+  // Type of the global ptr should be A[][]
+  {
+    QualType T = GlobalPtr.getType();
+    ASSERT_TRUE(T->isArrayType());
+    const auto *ArrTy = cast<ConstantArrayType>(T->getAsArrayTypeUnsafe());
+    ASSERT_NE(ArrTy, nullptr);
+    ASSERT_EQ(ArrTy->getZExtSize(), (uint64_t)3);
+
+    QualType ElemTy = ArrTy->getElementType();
+    const auto *ElemArrTy =
+        cast<ConstantArrayType>(ElemTy->getAsArrayTypeUnsafe());
+    ASSERT_NE(ElemArrTy, nullptr);
+    ASSERT_EQ(ElemArrTy->getZExtSize(), (uint64_t)2);
+  }
+
+  // This is still A[][] because we didn't narrow().
+  {
+    Pointer Elem = GlobalPtr.atIndex(0);
+    QualType T = Elem.getType();
+    const auto *ArrTy = cast<ConstantArrayType>(T->getAsArrayTypeUnsafe());
+    ASSERT_NE(ArrTy, nullptr);
+    ASSERT_EQ(ArrTy->getZExtSize(), (uint64_t)3);
+
+    QualType ElemTy = ArrTy->getElementType();
+    const auto *ElemArrTy =
+        cast<ConstantArrayType>(ElemTy->getAsArrayTypeUnsafe());
+    ASSERT_NE(ElemArrTy, nullptr);
+    ASSERT_EQ(ElemArrTy->getZExtSize(), (uint64_t)2);
+  }
+
+  // Now with narrow(). This is just A[2], the type of the first element.
+  {
+    Pointer Elem = GlobalPtr.atIndex(0).narrow();
+    QualType T = Elem.getType();
+    const auto *ArrTy = cast<ConstantArrayType>(T->getAsArrayTypeUnsafe());
+    ASSERT_NE(ArrTy, nullptr);
+    ASSERT_EQ(ArrTy->getZExtSize(), (uint64_t)2);
+  }
+
+  // Same with element 1.
+  {
+    Pointer Elem = GlobalPtr.atIndex(1).narrow();
+    QualType T = Elem.getType();
+    const auto *ArrTy = cast<ConstantArrayType>(T->getAsArrayTypeUnsafe());
+    ASSERT_NE(ArrTy, nullptr);
+    ASSERT_EQ(ArrTy->getZExtSize(), (uint64_t)2);
+  }
+  // And 2.
+  {
+    Pointer Elem = GlobalPtr.atIndex(2).narrow();
+    QualType T = Elem.getType();
+    const auto *ArrTy = cast<ConstantArrayType>(T->getAsArrayTypeUnsafe());
+    ASSERT_NE(ArrTy, nullptr);
+    ASSERT_EQ(ArrTy->getZExtSize(), (uint64_t)2);
+  }
+
+  // This is arr[I][0], but we didn't narrow() at the end so the type is that 
of
+  // arr[I].
+  {
+    for (unsigned I = 0; I != 3; ++I) {
+      Pointer Elem = GlobalPtr.atIndex(I).narrow().atIndex(0);
+      QualType T = Elem.getType();
+      const auto *ArrTy = cast<ConstantArrayType>(T->getAsArrayTypeUnsafe());
+      ASSERT_NE(ArrTy, nullptr);
+      ASSERT_EQ(ArrTy->getZExtSize(), (uint64_t)2);
+    }
+  }
+  // Now WITH a narrow, the type should be just A.
+  {
+    for (unsigned I = 0; I != 3; ++I) {
+      for (unsigned J = 0; J != 2; ++J) {
+        Pointer Elem = GlobalPtr.atIndex(I).narrow().atIndex(J).narrow();
+        QualType T = Elem.getType();
+        ASSERT_TRUE(T->isRecordType());
+      }
+    }
+  }
+
+  // Same as the above, but we expand() again to undo the last narrow.
+  // The type should therefore be A[].
+  {
+    for (unsigned I = 0; I != 3; ++I) {
+      for (unsigned J = 0; J != 2; ++J) {
+        Pointer Elem =
+            GlobalPtr.atIndex(I).narrow().atIndex(J).narrow().expand();
+        QualType T = Elem.getType();
+        const auto *ArrTy = cast<ConstantArrayType>(T->getAsArrayTypeUnsafe());
+        ASSERT_NE(ArrTy, nullptr);
+        ASSERT_EQ(ArrTy->getZExtSize(), (uint64_t)2);
+      }
+    }
+  }
+
+  // Check narrow/expand invariants.
+  {
+    for (unsigned I = 0; I != 3; ++I) {
+      for (unsigned J = 0; J != 2; ++J) {
+        ASSERT_EQ(GlobalPtr.atIndex(I).narrow().atIndex(J),
+                  GlobalPtr.atIndex(I).narrow().atIndex(J).narrow().expand());
+        ASSERT_EQ(GlobalPtr.atIndex(I).narrow().atIndex(J), 
GlobalPtr.atIndex(I)
+                                                                .narrow()
+                                                                .atIndex(J)
+                                                                .narrow()
+                                                                .expand()
+                                                                .expand());
+        ASSERT_EQ(GlobalPtr.atIndex(I), 
GlobalPtr.atIndex(I).narrow().expand());
+        ASSERT_EQ(GlobalPtr.atIndex(I),
+                  GlobalPtr.atIndex(I).narrow().expand().expand());
+        ASSERT_EQ(GlobalPtr.atIndex(I).atIndex(1), GlobalPtr.atIndex(1));
+      }
+    }
+  }
+
+  // getIndex()
+  {
+    // First dimension.
+    ASSERT_EQ(GlobalPtr.atIndex(0).getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(1).getIndex(), 1);
+    ASSERT_EQ(GlobalPtr.atIndex(2).getIndex(), 2);
+
+    // First dimension, with narrow().
+    ASSERT_EQ(GlobalPtr.atIndex(0).narrow().getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(1).narrow().getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(2).narrow().getIndex(), 0);
+
+    // Second dimension.
+    ASSERT_EQ(GlobalPtr.atIndex(0).narrow().atIndex(0).getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(0).narrow().atIndex(1).getIndex(), 1);
+    ASSERT_EQ(GlobalPtr.atIndex(1).narrow().atIndex(0).getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(1).narrow().atIndex(1).getIndex(), 1);
+    ASSERT_EQ(GlobalPtr.atIndex(2).narrow().atIndex(0).getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(2).narrow().atIndex(1).getIndex(), 1);
+
+    // Second dimension, with narrow().
+    ASSERT_EQ(GlobalPtr.atIndex(0).narrow().atIndex(0).narrow().getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(0).narrow().atIndex(1).narrow().getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(1).narrow().atIndex(0).narrow().getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(1).narrow().atIndex(1).narrow().getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(2).narrow().atIndex(0).narrow().getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(2).narrow().atIndex(1).narrow().getIndex(), 0);
+  }
+}
+
+TEST(Pointer, TypesPrimitive) {
+  constexpr char Code[] = "constexpr int arr[3][2] = {\n"
+                          " { 1, 2 },\n"
+                          " { 3, 4 },\n"
+                          " { 5, 6 },\n"
+                          "};\n";
+
+  auto AST = tooling::buildASTFromCodeWithArgs(
+      Code, {"-fexperimental-new-constant-interpreter"});
+  ASTContext &ASTCtx = AST->getASTContext();
+  const VarDecl *D =
+      selectFirst<VarDecl>("arr", match(varDecl().bind("arr"), ASTCtx));
+  ASSERT_NE(D, nullptr);
+
+  const auto &Ctx = AST->getASTContext().getInterpContext();
+  Program &Prog = Ctx.getProgram();
+  // Global is registered.
+  ASSERT_TRUE(Prog.getGlobal(D));
+
+  // Get a Pointer to the global.
+  const Pointer &GlobalPtr = Prog.getPtrGlobal(*Prog.getGlobal(D));
+
+  // Type of the global ptr should be int[3][2].
+  {
+    QualType T = GlobalPtr.getType();
+    ASSERT_TRUE(T->isArrayType());
+    const auto *ArrTy = cast<ConstantArrayType>(T->getAsArrayTypeUnsafe());
+    ASSERT_NE(ArrTy, nullptr);
+    ASSERT_EQ(ArrTy->getZExtSize(), (uint64_t)3);
+
+    QualType ElemTy = ArrTy->getElementType();
+    const auto *ElemArrTy =
+        cast<ConstantArrayType>(ElemTy->getAsArrayTypeUnsafe());
+    ASSERT_NE(ElemArrTy, nullptr);
+    ASSERT_EQ(ElemArrTy->getZExtSize(), (uint64_t)2);
+  }
+
+  // Type of the elements of the first dimension should be int[2].
+  {
+    for (unsigned I = 0; I != 3; ++I) {
+      Pointer Elem = GlobalPtr.atIndex(I).narrow();
+      QualType T = Elem.getType();
+      const auto *ArrTy = cast<ConstantArrayType>(T->getAsArrayTypeUnsafe());
+      ASSERT_NE(ArrTy, nullptr);
+      ASSERT_EQ(ArrTy->getZExtSize(), (uint64_t)2);
+    }
+  }
+
+  // Inner dimension is just int.
+  {
+    for (unsigned I = 0; I != 3; ++I) {
+      for (unsigned J = 0; J != 2; ++J) {
+        Pointer Elem = GlobalPtr.atIndex(I).narrow().atIndex(J);
+        QualType T = Elem.getType();
+        ASSERT_TRUE(T->isIntegerType());
+      }
+    }
+  }
+
+  {
+    // First dimension.
+    ASSERT_EQ(GlobalPtr.atIndex(0).getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(1).getIndex(), 1);
+    ASSERT_EQ(GlobalPtr.atIndex(2).getIndex(), 2);
+
+    // First dimension, with narrow().
+    ASSERT_EQ(GlobalPtr.atIndex(0).narrow().getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(1).narrow().getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(2).narrow().getIndex(), 0);
+
+    // Second dimension.
+    ASSERT_EQ(GlobalPtr.atIndex(0).narrow().atIndex(0).getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(0).narrow().atIndex(1).getIndex(), 1);
+    ASSERT_EQ(GlobalPtr.atIndex(1).narrow().atIndex(0).getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(1).narrow().atIndex(1).getIndex(), 1);
+    ASSERT_EQ(GlobalPtr.atIndex(2).narrow().atIndex(0).getIndex(), 0);
+    ASSERT_EQ(GlobalPtr.atIndex(2).narrow().atIndex(1).getIndex(), 1);
+  }
+
+  {
+    // narrow() does not affect pointers into primitive arrays.
+    ASSERT_EQ(GlobalPtr.atIndex(0).narrow().atIndex(1),
+              GlobalPtr.atIndex(0).narrow().atIndex(1).narrow());
+    ASSERT_EQ(GlobalPtr.atIndex(0).narrow().atIndex(1),
+              GlobalPtr.atIndex(0).narrow().atIndex(1).expand());
+
+    ASSERT_EQ(GlobalPtr.atIndex(0).narrow(),
+              GlobalPtr.atIndex(0).narrow().atIndex(1).getArray());
+
+    ASSERT_EQ(GlobalPtr, GlobalPtr.atIndex(2).getArray());
+    ASSERT_EQ(GlobalPtr, GlobalPtr.atIndex(2).narrow().expand().getArray());
+  }
+}

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

Reply via email to