diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp index 6017f6dd61cb3..bcd9f6f3d078a 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -367,10 +367,12 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, } /// Arrays of composite elements. -Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD, +Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy, + const Descriptor *Elem, MetadataSize MD, unsigned NumElems, bool IsConst, bool IsTemporary, bool IsMutable) - : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)), + : Source(D), SourceType(SourceTy), + ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)), Size(ElemSize * NumElems), MDSize(MD.value_or(0)), AllocSize(std::max(alignof(void *), Size) + MDSize), ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable), @@ -410,6 +412,8 @@ Descriptor::Descriptor(const DeclTy &D) } QualType Descriptor::getType() const { + if (SourceType) + return QualType(SourceType, 0); if (const auto *D = asValueDecl()) return D->getType(); if (const auto *T = dyn_cast_if_present(asDecl())) diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h index 01fa4b198de67..b2e9f1b6bded4 100644 --- a/clang/lib/AST/ByteCode/Descriptor.h +++ b/clang/lib/AST/ByteCode/Descriptor.h @@ -124,6 +124,7 @@ struct Descriptor final { private: /// Original declaration, used to emit the error message. const DeclTy Source; + const Type *SourceType = nullptr; /// Size of an element, in host bytes. const unsigned ElemSize; /// Size of the storage, in host bytes. @@ -186,8 +187,9 @@ struct Descriptor final { bool IsTemporary, UnknownSize); /// Allocates a descriptor for an array of composites. - Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD, - unsigned NumElems, bool IsConst, bool IsTemporary, bool IsMutable); + Descriptor(const DeclTy &D, const Type *SourceTy, const Descriptor *Elem, + MetadataSize MD, unsigned NumElems, bool IsConst, bool IsTemporary, + bool IsMutable); /// Allocates a descriptor for an array of composites of unknown size. Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD, diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp b/clang/lib/AST/ByteCode/DynamicAllocator.cpp index 3ef8c2e1f3e7c..728bd75d7d141 100644 --- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp +++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp @@ -57,8 +57,10 @@ Block *DynamicAllocator::allocate(const Descriptor *ElementDesc, assert(ElementDesc->getMetadataSize() == 0); // Create a new descriptor for an array of the specified size and // element type. + // FIXME: Pass proper element type. const Descriptor *D = allocateDescriptor( - ElementDesc->asExpr(), ElementDesc, Descriptor::InlineDescMD, NumElements, + ElementDesc->asExpr(), nullptr, ElementDesc, Descriptor::InlineDescMD, + NumElements, /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false); return allocate(D, EvalID, AllocForm); } diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 0754e259b7cb3..cc2cfc9b03b41 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -419,7 +419,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, unsigned ElemSize = ElemDesc->getAllocSize() + sizeof(InlineDescriptor); if (std::numeric_limits::max() / ElemSize <= NumElems) return {}; - return allocateDescriptor(D, ElemDesc, MDSize, NumElems, IsConst, + return allocateDescriptor(D, Ty, ElemDesc, MDSize, NumElems, IsConst, IsTemporary, IsMutable); } } diff --git a/clang/unittests/AST/ByteCode/toAPValue.cpp b/clang/unittests/AST/ByteCode/toAPValue.cpp index cd62338ee23c1..ab567609f78e3 100644 --- a/clang/unittests/AST/ByteCode/toAPValue.cpp +++ b/clang/unittests/AST/ByteCode/toAPValue.cpp @@ -254,3 +254,69 @@ TEST(ToAPValue, MemberPointers) { ASSERT_EQ(A.getKind(), APValue::MemberPointer); } } + +/// Compare outputs between the two interpreters. +TEST(ToAPValue, Comparison) { + constexpr char Code[] = + "constexpr int GI = 12;\n" + "constexpr const int *PI = &GI;\n" + "struct S{int a; };\n" + "constexpr S GS[] = {{}, {}};\n" + "constexpr const S* OS = GS + 1;\n" + "constexpr S DS = *OS;\n" + "constexpr int IA[2][2][2] = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}};\n" + "constexpr const int *PIA = IA[1][1];\n"; + + for (const char *Arg : {"", "-fexperimental-new-constant-interpreter"}) { + auto AST = tooling::buildASTFromCodeWithArgs(Code, {Arg}); + + auto getDecl = [&](const char *Name) -> const VarDecl * { + auto Nodes = + match(valueDecl(hasName(Name)).bind("var"), AST->getASTContext()); + assert(Nodes.size() == 1); + const auto *D = Nodes[0].getNodeAs("var"); + assert(D); + return cast(D); + }; + + { + const VarDecl *GIDecl = getDecl("GI"); + const APValue *V = GIDecl->evaluateValue(); + ASSERT_TRUE(V->isInt()); + } + + { + const VarDecl *GIDecl = getDecl("GI"); + const VarDecl *PIDecl = getDecl("PI"); + const APValue *V = PIDecl->evaluateValue(); + ASSERT_TRUE(V->isLValue()); + ASSERT_TRUE(V->hasLValuePath()); + ASSERT_EQ(V->getLValueBase().get(), GIDecl); + ASSERT_EQ(V->getLValuePath().size(), 0u); + } + + { + const APValue *V = getDecl("OS")->evaluateValue(); + ASSERT_TRUE(V->isLValue()); + ASSERT_EQ(V->getLValueOffset().getQuantity(), (unsigned)sizeof(int)); + ASSERT_TRUE(V->hasLValuePath()); + ASSERT_EQ(V->getLValuePath().size(), 1u); + ASSERT_EQ(V->getLValuePath()[0].getAsArrayIndex(), 1u); + } + + { + const APValue *V = getDecl("DS")->evaluateValue(); + ASSERT_TRUE(V->isStruct()); + } + { + const APValue *V = getDecl("PIA")->evaluateValue(); + ASSERT_TRUE(V->isLValue()); + ASSERT_TRUE(V->hasLValuePath()); + ASSERT_EQ(V->getLValuePath().size(), 3u); + ASSERT_EQ(V->getLValuePath()[0].getAsArrayIndex(), 1u); + ASSERT_EQ(V->getLValuePath()[1].getAsArrayIndex(), 1u); + ASSERT_EQ(V->getLValuePath()[2].getAsArrayIndex(), 0u); + ASSERT_EQ(V->getLValueOffset().getQuantity(), (unsigned)sizeof(int) * 6); + } + } +}