brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.2 KiB · 37e6f24 Raw
411 lines · cpp
1#include "../../../lib/AST/ByteCode/Descriptor.h"2#include "../../../lib/AST/ByteCode/Context.h"3#include "../../../lib/AST/ByteCode/Program.h"4#include "clang/AST/ASTContext.h"5#include "clang/AST/Decl.h"6#include "clang/ASTMatchers/ASTMatchFinder.h"7#include "clang/ASTMatchers/ASTMatchers.h"8#include "clang/Tooling/Tooling.h"9#include "gtest/gtest.h"10 11using namespace clang;12using namespace clang::interp;13using namespace clang::ast_matchers;14 15/// Inspect generated Descriptors as well as the pointers we create.16///17TEST(Descriptor, Primitives) {18  constexpr char Code[] = "struct A { bool a; bool b; };\n"19                          "struct S {\n"20                          "  float f;\n"21                          "  char s[4];\n"22                          "  A a[3];\n"23                          "  short l[3][3];\n"24                          "  int EmptyA[0];\n"25                          "};\n"26                          "constexpr S d = {0.0, \"foo\", {{true, false}, "27                          "{false, true}, {false, false}},\n"28                          "  {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, {}};\n";29 30  auto AST = tooling::buildASTFromCodeWithArgs(31      Code, {"-fexperimental-new-constant-interpreter"});32 33  const VarDecl *D = selectFirst<VarDecl>(34      "d", match(varDecl().bind("d"), AST->getASTContext()));35  ASSERT_NE(D, nullptr);36 37  const auto &Ctx = AST->getASTContext().getInterpContext();38  Program &Prog = Ctx.getProgram();39  // Global is registered.40  ASSERT_TRUE(Prog.getGlobal(D));41 42  // Get a Pointer to the global.43  const Pointer &GlobalPtr = Prog.getPtrGlobal(*Prog.getGlobal(D));44 45  // Test Descriptor of the struct S.46  const Descriptor *GlobalDesc = GlobalPtr.getFieldDesc();47  ASSERT_TRUE(GlobalDesc == GlobalPtr.getDeclDesc());48 49  ASSERT_TRUE(GlobalDesc->asDecl() == D);50  ASSERT_FALSE(GlobalDesc->asExpr());51  ASSERT_TRUE(GlobalDesc->asValueDecl() == D);52  ASSERT_FALSE(GlobalDesc->asFieldDecl());53  ASSERT_FALSE(GlobalDesc->asRecordDecl());54 55  // Still true because this is a global variable.56  ASSERT_TRUE(GlobalDesc->getMetadataSize() == sizeof(GlobalInlineDescriptor));57  ASSERT_FALSE(GlobalDesc->isPrimitiveArray());58  ASSERT_FALSE(GlobalDesc->isCompositeArray());59  ASSERT_FALSE(GlobalDesc->isZeroSizeArray());60  ASSERT_FALSE(GlobalDesc->isUnknownSizeArray());61  ASSERT_FALSE(GlobalDesc->isPrimitive());62  ASSERT_FALSE(GlobalDesc->isArray());63  ASSERT_TRUE(GlobalDesc->isRecord());64 65  // Test the Record for the struct S.66  const Record *SRecord = GlobalDesc->ElemRecord;67  ASSERT_TRUE(SRecord);68  ASSERT_TRUE(SRecord->getNumFields() == 5);69  ASSERT_TRUE(SRecord->getNumBases() == 0);70  ASSERT_FALSE(SRecord->getDestructor());71 72  // First field.73  const Record::Field *F1 = SRecord->getField(0u);74  ASSERT_TRUE(F1);75  ASSERT_FALSE(F1->isBitField());76  ASSERT_TRUE(F1->Desc->isPrimitive());77 78  // Second field.79  const Record::Field *F2 = SRecord->getField(1u);80  ASSERT_TRUE(F2);81  ASSERT_FALSE(F2->isBitField());82  ASSERT_TRUE(F2->Desc->isArray());83  ASSERT_FALSE(F2->Desc->isCompositeArray());84  ASSERT_TRUE(F2->Desc->isPrimitiveArray());85  ASSERT_FALSE(F2->Desc->isPrimitive());86  ASSERT_FALSE(F2->Desc->ElemDesc);87  ASSERT_EQ(F2->Desc->getNumElems(), 4u);88  ASSERT_TRUE(F2->Desc->getElemSize() > 0);89 90  // Third field.91  const Record::Field *F3 = SRecord->getField(2u);92  ASSERT_TRUE(F3);93  ASSERT_FALSE(F3->isBitField());94  ASSERT_TRUE(F3->Desc->isArray());95  ASSERT_TRUE(F3->Desc->isCompositeArray());96  ASSERT_FALSE(F3->Desc->isPrimitiveArray());97  ASSERT_FALSE(F3->Desc->isPrimitive());98  ASSERT_TRUE(F3->Desc->ElemDesc);99  ASSERT_EQ(F3->Desc->getNumElems(), 3u);100  ASSERT_TRUE(F3->Desc->getElemSize() > 0);101 102  // Fourth field.103  // Multidimensional arrays are treated as composite arrays, even104  // if the value type is primitive.105  const Record::Field *F4 = SRecord->getField(3u);106  ASSERT_TRUE(F4);107  ASSERT_FALSE(F4->isBitField());108  ASSERT_TRUE(F4->Desc->isArray());109  ASSERT_TRUE(F4->Desc->isCompositeArray());110  ASSERT_FALSE(F4->Desc->isPrimitiveArray());111  ASSERT_FALSE(F4->Desc->isPrimitive());112  ASSERT_TRUE(F4->Desc->ElemDesc);113  ASSERT_EQ(F4->Desc->getNumElems(), 3u);114  ASSERT_TRUE(F4->Desc->getElemSize() > 0);115  ASSERT_TRUE(F4->Desc->ElemDesc->isPrimitiveArray());116 117  // Fifth field. Zero-size array.118  const Record::Field *F5 = SRecord->getField(4u);119  ASSERT_TRUE(F5);120  ASSERT_FALSE(F5->isBitField());121  ASSERT_TRUE(F5->Desc->isArray());122  ASSERT_FALSE(F5->Desc->isCompositeArray());123  ASSERT_TRUE(F5->Desc->isPrimitiveArray());124  ASSERT_FALSE(F5->Desc->isPrimitive());125  ASSERT_EQ(F5->Desc->getNumElems(), 0u);126 127  // Check pointer stuff.128  // Global variables have an inline descriptor.129  ASSERT_TRUE(GlobalPtr.isRoot());130  ASSERT_TRUE(GlobalPtr.isLive());131  ASSERT_FALSE(GlobalPtr.isZero());132  ASSERT_FALSE(GlobalPtr.isField());133  ASSERT_TRUE(GlobalPtr.getFieldDesc() == GlobalPtr.getDeclDesc());134  ASSERT_TRUE(GlobalPtr.getOffset() == 0);135  ASSERT_FALSE(GlobalPtr.inArray());136  ASSERT_FALSE(GlobalPtr.isArrayElement());137  ASSERT_FALSE(GlobalPtr.isArrayRoot());138  ASSERT_FALSE(GlobalPtr.inPrimitiveArray());139  ASSERT_TRUE(GlobalPtr.isStatic());140  ASSERT_TRUE(GlobalPtr.isInitialized());141  ASSERT_FALSE(GlobalPtr.isOnePastEnd());142  ASSERT_FALSE(GlobalPtr.isElementPastEnd());143 144  // Pointer to the first field (a primitive).145  const Pointer &PF1 = GlobalPtr.atField(F1->Offset);146  ASSERT_TRUE(PF1.isLive());147  ASSERT_TRUE(PF1.isInitialized());148  ASSERT_TRUE(PF1.isField());149  ASSERT_FALSE(PF1.inArray());150  ASSERT_FALSE(PF1.isArrayElement());151  ASSERT_FALSE(PF1.isArrayRoot());152  ASSERT_FALSE(PF1.isOnePastEnd());153  ASSERT_FALSE(PF1.isRoot());154  ASSERT_TRUE(PF1.getFieldDesc()->isPrimitive());155  ASSERT_TRUE(Pointer::hasSameBase(PF1, GlobalPtr));156  ASSERT_TRUE(PF1.getBase() == GlobalPtr);157 158  // Pointer to the second field (a primitive array).159  const Pointer &PF2 = GlobalPtr.atField(F2->Offset);160  ASSERT_TRUE(PF2.isLive());161  ASSERT_TRUE(PF2.isInitialized());162  ASSERT_TRUE(PF2.isField());163  ASSERT_TRUE(PF2.inArray());164  ASSERT_FALSE(PF2.isArrayElement());165  ASSERT_TRUE(PF2.isArrayRoot());166  ASSERT_TRUE(PF2.getNumElems() == 4);167  ASSERT_FALSE(PF2.isOnePastEnd());168  ASSERT_FALSE(PF2.isRoot());169  ASSERT_FALSE(PF2.getFieldDesc()->isPrimitive());170  ASSERT_TRUE(PF2.getFieldDesc()->isArray());171  ASSERT_TRUE(Pointer::hasSameBase(PF2, GlobalPtr));172  ASSERT_TRUE(PF2.getBase() == GlobalPtr);173 174  // Check contents of field 2 (a primitive array).175  {176    const Pointer &E1 = PF2.atIndex(0);177    ASSERT_TRUE(E1.isLive());178    ASSERT_FALSE(E1.isArrayRoot());179    ASSERT_TRUE(E1.isArrayElement());180    ASSERT_TRUE(E1.inPrimitiveArray());181    ASSERT_TRUE(E1.deref<char>() == 'f');182    ASSERT_EQ(E1.getIndex(), 0u);183    ASSERT_TRUE(E1 == E1.atIndex(0));184    ASSERT_TRUE(Pointer::hasSameBase(E1, GlobalPtr));185 186    const Pointer &E2 = PF2.atIndex(1);187    ASSERT_TRUE(E2.isLive());188    ASSERT_FALSE(E2.isArrayRoot());189    ASSERT_TRUE(E2.isArrayElement());190    ASSERT_EQ(E2.getIndex(), 1u);191    // Narrow() doesn't do anything on primitive array elements, as there is192    // nothing to narrow into.193    ASSERT_EQ(E2.narrow(), E2);194    // ... so this should also hold.195    ASSERT_EQ(E2.expand(), E2);196    ASSERT_EQ(E2.narrow().expand(), E2);197 198    // .atIndex(1).atIndex(1) should be index 1.199    ASSERT_EQ(PF2.atIndex(1).atIndex(1), PF2.atIndex(1));200    ASSERT_EQ(PF2.atIndex(1).narrow().atIndex(1), PF2.atIndex(1));201 202    // getArray() should give us the array field again.203    ASSERT_EQ(E2.getArray(), PF2);204 205    // One-after-the-end pointer.206    const Pointer &O = PF2.atIndex(PF2.getNumElems());207    ASSERT_TRUE(O.isLive());208    ASSERT_TRUE(O.isOnePastEnd());209    ASSERT_TRUE(O.isInitialized());210    ASSERT_TRUE(O.getIndex() == PF2.getNumElems());211  }212 213  // Pointer to the third field (a composite array).214  const Pointer &PF3 = GlobalPtr.atField(F3->Offset);215  ASSERT_TRUE(PF3.isLive());216  ASSERT_TRUE(PF3.isInitialized());217  ASSERT_TRUE(PF3.isField());218  ASSERT_TRUE(PF3.inArray());219  ASSERT_TRUE(PF3.isArrayRoot());220  ASSERT_FALSE(PF3.isArrayElement());221  ASSERT_TRUE(PF3.getNumElems() == 3);222  ASSERT_FALSE(PF3.isOnePastEnd());223  ASSERT_FALSE(PF3.isRoot());224  ASSERT_FALSE(PF3.getFieldDesc()->isPrimitive());225  ASSERT_TRUE(PF3.getFieldDesc()->isArray());226  ASSERT_TRUE(Pointer::hasSameBase(PF3, GlobalPtr));227  ASSERT_TRUE(PF3.getBase() == GlobalPtr);228  ASSERT_EQ(PF3.getRecord(), nullptr);229  ASSERT_TRUE(PF3.getElemRecord());230 231  // Check contents of field 3 (a composite array).232  {233    const Pointer &E1 = PF3.atIndex(0);234    // Note that we didn't call narrow() above, so this points235    // to an array element and not just a field.236    ASSERT_TRUE(E1.isLive());237    ASSERT_EQ(E1.getIndex(), 0);238    ASSERT_TRUE(E1.isInitialized());239    ASSERT_TRUE(E1.isArrayElement());240    ASSERT_TRUE(E1.inArray());241    ASSERT_FALSE(E1.isArrayRoot());242    ASSERT_FALSE(E1.isRoot());243    ASSERT_EQ(E1.getArray(), PF3);244    ASSERT_TRUE(E1.isField());245    ASSERT_TRUE(E1.getElemRecord());246    ASSERT_FALSE(E1.getRecord());247 248    // Now the same with narrow().249    const Pointer &NE1 = PF3.atIndex(0).narrow();250    ASSERT_NE(E1, NE1);251    ASSERT_TRUE(NE1.isLive());252    ASSERT_EQ(NE1.getIndex(), 0);253    ASSERT_TRUE(NE1.isInitialized());254    ASSERT_TRUE(NE1.isArrayElement());255    ASSERT_TRUE(NE1.isField());256    ASSERT_FALSE(NE1.inArray());257    ASSERT_FALSE(NE1.isArrayRoot());258    ASSERT_FALSE(NE1.isRoot());259    // Not possible, since this is narrow()ed:260    // ASSERT_EQ(NE1.getArray(), PF3);261    ASSERT_EQ(NE1.expand(), E1);262    ASSERT_FALSE(NE1.getElemRecord());263    ASSERT_TRUE(NE1.getRecord());264 265    // Second element, NOT narrowed.266    const Pointer &E2 = PF3.atIndex(1);267    ASSERT_TRUE(E2.isLive());268    ASSERT_EQ(E2.getIndex(), 1);269    ASSERT_TRUE(E2.isInitialized());270    ASSERT_TRUE(E2.isArrayElement());271    ASSERT_TRUE(E2.isField());272    ASSERT_TRUE(E2.inArray());273    ASSERT_FALSE(E2.isArrayRoot());274    ASSERT_FALSE(E2.isRoot());275    ASSERT_EQ(E2.getArray(), PF3);276 277    // Second element, narrowed.278    const Pointer &NE2 = PF3.atIndex(1).narrow();279    ASSERT_TRUE(NE2.isLive());280    ASSERT_EQ(NE2.getIndex(), 0);281    ASSERT_TRUE(NE2.isInitialized());282    ASSERT_TRUE(NE2.isArrayElement());283    ASSERT_TRUE(NE2.isField());284    ASSERT_FALSE(NE2.inArray());285    ASSERT_FALSE(NE2.isArrayRoot());286    ASSERT_FALSE(NE2.isRoot());287    // Not possible, since this is narrow()ed:288    // ASSERT_EQ(NE2.getArray(), PF3);289    ASSERT_FALSE(NE2.getElemRecord());290    ASSERT_TRUE(NE2.getRecord());291 292    // Chained atIndex() without narrowing in between.293    ASSERT_EQ(PF3.atIndex(1).atIndex(1), PF3.atIndex(1));294 295    // First field of the second element.296    const Pointer &FP1 = NE2.atField(NE2.getRecord()->getField(0u)->Offset);297    ASSERT_TRUE(FP1.isLive());298    ASSERT_TRUE(FP1.isInitialized());299    ASSERT_EQ(FP1.getBase(), NE2);300    ASSERT_FALSE(FP1.isArrayElement());301    ASSERT_FALSE(FP1.inArray());302    ASSERT_FALSE(FP1.inPrimitiveArray());303    ASSERT_TRUE(FP1.isField());304 305    // One-past-the-end of a composite array.306    const Pointer &O = PF3.atIndex(PF3.getNumElems()).narrow();307    ASSERT_TRUE(O.isOnePastEnd());308    ASSERT_TRUE(O.isElementPastEnd());309  }310 311  // Pointer to the fourth field (a multidimensional primitive array).312  const Pointer &PF4 = GlobalPtr.atField(F4->Offset);313  ASSERT_TRUE(PF4.isLive());314  ASSERT_TRUE(PF4.isInitialized());315  ASSERT_TRUE(PF4.isField());316  ASSERT_TRUE(PF4.inArray());317  ASSERT_TRUE(PF4.isArrayRoot());318  ASSERT_FALSE(PF4.isArrayElement());319  ASSERT_TRUE(PF4.getNumElems() == 3);320  ASSERT_FALSE(PF4.isOnePastEnd());321  ASSERT_FALSE(PF4.isRoot());322  ASSERT_FALSE(PF4.getFieldDesc()->isPrimitive());323  ASSERT_TRUE(PF4.getFieldDesc()->isArray());324  ASSERT_TRUE(Pointer::hasSameBase(PF4, GlobalPtr));325  ASSERT_TRUE(PF4.getBase() == GlobalPtr);326  ASSERT_EQ(PF4.getRecord(), nullptr);327  ASSERT_EQ(PF4.getElemRecord(), nullptr);328  ASSERT_NE(PF4.getField(), nullptr);329  ASSERT_TRUE(PF4.getFieldDesc()->ElemDesc->isPrimitiveArray());330  // Check contents of field 4 (a primitive array).331  {332    // Pointer to the first element, is of type short[3].333    const Pointer &E1 = PF4.atIndex(0);334    ASSERT_NE(E1, PF4);335    ASSERT_TRUE(E1.isLive());336    ASSERT_TRUE(E1.isArrayElement());337    ASSERT_TRUE(E1.inArray());338    ASSERT_EQ(E1.getNumElems(), 3u);339    ASSERT_EQ(E1.getIndex(), 0u);340    ASSERT_EQ(E1.getArray(), PF4);341 342    // Now narrow()'ed.343    const Pointer &NE1 = PF4.atIndex(0).narrow();344    ASSERT_NE(NE1, PF4);345    ASSERT_NE(NE1, E1);346    ASSERT_TRUE(NE1.isLive());347    ASSERT_TRUE(NE1.isArrayElement());348    ASSERT_TRUE(NE1.isArrayRoot());349    ASSERT_FALSE(NE1.getFieldDesc()->isCompositeArray());350    ASSERT_TRUE(NE1.getFieldDesc()->isPrimitiveArray());351    ASSERT_EQ(NE1.getFieldDesc()->getNumElems(), 3u);352    ASSERT_TRUE(NE1.inArray());353    ASSERT_EQ(NE1.getNumElems(), 3u);354    ASSERT_EQ(NE1.getIndex(), 0u);355 356    // Last element of the first dimension.357    const Pointer &PE1 = PF4.atIndex(0).narrow().atIndex(2);358    ASSERT_TRUE(PE1.isLive());359    ASSERT_EQ(PE1.deref<short>(), 3);360    ASSERT_EQ(PE1.getArray(), NE1);361    ASSERT_EQ(PE1.getIndex(), 2u);362 363    // third dimension364    const Pointer &E3 = PF4.atIndex(2);365    ASSERT_NE(E3, PF4);366    ASSERT_TRUE(E3.isLive());367    ASSERT_TRUE(E3.isArrayElement());368    ASSERT_FALSE(E3.isArrayRoot());369    ASSERT_TRUE(E3.inArray());370    ASSERT_EQ(E3.getNumElems(), 3u);371    ASSERT_EQ(E3.getIndex(), 2u);372 373    // Same, but narrow()'ed.374    const Pointer &NE3 = PF4.atIndex(2).narrow();375    ASSERT_NE(NE3, PF4);376    ASSERT_NE(NE3, E1);377    ASSERT_TRUE(NE3.isLive());378    ASSERT_TRUE(NE3.isArrayElement());379    ASSERT_TRUE(NE3.isArrayRoot());380    ASSERT_FALSE(NE3.getFieldDesc()->isCompositeArray());381    ASSERT_TRUE(NE3.getFieldDesc()->isPrimitiveArray());382    ASSERT_EQ(NE3.getFieldDesc()->getNumElems(), 3u);383    ASSERT_TRUE(NE3.inArray());384    ASSERT_EQ(NE3.getNumElems(), 3u);385    // This is narrow()'ed, so not an "array elemnet"386    ASSERT_EQ(PF4.atIndex(2).getIndex(), 2u);387    ASSERT_EQ(NE3.getIndex(), 0u);388 389    // Last element of the last dimension390    const Pointer &PE3 = PF4.atIndex(2).narrow().atIndex(2);391    ASSERT_TRUE(PE3.isLive());392    ASSERT_EQ(PE3.deref<short>(), 9);393    ASSERT_EQ(PE3.getArray(), NE3);394    ASSERT_EQ(PE3.getIndex(), 2u);395  }396 397  // Zero-size array.398  {399    const Pointer &PF5 = GlobalPtr.atField(F5->Offset);400 401    ASSERT_TRUE(PF5.isZeroSizeArray());402    ASSERT_TRUE(PF5.isOnePastEnd());403    ASSERT_FALSE(PF5.isElementPastEnd());404 405    const Pointer &E1 = PF5.atIndex(0);406    (void)E1;407    ASSERT_TRUE(PF5.isOnePastEnd());408    ASSERT_FALSE(PF5.isElementPastEnd());409  }410}411