[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-10-12 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/unittests/AST/Interp/CMakeLists.txt:2
+add_clang_unittest(InterpTests
+  Descriptor.cpp
+  )

thakis wrote:
> Why is this in a separate executable instead of in ASTTests? So it can have 
> fewer deps?
Mostly because running ASTTests takes very long


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-10-12 Thread Nico Weber via Phabricator via cfe-commits
thakis added inline comments.



Comment at: clang/unittests/AST/Interp/CMakeLists.txt:2
+add_clang_unittest(InterpTests
+  Descriptor.cpp
+  )

Why is this in a separate executable instead of in ASTTests? So it can have 
fewer deps?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-10-12 Thread Timm Bäder via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG2f43ace0f48f: [clang][Interp] Fix expected values for 
Pointer API (authored by tbaeder).

Changed prior to commit:
  https://reviews.llvm.org/D158069?vs=557656&id=557689#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

Files:
  clang/lib/AST/Interp/Context.h
  clang/lib/AST/Interp/Pointer.h
  clang/unittests/AST/CMakeLists.txt
  clang/unittests/AST/Interp/CMakeLists.txt
  clang/unittests/AST/Interp/Descriptor.cpp

Index: clang/unittests/AST/Interp/Descriptor.cpp
===
--- /dev/null
+++ clang/unittests/AST/Interp/Descriptor.cpp
@@ -0,0 +1,385 @@
+#include "../../../lib/AST/Interp/Descriptor.h"
+#include "../../../lib/AST/Interp/Context.h"
+#include "../../../lib/AST/Interp/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;
+
+/// Inspect generated Descriptors as well as the pointers we create.
+///
+TEST(Descriptor, Primitives) {
+  constexpr char Code[] =
+  "struct A { bool a; bool b; };\n"
+  "struct S {\n"
+  "  float f;\n"
+  "  char s[4];\n"
+  "  A a[3];\n"
+  "  short l[3][3];\n"
+  "};\n"
+  "constexpr S d = {0.0, \"foo\", {{true, false}, {false, true}, {false, false}},\n"
+  "  {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}};\n";
+
+  auto AST = tooling::buildASTFromCodeWithArgs(
+  Code, {"-fexperimental-new-constant-interpreter"});
+
+  const VarDecl *D = selectFirst(
+  "d", match(varDecl().bind("d"), AST->getASTContext()));
+  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));
+
+  // Test Descriptor of the struct S.
+  const Descriptor *GlobalDesc = GlobalPtr.getFieldDesc();
+  ASSERT_TRUE(GlobalDesc == GlobalPtr.getDeclDesc());
+
+  ASSERT_TRUE(GlobalDesc->asDecl() == D);
+  ASSERT_FALSE(GlobalDesc->asExpr());
+  ASSERT_TRUE(GlobalDesc->asValueDecl() == D);
+  ASSERT_FALSE(GlobalDesc->asFieldDecl());
+  ASSERT_FALSE(GlobalDesc->asRecordDecl());
+
+  // Still true because this is a global variable.
+  ASSERT_TRUE(GlobalDesc->getMetadataSize() == 0);
+  ASSERT_FALSE(GlobalDesc->isPrimitiveArray());
+  ASSERT_FALSE(GlobalDesc->isCompositeArray());
+  ASSERT_FALSE(GlobalDesc->isZeroSizeArray());
+  ASSERT_FALSE(GlobalDesc->isUnknownSizeArray());
+  ASSERT_FALSE(GlobalDesc->isPrimitive());
+  ASSERT_FALSE(GlobalDesc->isArray());
+  ASSERT_TRUE(GlobalDesc->isRecord());
+
+  // Test the Record for the struct S.
+  const Record *SRecord = GlobalDesc->ElemRecord;
+  ASSERT_TRUE(SRecord);
+  ASSERT_TRUE(SRecord->getNumFields() == 4);
+  ASSERT_TRUE(SRecord->getNumBases() == 0);
+  ASSERT_FALSE(SRecord->getDestructor());
+
+  // First field.
+  const Record::Field *F1 = SRecord->getField(0u);
+  ASSERT_TRUE(F1);
+  ASSERT_FALSE(F1->isBitField());
+  ASSERT_TRUE(F1->Desc->isPrimitive());
+
+  // Second field.
+  const Record::Field *F2 = SRecord->getField(1u);
+  ASSERT_TRUE(F2);
+  ASSERT_FALSE(F2->isBitField());
+  ASSERT_TRUE(F2->Desc->isArray());
+  ASSERT_FALSE(F2->Desc->isCompositeArray());
+  ASSERT_TRUE(F2->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F2->Desc->isPrimitive());
+  ASSERT_FALSE(F2->Desc->ElemDesc);
+  ASSERT_EQ(F2->Desc->getNumElems(), 4u);
+  ASSERT_TRUE(F2->Desc->getElemSize() > 0);
+
+  // Third field.
+  const Record::Field *F3 = SRecord->getField(2u);
+  ASSERT_TRUE(F3);
+  ASSERT_FALSE(F3->isBitField());
+  ASSERT_TRUE(F3->Desc->isArray());
+  ASSERT_TRUE(F3->Desc->isCompositeArray());
+  ASSERT_FALSE(F3->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F3->Desc->isPrimitive());
+  ASSERT_TRUE(F3->Desc->ElemDesc);
+  ASSERT_EQ(F3->Desc->getNumElems(), 3u);
+  ASSERT_TRUE(F3->Desc->getElemSize() > 0);
+
+  // Fourth field.
+  // Multidimensional arrays are treated as composite arrays, even
+  // if the value type is primitive.
+  const Record::Field *F4 = SRecord->getField(3u);
+  ASSERT_TRUE(F4);
+  ASSERT_FALSE(F4->isBitField());
+  ASSERT_TRUE(F4->Desc->isArray());
+  ASSERT_TRUE(F4->Desc->isCompositeArray());
+  ASSERT_FALSE(F4->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F4->Desc->isPrimitive());
+  ASSERT_TRUE(F4->Desc->ElemDesc);
+  ASSERT_EQ(F4->Desc->getNumElems(), 3u);
+  ASSERT_TRUE(F4->Desc->getElemSize() > 0);
+  ASSERT_TRUE(F4->Desc->ElemDesc->isPrimitiveArray());
+
+  // Check pointer stuff.
+  // Global variables have no inline des

[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-10-11 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman accepted this revision.
aaron.ballman added a comment.
This revision is now accepted and ready to land.

LGTM!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-10-09 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 557656.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

Files:
  clang/lib/AST/Interp/Context.h
  clang/lib/AST/Interp/Pointer.h
  clang/unittests/AST/CMakeLists.txt
  clang/unittests/AST/Interp/CMakeLists.txt
  clang/unittests/AST/Interp/Descriptor.cpp

Index: clang/unittests/AST/Interp/Descriptor.cpp
===
--- /dev/null
+++ clang/unittests/AST/Interp/Descriptor.cpp
@@ -0,0 +1,388 @@
+#define INCLUDED_FROM_UNITTEST
+#include "../../../lib/AST/Interp/Context.h"
+#include "../../../lib/AST/Interp/Pointer.h"
+#undef INCLUDED_FROM_UNITTEST
+#include "../../../lib/AST/Interp/Descriptor.h"
+#include "../../../lib/AST/Interp/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;
+
+/// Inspect generated Descriptors as well as the pointers we create.
+///
+TEST(Descriptor, Primitives) {
+  constexpr char Code[] = "struct A { bool a; bool b; };\n"
+  "struct S {\n"
+  "  float f;\n"
+  "  char s[4];\n"
+  "  A a[3];\n"
+  "  short l[3][3];\n"
+  "};\n"
+  "constexpr S d = {0.0, \"foo\", {{true, false}, "
+  "{false, true}, {false, false}},\n"
+  "  {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}};\n";
+
+  auto AST = tooling::buildASTFromCodeWithArgs(
+  Code, {"-fexperimental-new-constant-interpreter"});
+
+  const VarDecl *D = selectFirst(
+  "d", match(varDecl().bind("d"), AST->getASTContext()));
+  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));
+
+  // Test Descriptor of the struct S.
+  const Descriptor *GlobalDesc = GlobalPtr.getFieldDesc();
+  ASSERT_TRUE(GlobalDesc == GlobalPtr.getDeclDesc());
+
+  ASSERT_TRUE(GlobalDesc->asDecl() == D);
+  ASSERT_FALSE(GlobalDesc->asExpr());
+  ASSERT_TRUE(GlobalDesc->asValueDecl() == D);
+  ASSERT_FALSE(GlobalDesc->asFieldDecl());
+  ASSERT_FALSE(GlobalDesc->asRecordDecl());
+
+  // Still true because this is a global variable.
+  ASSERT_TRUE(GlobalDesc->getMetadataSize() == 0);
+  ASSERT_FALSE(GlobalDesc->isPrimitiveArray());
+  ASSERT_FALSE(GlobalDesc->isCompositeArray());
+  ASSERT_FALSE(GlobalDesc->isZeroSizeArray());
+  ASSERT_FALSE(GlobalDesc->isUnknownSizeArray());
+  ASSERT_FALSE(GlobalDesc->isPrimitive());
+  ASSERT_FALSE(GlobalDesc->isArray());
+  ASSERT_TRUE(GlobalDesc->isRecord());
+
+  // Test the Record for the struct S.
+  const Record *SRecord = GlobalDesc->ElemRecord;
+  ASSERT_TRUE(SRecord);
+  ASSERT_TRUE(SRecord->getNumFields() == 4);
+  ASSERT_TRUE(SRecord->getNumBases() == 0);
+  ASSERT_FALSE(SRecord->getDestructor());
+
+  // First field.
+  const Record::Field *F1 = SRecord->getField(0u);
+  ASSERT_TRUE(F1);
+  // ASSERT_FALSE(F1->isBitField());
+  ASSERT_TRUE(F1->Desc->isPrimitive());
+
+  // Second field.
+  const Record::Field *F2 = SRecord->getField(1u);
+  ASSERT_TRUE(F2);
+  // ASSERT_FALSE(F2->isBitField());
+  ASSERT_TRUE(F2->Desc->isArray());
+  ASSERT_FALSE(F2->Desc->isCompositeArray());
+  ASSERT_TRUE(F2->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F2->Desc->isPrimitive());
+  ASSERT_FALSE(F2->Desc->ElemDesc);
+  ASSERT_EQ(F2->Desc->getNumElems(), 4u);
+  ASSERT_TRUE(F2->Desc->getElemSize() > 0);
+
+  // Third field.
+  const Record::Field *F3 = SRecord->getField(2u);
+  ASSERT_TRUE(F3);
+  // ASSERT_FALSE(F3->isBitField());
+  ASSERT_TRUE(F3->Desc->isArray());
+  ASSERT_TRUE(F3->Desc->isCompositeArray());
+  ASSERT_FALSE(F3->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F3->Desc->isPrimitive());
+  ASSERT_TRUE(F3->Desc->ElemDesc);
+  ASSERT_EQ(F3->Desc->getNumElems(), 3u);
+  ASSERT_TRUE(F3->Desc->getElemSize() > 0);
+
+  // Fourth field.
+  // Multidimensional arrays are treated as composite arrays, even
+  // if the value type is primitive.
+  const Record::Field *F4 = SRecord->getField(3u);
+  ASSERT_TRUE(F4);
+  // ASSERT_FALSE(F4->isBitField());
+  ASSERT_TRUE(F4->Desc->isArray());
+  ASSERT_TRUE(F4->Desc->isCompositeArray());
+  ASSERT_FALSE(F4->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F4->Desc->isPrimitive());
+  ASSERT_TRUE(F4->Desc->ElemDesc);
+  ASSERT_EQ(F4->Desc->getNumElems(), 3u);
+  ASSERT_TRUE(F4->Desc->getElemSize() > 0);
+  ASSERT_TRUE(F4->Desc->ElemDesc->isPrimitiveArray());
+
+  // Check pointer stuff.
+  // Global variables have no inline descriptor (yet)

[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-10-09 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: clang/lib/AST/Interp/Pointer.h:81-88
+  /// Equality operators are just for tests.
+  bool operator==(const Pointer &P) const {
+return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset;
+  }
+
+  bool operator!=(const Pointer &P) const {
+return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset;

tbaeder wrote:
> aaron.ballman wrote:
> > tbaeder wrote:
> > > aaron.ballman wrote:
> > > > tbaeder wrote:
> > > > > aaron.ballman wrote:
> > > > > > Same here -- can these be private and friended?
> > > > > Don't you need a class to friend something? I only have the 
> > > > > `TEST(...)` function in the unit test, so I can't do that, right?
> > > > `FRIEND_TEST` does this, I believe: 
> > > > https://google.github.io/googletest/reference/testing.html#FRIEND_TEST
> > > Is this something we should be doing? There's nothing else in clang using 
> > > `FRIEND_TEST` and only stuff in `Testing/` includes gtest.h.
> > It's a tradeoff as to whether we want to expose private implementation 
> > details as part of a public interface just to enable unit testing, or 
> > whether we want to sprinkle unit testing annotations around the private 
> > implementation details just to enable unit testing. Personally, I prefer 
> > having cleaner public interfaces; otherwise we end up with people using the 
> > implementation details of a class and it's harder to refactor in the 
> > future. I'm not certain how others feel, though.
> I think `FRIEND_TEST` just doesn't work because I can't import a gtest header 
> from the `clangAST` library.
> 
> What I //can// do is just wrap those things in a `#ifdef IN_UNITTEST` and 
> define than before including those headers (all of this  code is in headers 
> right now) in the `unittest/AST/Interp/Descriptor.cpp`.
Okay, that seems like a good compromise to me. Later, we might want to figure 
out if we can hoist the macro logic up to a higher level so that other 
interfaces can use the same pattern. (e.g., maybe we want 
`LLVM_UNIT_TEST_INTERFACE` macro or some such?)


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-10-09 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/AST/Interp/Pointer.h:81-88
+  /// Equality operators are just for tests.
+  bool operator==(const Pointer &P) const {
+return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset;
+  }
+
+  bool operator!=(const Pointer &P) const {
+return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset;

aaron.ballman wrote:
> tbaeder wrote:
> > aaron.ballman wrote:
> > > tbaeder wrote:
> > > > aaron.ballman wrote:
> > > > > Same here -- can these be private and friended?
> > > > Don't you need a class to friend something? I only have the `TEST(...)` 
> > > > function in the unit test, so I can't do that, right?
> > > `FRIEND_TEST` does this, I believe: 
> > > https://google.github.io/googletest/reference/testing.html#FRIEND_TEST
> > Is this something we should be doing? There's nothing else in clang using 
> > `FRIEND_TEST` and only stuff in `Testing/` includes gtest.h.
> It's a tradeoff as to whether we want to expose private implementation 
> details as part of a public interface just to enable unit testing, or whether 
> we want to sprinkle unit testing annotations around the private 
> implementation details just to enable unit testing. Personally, I prefer 
> having cleaner public interfaces; otherwise we end up with people using the 
> implementation details of a class and it's harder to refactor in the future. 
> I'm not certain how others feel, though.
I think `FRIEND_TEST` just doesn't work because I can't import a gtest header 
from the `clangAST` library.

What I //can// do is just wrap those things in a `#ifdef IN_UNITTEST` and 
define than before including those headers (all of this  code is in headers 
right now) in the `unittest/AST/Interp/Descriptor.cpp`.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-10-04 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: clang/lib/AST/Interp/Pointer.h:81-88
+  /// Equality operators are just for tests.
+  bool operator==(const Pointer &P) const {
+return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset;
+  }
+
+  bool operator!=(const Pointer &P) const {
+return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset;

tbaeder wrote:
> aaron.ballman wrote:
> > tbaeder wrote:
> > > aaron.ballman wrote:
> > > > Same here -- can these be private and friended?
> > > Don't you need a class to friend something? I only have the `TEST(...)` 
> > > function in the unit test, so I can't do that, right?
> > `FRIEND_TEST` does this, I believe: 
> > https://google.github.io/googletest/reference/testing.html#FRIEND_TEST
> Is this something we should be doing? There's nothing else in clang using 
> `FRIEND_TEST` and only stuff in `Testing/` includes gtest.h.
It's a tradeoff as to whether we want to expose private implementation details 
as part of a public interface just to enable unit testing, or whether we want 
to sprinkle unit testing annotations around the private implementation details 
just to enable unit testing. Personally, I prefer having cleaner public 
interfaces; otherwise we end up with people using the implementation details of 
a class and it's harder to refactor in the future. I'm not certain how others 
feel, though.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-10-02 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/AST/Interp/Pointer.h:81-88
+  /// Equality operators are just for tests.
+  bool operator==(const Pointer &P) const {
+return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset;
+  }
+
+  bool operator!=(const Pointer &P) const {
+return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset;

aaron.ballman wrote:
> tbaeder wrote:
> > aaron.ballman wrote:
> > > Same here -- can these be private and friended?
> > Don't you need a class to friend something? I only have the `TEST(...)` 
> > function in the unit test, so I can't do that, right?
> `FRIEND_TEST` does this, I believe: 
> https://google.github.io/googletest/reference/testing.html#FRIEND_TEST
Is this something we should be doing? There's nothing else in clang using 
`FRIEND_TEST` and only stuff in `Testing/` includes gtest.h.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-10-02 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: clang/lib/AST/Interp/Pointer.h:81-88
+  /// Equality operators are just for tests.
+  bool operator==(const Pointer &P) const {
+return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset;
+  }
+
+  bool operator!=(const Pointer &P) const {
+return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset;

tbaeder wrote:
> aaron.ballman wrote:
> > Same here -- can these be private and friended?
> Don't you need a class to friend something? I only have the `TEST(...)` 
> function in the unit test, so I can't do that, right?
`FRIEND_TEST` does this, I believe: 
https://google.github.io/googletest/reference/testing.html#FRIEND_TEST


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-09-30 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/AST/Interp/Pointer.h:81-88
+  /// Equality operators are just for tests.
+  bool operator==(const Pointer &P) const {
+return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset;
+  }
+
+  bool operator!=(const Pointer &P) const {
+return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset;

aaron.ballman wrote:
> Same here -- can these be private and friended?
Don't you need a class to friend something? I only have the `TEST(...)` 
function in the unit test, so I can't do that, right?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-09-28 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: clang/lib/AST/Interp/Context.h:88
+  /// Returns the program. This is only needed for unittests.
+  Program &getProgram() const { return *P.get(); }
+

tbaeder wrote:
> cor3ntin wrote:
> > This should return a const ref
> Things like `getGlobal()` aren't const so that doesn't work.
If this is only needed for testing, can we make it a private function and use 
friendship to expose it to just what needs it? (Esp because it's got some odd 
const-correctness properties to it.)



Comment at: clang/lib/AST/Interp/Pointer.h:81-88
+  /// Equality operators are just for tests.
+  bool operator==(const Pointer &P) const {
+return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset;
+  }
+
+  bool operator!=(const Pointer &P) const {
+return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset;

Same here -- can these be private and friended?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-09-27 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

Ping


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-09-20 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/AST/Interp/Context.h:88
+  /// Returns the program. This is only needed for unittests.
+  Program &getProgram() const { return *P.get(); }
+

cor3ntin wrote:
> This should return a const ref
Things like `getGlobal()` aren't const so that doesn't work.



Comment at: clang/lib/AST/Interp/Pointer.h:342
+
+// narrow()ed element in a composite array.
+if (Base > 0 && Base == Offset)

cor3ntin wrote:
> Can you be a bit more verbose here? I can't figure out what is happening from 
> the comment!
For primitive arrays, the elements don't have inline descriptors:

```
 Offset
 │
 ▼
┌┬───┬───┬───┬───┬───┬─┐
│InitMap │ 1 │ 2 │ 3 │ 4 │ 5 │ ... │
└┴───┴───┴───┴───┴───┴─┘
▲
│
Base
```

If the array elements are composite elements themselves however, we can have a 
pointer that refers to the array element:

```
   Offset
   │
   ▼
┌──┬───┬──┬───┐
│InlineDesc│'a'│InlineDesc│'b'│
└──┴───┴──┴───┘
▲
│
Base
```

(so things like `isArrayElement()` return `true`) as well as a pointer that 
_only_ refers to the composite element (after a call to `narrow()`:

```
   Offset
   │
   ▼
┌──┬───┬──┬───┐
│InlineDesc│'a'│InlineDesc│'b'│
└──┴───┴──┴───┘
   ▲
   │
   Base
```

For the latter, the expected value of `getIndex()` is `0`, since it is (as far 
as the pointer knows) _not_ an array element.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-09-19 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 557097.
tbaeder marked an inline comment as done.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

Files:
  clang/lib/AST/Interp/Context.h
  clang/lib/AST/Interp/Pointer.h
  clang/unittests/AST/CMakeLists.txt
  clang/unittests/AST/Interp/CMakeLists.txt
  clang/unittests/AST/Interp/Descriptor.cpp

Index: clang/unittests/AST/Interp/Descriptor.cpp
===
--- /dev/null
+++ clang/unittests/AST/Interp/Descriptor.cpp
@@ -0,0 +1,385 @@
+#include "../../../lib/AST/Interp/Descriptor.h"
+#include "../../../lib/AST/Interp/Context.h"
+#include "../../../lib/AST/Interp/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;
+
+/// Inspect generated Descriptors as well as the pointers we create.
+///
+TEST(Descriptor, Primitives) {
+  constexpr char Code[] =
+  "struct A { bool a; bool b; };\n"
+  "struct S {\n"
+  "  float f;\n"
+  "  char s[4];\n"
+  "  A a[3];\n"
+  "  short l[3][3];\n"
+  "};\n"
+  "constexpr S d = {0.0, \"foo\", {{true, false}, {false, true}, {false, false}},\n"
+  "  {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}};\n";
+
+  auto AST = tooling::buildASTFromCodeWithArgs(
+  Code, {"-fexperimental-new-constant-interpreter"});
+
+  const VarDecl *D = selectFirst(
+  "d", match(varDecl().bind("d"), AST->getASTContext()));
+  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));
+
+  // Test Descriptor of the struct S.
+  const Descriptor *GlobalDesc = GlobalPtr.getFieldDesc();
+  ASSERT_TRUE(GlobalDesc == GlobalPtr.getDeclDesc());
+
+  ASSERT_TRUE(GlobalDesc->asDecl() == D);
+  ASSERT_FALSE(GlobalDesc->asExpr());
+  ASSERT_TRUE(GlobalDesc->asValueDecl() == D);
+  ASSERT_FALSE(GlobalDesc->asFieldDecl());
+  ASSERT_FALSE(GlobalDesc->asRecordDecl());
+
+  // Still true because this is a global variable.
+  ASSERT_TRUE(GlobalDesc->getMetadataSize() == 0);
+  ASSERT_FALSE(GlobalDesc->isPrimitiveArray());
+  ASSERT_FALSE(GlobalDesc->isCompositeArray());
+  ASSERT_FALSE(GlobalDesc->isZeroSizeArray());
+  ASSERT_FALSE(GlobalDesc->isUnknownSizeArray());
+  ASSERT_FALSE(GlobalDesc->isPrimitive());
+  ASSERT_FALSE(GlobalDesc->isArray());
+  ASSERT_TRUE(GlobalDesc->isRecord());
+
+  // Test the Record for the struct S.
+  const Record *SRecord = GlobalDesc->ElemRecord;
+  ASSERT_TRUE(SRecord);
+  ASSERT_TRUE(SRecord->getNumFields() == 4);
+  ASSERT_TRUE(SRecord->getNumBases() == 0);
+  ASSERT_FALSE(SRecord->getDestructor());
+
+  // First field.
+  const Record::Field *F1 = SRecord->getField(0u);
+  ASSERT_TRUE(F1);
+  ASSERT_FALSE(F1->isBitField());
+  ASSERT_TRUE(F1->Desc->isPrimitive());
+
+  // Second field.
+  const Record::Field *F2 = SRecord->getField(1u);
+  ASSERT_TRUE(F2);
+  ASSERT_FALSE(F2->isBitField());
+  ASSERT_TRUE(F2->Desc->isArray());
+  ASSERT_FALSE(F2->Desc->isCompositeArray());
+  ASSERT_TRUE(F2->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F2->Desc->isPrimitive());
+  ASSERT_FALSE(F2->Desc->ElemDesc);
+  ASSERT_EQ(F2->Desc->getNumElems(), 4u);
+  ASSERT_TRUE(F2->Desc->getElemSize() > 0);
+
+  // Third field.
+  const Record::Field *F3 = SRecord->getField(2u);
+  ASSERT_TRUE(F3);
+  ASSERT_FALSE(F3->isBitField());
+  ASSERT_TRUE(F3->Desc->isArray());
+  ASSERT_TRUE(F3->Desc->isCompositeArray());
+  ASSERT_FALSE(F3->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F3->Desc->isPrimitive());
+  ASSERT_TRUE(F3->Desc->ElemDesc);
+  ASSERT_EQ(F3->Desc->getNumElems(), 3u);
+  ASSERT_TRUE(F3->Desc->getElemSize() > 0);
+
+  // Fourth field.
+  // Multidimensional arrays are treated as composite arrays, even
+  // if the value type is primitive.
+  const Record::Field *F4 = SRecord->getField(3u);
+  ASSERT_TRUE(F4);
+  ASSERT_FALSE(F4->isBitField());
+  ASSERT_TRUE(F4->Desc->isArray());
+  ASSERT_TRUE(F4->Desc->isCompositeArray());
+  ASSERT_FALSE(F4->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F4->Desc->isPrimitive());
+  ASSERT_TRUE(F4->Desc->ElemDesc);
+  ASSERT_EQ(F4->Desc->getNumElems(), 3u);
+  ASSERT_TRUE(F4->Desc->getElemSize() > 0);
+  ASSERT_TRUE(F4->Desc->ElemDesc->isPrimitiveArray());
+
+  // Check pointer stuff.
+  // Global variables have no inline descriptor (yet).
+  ASSERT_TRUE(GlobalPtr.isRoot());
+  ASSERT_TRUE(GlobalPtr.isLive());
+  ASSERT_FALSE(GlobalPtr.isZero());
+  ASSERT_FALSE(GlobalPtr.isField());
+  ASSERT_TRUE(GlobalPtr.getFieldDesc() == GlobalPtr.getDeclDesc());
+  ASSERT_TRUE(GlobalPtr.getOffset() == 0);

[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-08-16 Thread Corentin Jabot via Phabricator via cfe-commits
cor3ntin added inline comments.



Comment at: clang/lib/AST/Interp/Context.h:88
+  /// Returns the program. This is only needed for unittests.
+  Program &getProgram() const { return *P.get(); }
+

This should return a const ref



Comment at: clang/lib/AST/Interp/Pointer.h:221
 }
+
 assert(Offset != Base && "not an array element");

WS only change



Comment at: clang/lib/AST/Interp/Pointer.h:342
+
+// narrow()ed element in a composite array.
+if (Base > 0 && Base == Offset)

Can you be a bit more verbose here? I can't figure out what is happening from 
the comment!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-08-16 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder updated this revision to Diff 550696.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158069/new/

https://reviews.llvm.org/D158069

Files:
  clang/lib/AST/Interp/Context.h
  clang/lib/AST/Interp/Pointer.h
  clang/unittests/AST/CMakeLists.txt
  clang/unittests/AST/Interp/CMakeLists.txt
  clang/unittests/AST/Interp/Descriptor.cpp

Index: clang/unittests/AST/Interp/Descriptor.cpp
===
--- /dev/null
+++ clang/unittests/AST/Interp/Descriptor.cpp
@@ -0,0 +1,385 @@
+#include "../../../lib/AST/Interp/Descriptor.h"
+#include "../../../lib/AST/Interp/Context.h"
+#include "../../../lib/AST/Interp/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;
+
+/// Inspect generated Descriptors as well as the pointers we create.
+///
+TEST(Descriptor, Primitives) {
+  constexpr char Code[] =
+  "struct A { bool a; bool b; };\n"
+  "struct S {\n"
+  "  float f;\n"
+  "  char s[4] = \"foo\";\n"
+  "  A a[3];\n"
+  "  short l[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};\n"
+  "};\n"
+  "constexpr S d{};";
+
+  auto AST = tooling::buildASTFromCodeWithArgs(
+  Code, {"-fexperimental-new-constant-interpreter"});
+
+  const VarDecl *D = selectFirst(
+  "d", match(varDecl().bind("d"), AST->getASTContext()));
+  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));
+
+  // Test Descriptor of the struct S.
+  const Descriptor *GlobalDesc = GlobalPtr.getFieldDesc();
+  ASSERT_TRUE(GlobalDesc == GlobalPtr.getDeclDesc());
+
+  ASSERT_TRUE(GlobalDesc->asDecl() == D);
+  ASSERT_FALSE(GlobalDesc->asExpr());
+  ASSERT_TRUE(GlobalDesc->asValueDecl() == D);
+  ASSERT_FALSE(GlobalDesc->asFieldDecl());
+  ASSERT_FALSE(GlobalDesc->asRecordDecl());
+
+  // Still true because this is a global variable.
+  ASSERT_TRUE(GlobalDesc->getMetadataSize() == 0);
+  ASSERT_FALSE(GlobalDesc->isPrimitiveArray());
+  ASSERT_FALSE(GlobalDesc->isCompositeArray());
+  ASSERT_FALSE(GlobalDesc->isZeroSizeArray());
+  ASSERT_FALSE(GlobalDesc->isUnknownSizeArray());
+  ASSERT_FALSE(GlobalDesc->isPrimitive());
+  ASSERT_FALSE(GlobalDesc->isArray());
+  ASSERT_TRUE(GlobalDesc->isRecord());
+
+  // Test the Record for the struct S.
+  const Record *SRecord = GlobalDesc->ElemRecord;
+  ASSERT_TRUE(SRecord);
+  ASSERT_TRUE(SRecord->getNumFields() == 4);
+  ASSERT_TRUE(SRecord->getNumBases() == 0);
+  ASSERT_FALSE(SRecord->getDestructor());
+
+  // First field.
+  const Record::Field *F1 = SRecord->getField(0u);
+  ASSERT_TRUE(F1);
+  ASSERT_FALSE(F1->isBitField());
+  ASSERT_TRUE(F1->Desc->isPrimitive());
+
+  // Second field.
+  const Record::Field *F2 = SRecord->getField(1u);
+  ASSERT_TRUE(F2);
+  ASSERT_FALSE(F2->isBitField());
+  ASSERT_TRUE(F2->Desc->isArray());
+  ASSERT_FALSE(F2->Desc->isCompositeArray());
+  ASSERT_TRUE(F2->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F2->Desc->isPrimitive());
+  ASSERT_FALSE(F2->Desc->ElemDesc);
+  ASSERT_EQ(F2->Desc->getNumElems(), 4u);
+  ASSERT_TRUE(F2->Desc->getElemSize() > 0);
+
+  // Third field.
+  const Record::Field *F3 = SRecord->getField(2u);
+  ASSERT_TRUE(F3);
+  ASSERT_FALSE(F3->isBitField());
+  ASSERT_TRUE(F3->Desc->isArray());
+  ASSERT_TRUE(F3->Desc->isCompositeArray());
+  ASSERT_FALSE(F3->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F3->Desc->isPrimitive());
+  ASSERT_TRUE(F3->Desc->ElemDesc);
+  ASSERT_EQ(F3->Desc->getNumElems(), 3u);
+  ASSERT_TRUE(F3->Desc->getElemSize() > 0);
+
+  // Fourth field.
+  // Multidimensional arrays are treated as composite arrays, even
+  // if the value type is primitive.
+  const Record::Field *F4 = SRecord->getField(3u);
+  ASSERT_TRUE(F4);
+  ASSERT_FALSE(F4->isBitField());
+  ASSERT_TRUE(F4->Desc->isArray());
+  ASSERT_TRUE(F4->Desc->isCompositeArray());
+  ASSERT_FALSE(F4->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F4->Desc->isPrimitive());
+  ASSERT_TRUE(F4->Desc->ElemDesc);
+  ASSERT_EQ(F4->Desc->getNumElems(), 3u);
+  ASSERT_TRUE(F4->Desc->getElemSize() > 0);
+  ASSERT_TRUE(F4->Desc->ElemDesc->isPrimitiveArray());
+
+  // Check pointer stuff.
+  // Global variables have no inline descriptor (yet).
+  ASSERT_TRUE(GlobalPtr.isRoot());
+  ASSERT_TRUE(GlobalPtr.isLive());
+  ASSERT_FALSE(GlobalPtr.isZero());
+  ASSERT_FALSE(GlobalPtr.isField());
+  ASSERT_TRUE(GlobalPtr.getFieldDesc() == GlobalPtr.getDeclDesc());
+  ASSERT_TRUE(GlobalPtr.getOffset() == 0);
+  ASSERT_FALSE(GlobalPtr.inArray());
+  ASSERT_FALSE(GlobalPtr.isArrayElement());
+  ASSERT_FALSE(GlobalPtr.

[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements

2023-08-16 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, shafik, cor3ntin.
Herald added subscribers: ChuanqiXu, arphaman.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158069

Files:
  clang/lib/AST/Interp/Context.h
  clang/lib/AST/Interp/Pointer.h
  clang/unittests/AST/CMakeLists.txt
  clang/unittests/AST/Interp/CMakeLists.txt
  clang/unittests/AST/Interp/Descriptor.cpp

Index: clang/unittests/AST/Interp/Descriptor.cpp
===
--- /dev/null
+++ clang/unittests/AST/Interp/Descriptor.cpp
@@ -0,0 +1,368 @@
+#include "../../../lib/AST/Interp/Descriptor.h"
+#include "../../../lib/AST/Interp/Context.h"
+#include "../../../lib/AST/Interp/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;
+
+/// Inspect generated Descriptors as well as the pointers we create.
+///
+TEST(Descriptor, Primitives) {
+  constexpr char Code[] =
+  "struct A { bool a; bool b; };\n"
+  "struct S {\n"
+  "  float f;\n"
+  "  char s[4] = \"foo\";\n"
+  "  A a[3];\n"
+  "  short l[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};\n"
+  "};\n"
+  "constexpr S d{};";
+
+  auto AST = tooling::buildASTFromCodeWithArgs(
+  Code, {"-fexperimental-new-constant-interpreter"});
+
+  const VarDecl *D = selectFirst(
+  "d", match(varDecl().bind("d"), AST->getASTContext()));
+  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));
+
+  // Test Descriptor of the struct S.
+  const Descriptor *GlobalDesc = GlobalPtr.getFieldDesc();
+  ASSERT_TRUE(GlobalDesc == GlobalPtr.getDeclDesc());
+
+  ASSERT_TRUE(GlobalDesc->asDecl() == D);
+  ASSERT_FALSE(GlobalDesc->asExpr());
+  ASSERT_TRUE(GlobalDesc->asValueDecl() == D);
+  ASSERT_FALSE(GlobalDesc->asFieldDecl());
+  ASSERT_FALSE(GlobalDesc->asRecordDecl());
+
+  // Still true because this is a global variable.
+  ASSERT_TRUE(GlobalDesc->getMetadataSize() == 0);
+  ASSERT_FALSE(GlobalDesc->isPrimitiveArray());
+  ASSERT_FALSE(GlobalDesc->isCompositeArray());
+  ASSERT_FALSE(GlobalDesc->isZeroSizeArray());
+  ASSERT_FALSE(GlobalDesc->isUnknownSizeArray());
+  ASSERT_FALSE(GlobalDesc->isPrimitive());
+  ASSERT_FALSE(GlobalDesc->isArray());
+  ASSERT_TRUE(GlobalDesc->isRecord());
+
+  // Test the Record for the struct S.
+  const Record *SRecord = GlobalDesc->ElemRecord;
+  ASSERT_TRUE(SRecord);
+  ASSERT_TRUE(SRecord->getNumFields() == 4);
+  ASSERT_TRUE(SRecord->getNumBases() == 0);
+  ASSERT_FALSE(SRecord->getDestructor());
+
+  // First field.
+  const Record::Field *F1 = SRecord->getField(0u);
+  ASSERT_TRUE(F1);
+  ASSERT_FALSE(F1->isBitField());
+  ASSERT_TRUE(F1->Desc->isPrimitive());
+
+  // Second field.
+  const Record::Field *F2 = SRecord->getField(1u);
+  ASSERT_TRUE(F2);
+  ASSERT_FALSE(F2->isBitField());
+  ASSERT_TRUE(F2->Desc->isArray());
+  ASSERT_FALSE(F2->Desc->isCompositeArray());
+  ASSERT_TRUE(F2->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F2->Desc->isPrimitive());
+  ASSERT_FALSE(F2->Desc->ElemDesc);
+  ASSERT_EQ(F2->Desc->getNumElems(), 4u);
+  ASSERT_TRUE(F2->Desc->getElemSize() > 0);
+
+  // Third field.
+  const Record::Field *F3 = SRecord->getField(2u);
+  ASSERT_TRUE(F3);
+  ASSERT_FALSE(F3->isBitField());
+  ASSERT_TRUE(F3->Desc->isArray());
+  ASSERT_TRUE(F3->Desc->isCompositeArray());
+  ASSERT_FALSE(F3->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F3->Desc->isPrimitive());
+  ASSERT_TRUE(F3->Desc->ElemDesc);
+  ASSERT_EQ(F3->Desc->getNumElems(), 3u);
+  ASSERT_TRUE(F3->Desc->getElemSize() > 0);
+
+  // Fourth field.
+  // Multidimensional arrays are treated as composite arrays, even
+  // if the value type is primitive.
+  const Record::Field *F4 = SRecord->getField(3u);
+  ASSERT_TRUE(F4);
+  ASSERT_FALSE(F4->isBitField());
+  ASSERT_TRUE(F4->Desc->isArray());
+  ASSERT_TRUE(F4->Desc->isCompositeArray());
+  ASSERT_FALSE(F4->Desc->isPrimitiveArray());
+  ASSERT_FALSE(F4->Desc->isPrimitive());
+  ASSERT_TRUE(F4->Desc->ElemDesc);
+  ASSERT_EQ(F4->Desc->getNumElems(), 3u);
+  ASSERT_TRUE(F4->Desc->getElemSize() > 0);
+  ASSERT_TRUE(F4->Desc->ElemDesc->isPrimitiveArray());
+
+  // Check pointer stuff.
+  // Global variables have no inline descriptor (yet).
+  ASSERT_TRUE(GlobalPtr.isRoot());
+  ASSERT_TRUE(GlobalPtr.isLive());
+  ASSERT_FALSE(GlobalPtr.isZero());
+  ASSERT_FALSE(GlobalPtr.isField());
+  AS