[PATCH] D158069: [clang][Interp] Fix getIndex() for composite array elements
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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