Index: clang/include/clang/AST/APValue.h =================================================================== --- clang/include/clang/AST/APValue.h +++ clang/include/clang/AST/APValue.h @@ -185,6 +185,7 @@ friend class ASTReader; friend class ASTWriter; + friend class ASTImporter; private: ValueKind Kind; @@ -508,10 +509,13 @@ assert(isFixedPoint() && "Invalid accessor"); *(APFixedPoint *)(char *)Data.buffer = std::move(FX); } - void setVector(const APValue *E, unsigned N) { + void ReserveVector(unsigned N) { assert(isVector() && "Invalid accessor"); ((Vec*)(char*)Data.buffer)->Elts = new APValue[N]; ((Vec*)(char*)Data.buffer)->NumElts = N; + } + void setVector(const APValue *E, unsigned N) { + ReserveVector(N); for (unsigned i = 0; i != N; ++i) ((Vec*)(char*)Data.buffer)->Elts[i] = E[i]; } @@ -529,6 +533,13 @@ ((ComplexAPFloat *)(char *)Data.buffer)->Real = std::move(R); ((ComplexAPFloat *)(char *)Data.buffer)->Imag = std::move(I); } + +private: + void setLValueEmptyPath(LValueBase B, const CharUnits &O, unsigned Size, + bool OnePastTheEnd, bool IsNullPtr); + LValuePathEntry *getLValuePathPtr(); + +public: void setLValue(LValueBase B, const CharUnits &O, NoLValuePath, bool IsNullPtr); void setLValue(LValueBase B, const CharUnits &O, @@ -595,13 +606,16 @@ new ((void*)(char*)Data.buffer) UnionData(); Kind = Union; } + void MakeEmptyMemberPointer(const ValueDecl *Member, bool IsDerivedMember, + unsigned Size); void MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, - ArrayRef Path); + ArrayRef Path); void MakeAddrLabelDiff() { assert(isAbsent() && "Bad state change"); - new ((void*)(char*)Data.buffer) AddrLabelDiffData(); + new ((void *)(char *)Data.buffer) AddrLabelDiffData(); Kind = AddrLabelDiff; } + CXXRecordDecl **getMemberPointerPathPtr(); }; } // end namespace clang. Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -271,9 +271,6 @@ llvm::DenseMap MaterializedTemporaryValues; - /// Used to cleanups APValues stored in the AST. - mutable llvm::SmallVector APValueCleanups; - /// A cache mapping a string value to a StringLiteral object with the same /// value. /// Index: clang/include/clang/AST/ASTImporter.h =================================================================== --- clang/include/clang/AST/ASTImporter.h +++ clang/include/clang/AST/ASTImporter.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_ASTIMPORTER_H #define LLVM_CLANG_AST_ASTIMPORTER_H +#include "clang/AST/APValue.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" @@ -324,6 +325,13 @@ /// "to" context, or the import error. llvm::Expected Import(const CXXBaseSpecifier *FromSpec); + /// Import the gieven APValue from the "from" context into + /// the "to" context. + /// + /// \return the equivalent APValue in the "from" Constext or the import + /// error. + llvm::Expected Import(const APValue &FromValue); + /// Import the definition of the given declaration, including all of /// the declarations it contains. LLVM_NODISCARD llvm::Error ImportDefinition(Decl *From); Index: clang/include/clang/AST/Expr.h =================================================================== --- clang/include/clang/AST/Expr.h +++ clang/include/clang/AST/Expr.h @@ -954,6 +954,7 @@ public: /// Describes the kind of result that can be trail-allocated. + /// Enumerator need to stay ordered by size of there storage. enum ResultStorageKind { RSK_None, RSK_Int64, RSK_APValue }; private: Index: clang/include/clang/AST/TextNodeDumper.h =================================================================== --- clang/include/clang/AST/TextNodeDumper.h +++ clang/include/clang/AST/TextNodeDumper.h @@ -146,7 +146,7 @@ const comments::CommandTraits *Traits; - const ASTContext *Context; + const ASTContext *Context = nullptr; const char *getCommandName(unsigned CommandID); Index: clang/include/clang/Serialization/ASTReader.h =================================================================== --- clang/include/clang/Serialization/ASTReader.h +++ clang/include/clang/Serialization/ASTReader.h @@ -2221,7 +2221,7 @@ const llvm::fltSemantics &Sem, unsigned &Idx); /// Read an APValue - APValue ReadAPValue(const RecordData &Record, unsigned &Idx); + APValue ReadAPValue(ModuleFile &F, const RecordData &Record, unsigned &Idx); // Read a string static std::string ReadString(const RecordData &Record, unsigned &Idx); @@ -2615,7 +2615,7 @@ return Reader->ReadSourceRange(*F, Record, Idx); } - APValue readAPValue() { return Reader->ReadAPValue(Record, Idx); } + APValue readAPValue() { return Reader->ReadAPValue(*F, Record, Idx); } /// Read an integral value, advancing Idx. llvm::APInt readAPInt() { Index: clang/lib/AST/APValue.cpp =================================================================== --- clang/lib/AST/APValue.cpp +++ clang/lib/AST/APValue.cpp @@ -172,8 +172,8 @@ struct APValue::MemberPointerData : MemberPointerBase { static const unsigned InlinePathSpace = - (DataSize - sizeof(MemberPointerBase)) / sizeof(const CXXRecordDecl*); - typedef const CXXRecordDecl *PathElem; + (DataSize - sizeof(MemberPointerBase)) / sizeof(CXXRecordDecl *); + typedef CXXRecordDecl *PathElem; union { PathElem Path[InlinePathSpace]; PathElem *PathPtr; @@ -745,6 +745,10 @@ return ((const LV*)(const char*)Data.buffer)->IsNullPtr; } +APValue::LValuePathEntry *APValue::getLValuePathPtr() { + return ((LV *)(char *)Data.buffer)->getPath(); +} + void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath, bool IsNullPtr) { assert(isLValue() && "Invalid accessor"); @@ -756,17 +760,24 @@ LVal.IsNullPtr = IsNullPtr; } -void APValue::setLValue(LValueBase B, const CharUnits &O, - ArrayRef Path, bool IsOnePastTheEnd, - bool IsNullPtr) { +void APValue::setLValueEmptyPath(LValueBase B, const CharUnits &O, + unsigned Size, bool IsOnePastTheEnd, + bool IsNullPtr) { assert(isLValue() && "Invalid accessor"); - LV &LVal = *((LV*)(char*)Data.buffer); + LV &LVal = *((LV *)(char *)Data.buffer); LVal.Base = B; LVal.IsOnePastTheEnd = IsOnePastTheEnd; LVal.Offset = O; - LVal.resizePath(Path.size()); - memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry)); LVal.IsNullPtr = IsNullPtr; + LVal.resizePath(Size); +} + +void APValue::setLValue(LValueBase B, const CharUnits &O, + ArrayRef Path, bool IsOnePastTheEnd, + bool IsNullPtr) { + setLValueEmptyPath(B, O, Path.size(), IsOnePastTheEnd, IsNullPtr); + memcpy(((LV *)(char *)Data.buffer)->getPath(), Path.data(), + Path.size() * sizeof(LValuePathEntry)); } const ValueDecl *APValue::getMemberPointerDecl() const { @@ -803,13 +814,23 @@ Kind = Array; } -void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, - ArrayRef Path) { +void APValue::MakeEmptyMemberPointer(const ValueDecl *Member, + bool IsDerivedMember, unsigned Size) { assert(isAbsent() && "Bad state change"); MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData; Kind = MemberPointer; MPD->MemberAndIsDerivedMember.setPointer(Member); MPD->MemberAndIsDerivedMember.setInt(IsDerivedMember); - MPD->resizePath(Path.size()); - memcpy(MPD->getPath(), Path.data(), Path.size()*sizeof(const CXXRecordDecl*)); + MPD->resizePath(Size); +} + +void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, + ArrayRef Path) { + MakeEmptyMemberPointer(Member, IsDerivedMember, Path.size()); + memcpy(((MemberPointerData *)(char *)Data.buffer)->getPath(), Path.data(), + Path.size() * sizeof(const CXXRecordDecl *)); +} + +CXXRecordDecl **APValue::getMemberPointerPathPtr() { + return ((MemberPointerData *)(char *)Data.buffer)->getPath(); } Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -827,9 +827,6 @@ for (const auto &Value : ModuleInitializers) Value.second->~PerModuleInitializers(); - - for (APValue *Value : APValueCleanups) - Value->~APValue(); } class ASTContext::ParentMap { Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -6369,21 +6369,15 @@ } ExpectedStmt ASTNodeImporter::VisitConstantExpr(ConstantExpr *E) { - auto Imp = importSeq(E->getSubExpr()); + auto Imp = importSeq(E->getSubExpr(), E->getAPValueResult()); if (!Imp) return Imp.takeError(); Expr *ToSubExpr; - std::tie(ToSubExpr) = *Imp; + APValue ToResult; + std::tie(ToSubExpr, ToResult) = *Imp; - // TODO : Handle APValue::ValueKind that require importing. - APValue::ValueKind Kind = E->getResultAPValueKind(); - if (Kind == APValue::Int || Kind == APValue::Float || - Kind == APValue::FixedPoint || Kind == APValue::ComplexFloat || - Kind == APValue::ComplexInt) - return ConstantExpr::Create(Importer.getToContext(), ToSubExpr, - E->getAPValueResult()); - return ConstantExpr::Create(Importer.getToContext(), ToSubExpr); + return ConstantExpr::Create(Importer.getToContext(), ToSubExpr, ToResult); } ExpectedStmt ASTNodeImporter::VisitParenExpr(ParenExpr *E) { @@ -8506,6 +8500,195 @@ return ToContext.Selectors.getSelector(FromSel.getNumArgs(), Idents.data()); } +llvm::Expected ASTImporter::Import(const APValue &FromValue) { + APValue Result; + llvm::Error Error = llvm::Error::success(); + auto ImportLoop = [&](const APValue *From, APValue *To, unsigned Size) { + for (unsigned Idx = 0; Idx < Size; Idx++) { + llvm::Expected Tmp = Import(From[Idx]); + if (!Tmp) { + Error = Tmp.takeError(); + return; + } + To[Idx] = std::move(Tmp.get()); + } + }; + switch (FromValue.getKind()) { + case APValue::None: + case APValue::Indeterminate: + case APValue::Int: + case APValue::Float: + case APValue::FixedPoint: + case APValue::ComplexInt: + case APValue::ComplexFloat: + Result = FromValue; + break; + case APValue::Vector: + Result.MakeVector(); + Result.ReserveVector(FromValue.getVectorLength()); + ImportLoop( + ((const APValue::Vec *)(const char *)FromValue.Data.buffer)->Elts, + ((const APValue::Vec *)(const char *)Result.Data.buffer)->Elts, + FromValue.getVectorLength()); + break; + case APValue::Array: + Result.MakeArray(FromValue.getArrayInitializedElts(), + FromValue.getArraySize()); + ImportLoop( + ((const APValue::Arr *)(const char *)FromValue.Data.buffer)->Elts, + ((const APValue::Arr *)(const char *)Result.Data.buffer)->Elts, + FromValue.getArrayInitializedElts()); + break; + case APValue::Struct: + Result.MakeStruct(FromValue.getStructNumBases(), + FromValue.getStructNumFields()); + ImportLoop( + ((const APValue::StructData *)(const char *)FromValue.Data.buffer) + ->Elts, + ((const APValue::StructData *)(const char *)Result.Data.buffer)->Elts, + FromValue.getStructNumBases() + FromValue.getStructNumFields()); + break; + case APValue::Union: { + Result.MakeUnion(); + auto ImpFDecl = Import(FromValue.getUnionField()); + if (!ImpFDecl) { + Error = ImpFDecl.takeError(); + break; + } + auto ImpValue = Import(FromValue.getUnionValue()); + if (!ImpValue) { + Error = ImpValue.takeError(); + break; + } + Result.setUnion(cast(ImpFDecl.get()), ImpValue.get()); + break; + } + case APValue::AddrLabelDiff: { + Result.MakeAddrLabelDiff(); + auto ImpLHS = + Import(const_cast(FromValue.getAddrLabelDiffLHS())); + if (!ImpLHS) { + Error = ImpLHS.takeError(); + break; + } + auto ImpRHS = + Import(const_cast(FromValue.getAddrLabelDiffRHS())); + if (!ImpRHS) { + Error = ImpRHS.takeError(); + break; + } + Result.setAddrLabelDiff(cast(ImpLHS.get()), + cast(ImpRHS.get())); + break; + } + case APValue::MemberPointer: { + auto ImpMemPtrDecl = Import(FromValue.getMemberPointerDecl()); + if (!ImpMemPtrDecl) { + Error = ImpMemPtrDecl.takeError(); + break; + } + Result.MakeEmptyMemberPointer(cast(ImpMemPtrDecl.get()), + FromValue.isMemberPointerToDerivedMember(), + FromValue.getMemberPointerPath().size()); + llvm::ArrayRef FromPath = + Result.getMemberPointerPath(); + CXXRecordDecl **ToPath = Result.getMemberPointerPathPtr(); + for (unsigned Idx = 0; Idx < FromValue.getMemberPointerPath().size(); + Idx++) { + auto ImpDecl = Import(FromPath[Idx]); + if (!ImpDecl) { + Error = ImpDecl.takeError(); + break; + } + ToPath[Idx] = cast(const_cast(ImpDecl.get())); + } + break; + } + case APValue::LValue: + APValue::LValueBase Base; + QualType FromElemTy; + if (FromValue.getLValueBase()) { + if (!FromValue.getLValueBase().is()) { + if (auto *E = FromValue.getLValueBase().dyn_cast()) { + FromElemTy = E->getType(); + auto ImpExpr = Import(const_cast(E)); + if (!ImpExpr) { + Error = ImpExpr.takeError(); + break; + } + Base = APValue::LValueBase(ImpExpr.get(), + FromValue.getLValueBase().getCallIndex(), + FromValue.getLValueBase().getVersion()); + } else { + FromElemTy = + FromValue.getLValueBase().get()->getType(); + auto ImpDecl = + Import(FromValue.getLValueBase().get()); + if (!ImpDecl) { + Error = ImpDecl.takeError(); + break; + } + Base = APValue::LValueBase(cast(ImpDecl.get()), + FromValue.getLValueBase().getCallIndex(), + FromValue.getLValueBase().getVersion()); + } + } else { + FromElemTy = FromValue.getLValueBase().getTypeInfoType(); + auto ImpTypeInfo = Import(QualType( + FromValue.getLValueBase().get().getType(), 0)); + if (!ImpTypeInfo) { + Error = ImpTypeInfo.takeError(); + break; + } + auto ImpType = Import(FromValue.getLValueBase().getTypeInfoType()); + if (!ImpType) { + Error = ImpType.takeError(); + break; + } + Base = APValue::LValueBase::getTypeInfo( + TypeInfoLValue(ImpTypeInfo.get().getTypePtr()), ImpType.get()); + } + } + CharUnits Offset = FromValue.getLValueOffset(); + unsigned PathLength = FromValue.getLValuePath().size(); + Result.MakeLValue(); + if (FromValue.hasLValuePath()) { + Result.setLValueEmptyPath(Base, Offset, PathLength, + FromValue.isLValueOnePastTheEnd(), + FromValue.isNullPointer()); + llvm::ArrayRef FromPath = + FromValue.getLValuePath(); + APValue::LValuePathEntry *ToPath = Result.getLValuePathPtr(); + for (unsigned LoopIdx = 0; LoopIdx < PathLength; LoopIdx++) { + if (FromElemTy->getAs()) { + const Decl *FromDecl = + FromPath[LoopIdx].getAsBaseOrMember().getPointer(); + auto ImpDecl = Import(FromDecl); + if (!ImpDecl) { + Error = ImpDecl.takeError(); + break; + } + if (auto *RD = dyn_cast(FromDecl)) + FromElemTy = FromContext.getRecordType(RD); + else + FromElemTy = cast(FromDecl)->getType(); + ToPath[LoopIdx] = APValue::LValuePathEntry(APValue::BaseOrMemberType( + ImpDecl.get(), FromPath[LoopIdx].getAsBaseOrMember().getInt())); + } else { + FromElemTy = FromContext.getAsArrayType(FromElemTy)->getElementType(); + ToPath[LoopIdx] = APValue::LValuePathEntry::ArrayIndex( + FromPath[LoopIdx].getAsArrayIndex()); + } + } + } else + Result.setLValue(Base, Offset, APValue::NoLValuePath{}, + FromValue.isNullPointer()); + } + if (Error) + return std::move(Error); + return Result; +} + DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name, DeclContext *DC, unsigned IDNS, Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -2347,6 +2347,11 @@ else if (Eval->Evaluated.needsCleanup()) getASTContext().addDestruction(&Eval->Evaluated); + if (auto *ConstantInit = dyn_cast(Eval->Value)) + if (ConstantExpr::getStorageKind(Eval->Evaluated) <= + ConstantInit->getResultStorageKind()) + ConstantInit->SetResult(Eval->Evaluated, getASTContext()); + Eval->IsEvaluating = false; Eval->WasEvaluated = true; Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -260,8 +260,10 @@ void ConstantExpr::DefaultInit(ResultStorageKind StorageKind) { ConstantExprBits.ResultKind = StorageKind; ConstantExprBits.APValueKind = APValue::None; + ConstantExprBits.BitWidth = 0; + ConstantExprBits.IsUnsigned = false; ConstantExprBits.HasCleanup = false; - if (StorageKind == ConstantExpr::RSK_APValue) + if (StorageKind == RSK_APValue) ::new (getTrailingObjects()) APValue(); } @@ -278,8 +280,7 @@ StorageKind == ConstantExpr::RSK_APValue, StorageKind == ConstantExpr::RSK_Int64); void *Mem = Context.Allocate(Size, alignof(ConstantExpr)); - ConstantExpr *Self = new (Mem) ConstantExpr(E, StorageKind); - return Self; + return new (Mem) ConstantExpr(E, StorageKind); } ConstantExpr *ConstantExpr::Create(const ASTContext &Context, Expr *E, @@ -308,9 +309,11 @@ } void ConstantExpr::MoveIntoResult(APValue &Value, const ASTContext &Context) { - assert(getStorageKind(Value) == ConstantExprBits.ResultKind && + assert(getStorageKind(Value) <= ConstantExprBits.ResultKind && "Invalid storage for this value kind"); ConstantExprBits.APValueKind = Value.getKind(); + if (!Value.hasValue()) + return; switch (ConstantExprBits.ResultKind) { case RSK_None: return; Index: clang/lib/AST/TextNodeDumper.cpp =================================================================== --- clang/lib/AST/TextNodeDumper.cpp +++ clang/lib/AST/TextNodeDumper.cpp @@ -685,10 +685,13 @@ } void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) { - if (Node->getResultAPValueKind() != APValue::None) { + if (Node->getResultStorageKind() != ConstantExpr::RSK_None) { ColorScope Color(OS, ShowColors, ValueColor); OS << " "; - Node->getAPValueResult().printPretty(OS, *Context, Node->getType()); + if (Context) + Node->getAPValueResult().printPretty(OS, *Context, Node->getType()); + else + Node->getAPValueResult().dump(OS); } } Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -11287,6 +11287,12 @@ FSI->markSafeWeakUse(Init); } + if (VDecl->isConstexpr()) { + Init = ConstantExpr::Create( + Context, Init, + ConstantExpr::getStorageKind(VDecl->getType()->getAs(), Context)); + } + // The initialization is usually a full-expression. // // FIXME: If this is a braced initialization of an aggregate, it is not Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -9115,45 +9115,152 @@ HasUnsignedPadding); } -APValue ASTReader::ReadAPValue(const RecordData &Record, unsigned &Idx) { - unsigned Kind = Record[Idx++]; +APValue ASTReader::ReadAPValue(ModuleFile &F, const RecordData &Record, + unsigned &RecordIdx) { + auto Kind = static_cast(Record[RecordIdx++]); switch (Kind) { case APValue::None: return APValue(); case APValue::Indeterminate: return APValue::IndeterminateValue(); case APValue::Int: - return APValue(ReadAPSInt(Record, Idx)); + return APValue(ReadAPSInt(Record, RecordIdx)); case APValue::Float: { const llvm::fltSemantics &FloatSema = llvm::APFloatBase::EnumToSemantics( - static_cast(Record[Idx++])); - return APValue(ReadAPFloat(Record, FloatSema, Idx)); + static_cast(Record[RecordIdx++])); + return APValue(ReadAPFloat(Record, FloatSema, RecordIdx)); } case APValue::FixedPoint: { - FixedPointSemantics FPSema = ReadFixedPointSemantics(Record, Idx); - return APValue(APFixedPoint(ReadAPInt(Record, Idx), FPSema)); + FixedPointSemantics FPSema = ReadFixedPointSemantics(Record, RecordIdx); + return APValue(APFixedPoint(ReadAPInt(Record, RecordIdx), FPSema)); } case APValue::ComplexInt: { - llvm::APSInt First = ReadAPSInt(Record, Idx); - return APValue(std::move(First), ReadAPSInt(Record, Idx)); + llvm::APSInt First = ReadAPSInt(Record, RecordIdx); + return APValue(std::move(First), ReadAPSInt(Record, RecordIdx)); } case APValue::ComplexFloat: { const llvm::fltSemantics &FloatSema1 = llvm::APFloatBase::EnumToSemantics( - static_cast(Record[Idx++])); - llvm::APFloat First = ReadAPFloat(Record, FloatSema1, Idx); + static_cast(Record[RecordIdx++])); + llvm::APFloat First = ReadAPFloat(Record, FloatSema1, RecordIdx); const llvm::fltSemantics &FloatSema2 = llvm::APFloatBase::EnumToSemantics( - static_cast(Record[Idx++])); - return APValue(std::move(First), ReadAPFloat(Record, FloatSema2, Idx)); - } - case APValue::LValue: - case APValue::Vector: - case APValue::Array: - case APValue::Struct: - case APValue::Union: - case APValue::MemberPointer: - case APValue::AddrLabelDiff: - // TODO : Handle all these APValue::ValueKind. - return APValue(); + static_cast(Record[RecordIdx++])); + return APValue(std::move(First), + ReadAPFloat(Record, FloatSema2, RecordIdx)); + } + case APValue::Vector: { + APValue Result; + Result.MakeVector(); + unsigned Length = Record[RecordIdx++]; + Result.ReserveVector(Length); + for (unsigned LoopIdx = 0; LoopIdx < Length; LoopIdx++) + Result.getVectorElt(LoopIdx) = ReadAPValue(F, Record, RecordIdx); + return Result; + } + case APValue::Array: { + APValue Result; + unsigned InitLength = Record[RecordIdx++]; + unsigned TotalLength = Record[RecordIdx++]; + Result.MakeArray(InitLength, TotalLength); + for (unsigned LoopIdx = 0; LoopIdx < InitLength; LoopIdx++) + Result.getArrayInitializedElt(LoopIdx) = + ReadAPValue(F, Record, RecordIdx); + return Result; + } + case APValue::Struct: { + APValue Result; + unsigned BasesLength = Record[RecordIdx++]; + unsigned FieldsLength = Record[RecordIdx++]; + Result.MakeStruct(BasesLength, FieldsLength); + for (unsigned LoopIdx = 0; LoopIdx < BasesLength; LoopIdx++) + Result.getStructBase(LoopIdx) = ReadAPValue(F, Record, RecordIdx); + for (unsigned LoopIdx = 0; LoopIdx < FieldsLength; LoopIdx++) + Result.getStructField(LoopIdx) = ReadAPValue(F, Record, RecordIdx); + return Result; + } + case APValue::Union: { + FieldDecl *FDecl = + cast(GetDecl(ReadDeclID(F, Record, RecordIdx))); + APValue Value = ReadAPValue(F, Record, RecordIdx); + return APValue(FDecl, Value); + } + case APValue::AddrLabelDiff: { + AddrLabelExpr *LHS = cast(ReadExpr(F)); + AddrLabelExpr *RHS = cast(ReadExpr(F)); + return APValue(LHS, RHS); + } + case APValue::MemberPointer: { + APValue Result; + bool IsDerived = Record[RecordIdx++]; + ValueDecl *Member = + cast(GetDecl(ReadDeclID(F, Record, RecordIdx))); + unsigned PathSize = Record[RecordIdx++]; + Result.MakeEmptyMemberPointer(Member, IsDerived, PathSize); + CXXRecordDecl **PathArray = Result.getMemberPointerPathPtr(); + for (unsigned LoopIdx = 0; LoopIdx < PathSize; LoopIdx++) + PathArray[LoopIdx] = + cast(GetDecl(ReadDeclID(F, Record, RecordIdx))); + return Result; + } + case APValue::LValue: { + uint64_t tmp = Record[RecordIdx++]; + bool hasLValuePath = tmp & 0x1; + bool isLValueOnePastTheEnd = tmp & 0x2; + bool isExpr = tmp & 0x4; + bool isTypeInfo = tmp & 0x8; + bool isNullPtr = tmp & 0x10; + bool hasBase = tmp & 0x20; + APValue::LValueBase Base; + QualType ElemTy; + assert(!isExpr || !isTypeInfo && "LValueBase cannot be both"); + if (hasBase) { + if (!isTypeInfo) { + unsigned CallIndex = Record[RecordIdx++]; + unsigned Version = Record[RecordIdx++]; + if (isExpr) { + Base = APValue::LValueBase(ReadExpr(F), CallIndex, Version); + ElemTy = Base.get()->getType(); + } else { + Base = APValue::LValueBase( + cast(GetDecl(ReadDeclID(F, Record, RecordIdx))), + CallIndex, Version); + ElemTy = Base.get()->getType(); + } + } else { + QualType TypeInfo = readType(F, Record, RecordIdx); + QualType Type = readType(F, Record, RecordIdx); + Base = APValue::LValueBase::getTypeInfo( + TypeInfoLValue(TypeInfo.getTypePtr()), Type); + Base.getTypeInfoType(); + } + } + CharUnits Offset = CharUnits::fromQuantity(Record[RecordIdx++]); + unsigned PathLength = Record[RecordIdx++]; + APValue Result; + Result.MakeLValue(); + if (hasLValuePath) { + Result.setLValueEmptyPath(Base, Offset, PathLength, isLValueOnePastTheEnd, + isNullPtr); + APValue::LValuePathEntry *Path = Result.getLValuePathPtr(); + for (unsigned LoopIdx = 0; LoopIdx < PathLength; LoopIdx++) { + if (ElemTy->getAs()) { + unsigned Int = Record[RecordIdx++]; + Decl *D = GetDecl(ReadDeclID(F, Record, RecordIdx)); + if (CXXRecordDecl *RD = dyn_cast(D)) + ElemTy = ContextObj->getRecordType(RD); + else + ElemTy = cast(D)->getType(); + Path[LoopIdx] = + APValue::LValuePathEntry(APValue::BaseOrMemberType(D, Int)); + } else { + ElemTy = ContextObj->getAsArrayType(ElemTy)->getElementType(); + Path[LoopIdx] = + APValue::LValuePathEntry::ArrayIndex(Record[RecordIdx++]); + } + } + } else + Result.setLValue(Base, Offset, APValue::NoLValuePath{}, isNullPtr); + return Result; + } } llvm_unreachable("Invalid APValue::ValueKind"); } @@ -10883,18 +10990,6 @@ break; } - if (FirstInit && SecondInit && - ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { - ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), - VarDifferentInitializer) - << FirstName << FirstInit->getSourceRange(); - ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), - VarDifferentInitializer) - << SecondName << SecondInit->getSourceRange(); - Diagnosed = true; - break; - } - const bool FirstIsConstexpr = FirstVD->isConstexpr(); const bool SecondIsConstexpr = SecondVD->isConstexpr(); if (FirstIsConstexpr != SecondIsConstexpr) { @@ -10907,6 +11002,19 @@ Diagnosed = true; break; } + + if (FirstInit && SecondInit && + ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarDifferentInitializer) + << FirstName << FirstInit->getSourceRange(); + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarDifferentInitializer) + << SecondName << SecondInit->getSourceRange(); + Diagnosed = true; + break; + } + break; } case Friend: { Index: clang/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- clang/lib/Serialization/ASTReaderStmt.cpp +++ clang/lib/Serialization/ASTReaderStmt.cpp @@ -540,10 +540,11 @@ uint64_t tmp = Record.readInt(); E->ConstantExprBits.IsUnsigned = tmp & 0x1; E->ConstantExprBits.BitWidth = tmp >> 1; + E->ConstantExprBits.APValueKind = APValue::Int; break; } case ConstantExpr::RSK_APValue: - E->APValueResult() = Record.readAPValue(); + E->SetResult(Record.readAPValue(), Record.getContext()); } E->setSubExpr(Record.readSubExpr()); } Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -5441,20 +5441,98 @@ AddAPFloat(Value.getComplexFloatImag()); return; } - case APValue::LValue: case APValue::Vector: + push_back(Value.getVectorLength()); + for (unsigned Idx = 0; Idx < Value.getVectorLength(); Idx++) + AddAPValue(Value.getVectorElt(Idx)); + return; case APValue::Array: + push_back(Value.getArrayInitializedElts()); + push_back(Value.getArraySize()); + for (unsigned Idx = 0; Idx < Value.getArrayInitializedElts(); Idx++) + AddAPValue(Value.getArrayInitializedElt(Idx)); + return; case APValue::Struct: + push_back(Value.getStructNumBases()); + push_back(Value.getStructNumFields()); + for (unsigned Idx = 0; Idx < Value.getStructNumBases(); Idx++) + AddAPValue(Value.getStructBase(Idx)); + for (unsigned Idx = 0; Idx < Value.getStructNumFields(); Idx++) + AddAPValue(Value.getStructField(Idx)); + return; case APValue::Union: - case APValue::MemberPointer: + AddDeclRef(Value.getUnionField()); + AddAPValue(Value.getUnionValue()); + return; case APValue::AddrLabelDiff: - // TODO : Handle all these APValue::ValueKind. + AddStmt(const_cast(Value.getAddrLabelDiffLHS())); + AddStmt(const_cast(Value.getAddrLabelDiffRHS())); + return; + case APValue::MemberPointer: { + push_back(Value.isMemberPointerToDerivedMember()); + AddDeclRef(Value.getMemberPointerDecl()); + ArrayRef RecordPath = Value.getMemberPointerPath(); + push_back(RecordPath.size()); + for (auto Elem : RecordPath) + AddDeclRef(Elem); + return; + } + case APValue::LValue: { + uint64_t tmp = Value.hasLValuePath() | Value.isLValueOnePastTheEnd() << 1 | + Value.getLValueBase().is() << 2 | + Value.getLValueBase().is() << 3 | + Value.isNullPointer() << 4 | + static_cast(Value.getLValueBase()) << 5; + push_back(tmp); + QualType ElemTy; + if (Value.getLValueBase()) { + if (!Value.getLValueBase().is()) { + push_back(Value.getLValueBase().getCallIndex()); + push_back(Value.getLValueBase().getVersion()); + if (auto *E = Value.getLValueBase().dyn_cast()) { + AddStmt(const_cast(E)); + ElemTy = E->getType(); + } else { + AddDeclRef(Value.getLValueBase().get()); + ElemTy = Value.getLValueBase().get()->getType(); + } + } else { + AddTypeRef( + QualType(Value.getLValueBase().get().getType(), 0)); + AddTypeRef(Value.getLValueBase().getTypeInfoType()); + ElemTy = Value.getLValueBase().getTypeInfoType(); + } + } + push_back(Value.getLValueOffset().getQuantity()); + push_back(Value.getLValuePath().size()); + if (Value.hasLValuePath()) { + ArrayRef Path = Value.getLValuePath(); + for (auto Elem : Path) { + if (ElemTy->getAs()) { + push_back(Elem.getAsBaseOrMember().getInt()); + const Decl *BaseOrMember = Elem.getAsBaseOrMember().getPointer(); + if (const CXXRecordDecl *RD = dyn_cast(BaseOrMember)) { + AddDeclRef(RD); + ElemTy = Writer->Context->getRecordType(RD); + } else { + const ValueDecl *VD = cast(BaseOrMember); + AddDeclRef(VD); + ElemTy = VD->getType(); + } + } else { + push_back(Elem.getAsArrayIndex()); + ElemTy = Writer->Context->getAsArrayType(ElemTy)->getElementType(); + } + } + } + } return; } llvm_unreachable("Invalid APValue::ValueKind"); } -void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record) { +void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, + RecordDataImpl &Record) { Record.push_back(getIdentifierRef(II)); } Index: clang/test/ASTMerge/APValue/Inputs/APValue.cpp =================================================================== --- /dev/null +++ clang/test/ASTMerge/APValue/Inputs/APValue.cpp @@ -0,0 +1,165 @@ + +// RUN: %clang_cc1 -std=gnu++2a -emit-pch %s -o %t.pch +// RUN: %clang_cc1 -std=gnu++2a -x c++ -include-pch %t.pch -ast-dump-all | FileCheck %s + +#ifndef EMIT +#define EMIT + +namespace Integer { + +constexpr int Unique_Int = int(6789); + +constexpr __uint128_t Unique_Int128 = ((__uint128_t)0x75f17d6b3588f843 << 64) | 0xb13dea7c9c324e51; + +} + +namespace FloatingPoint { + +constexpr double Unique_Double = double(567890.67890); + +} + +// FIXME: Add test for FixePoint, ComplexInt, ComplexFloat, AddrLabelDiff. + +namespace Struct { + +struct B { + int i; + double d; +}; + +constexpr B Basic_Struct = B{1, 0.7}; + +struct C { + int i = 9; +}; + +struct A : B { + int i; + double d; + C c; +}; + +constexpr A Advanced_Struct = A{Basic_Struct, 1, 79.789, {}}; + +} + +namespace Vector { + +using v4si = int __attribute__((__vector_size__(16))); + +constexpr v4si Vector_Int = (v4si){8, 2, 3}; + +} + +namespace Array { + +constexpr int Array_Int[] = {1, 2, 3, 4, 5, 6}; + +struct A { + int i = 789; + double d = 67890.09876; +}; + +constexpr A Array2_Struct[][3] = {{{}, {-45678, 9.8}, {9}}, {{}}}; + +using v4si = int __attribute__((__vector_size__(16))); + +constexpr v4si Array_Vector[] = {{1, 2, 3, 4}, {4, 5, 6, 7}}; + +} + +namespace Union { + +struct A { + int i = 6789; + float f = 987.9876; +}; + +union U { + int i; + A a{567890, 9876.5678f}; +}; + +constexpr U Unique_Union1 = U{0}; + +constexpr U Unique_Union2 = U{}; + +} + +namespace MemberPointer{ + +struct A { + struct B { + struct C { + struct D { + struct E { + struct F { + struct G { + int i; + }; + }; + }; + }; + }; + }; +}; + +constexpr auto MemberPointer1 = &A::B::C::D::E::F::G::i; + +struct A1 { + struct B1 { + int f() const { + return 0; + } + }; + +}; + +constexpr auto MemberPointer2 = &A1::B1::f; + +} + +namespace std { + struct type_info; +}; + +namespace LValue { + +constexpr int LValueInt = 0; +constexpr const int& ConstIntRef = LValueInt; +constexpr const int* IntPtr = &LValueInt; + +constexpr const int* NullPtr = nullptr; + +struct A { + int Arr[6] = {0, 1, 3, 4, 5, 9}; + int i = 0; +}; + +constexpr A Arr[] = {{}, {}}; + +constexpr const int& ArrayStructRef1 = Arr[0].i; + +constexpr const int& ArrayStructRef2 = Arr[1].Arr[5]; + +constexpr const int* ArrayStructRef3 = &ArrayStructRef2; + +struct B : A { +}; + +struct C { + B b; +}; + +constexpr C c; + +constexpr const int& StructPathRef = c.b.i; + +constexpr const std::type_info &TypeID = typeid(c); + +constexpr const std::type_info &TypeID2 = typeid(Arr[1].Arr[2]); + +} + +#endif Index: clang/test/ASTMerge/APValue/test.cpp =================================================================== --- /dev/null +++ clang/test/ASTMerge/APValue/test.cpp @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -x c++ -emit-pch -std=gnu++2a -o %t.1.ast %S/Inputs/APValue.cpp +// RUN: %clang_cc1 -x c++ -std=gnu++2a -ast-merge %t.1.ast -ast-dump-all | FileCheck %s + +//CHECK: VarDecl {{.*}} Unique_Int +//CHECK-NEXT: ConstantExpr {{.*}} 'int' 6789 + +//CHECK: VarDecl {{.*}} Unique_Int128 +//CHECK-NEXT: ConstantExpr {{.*}} 'unsigned __int128' 156773562844924187900898496343692168785 + +//CHECK: VarDecl {{.*}} Unique_Double +//CHECK-NEXT: ConstantExpr {{.*}} 'double' 5.678907e+05 + +//CHECK: VarDecl {{.*}} Basic_Struct +//CHECK-NEXT: ConstantExpr {{.*}} 'const Struct::B' {1, 7.000000e-01} + +//CHECK: VarDecl {{.*}} Advanced_Struct +//CHECK-NEXT: ConstantExpr {{.*}} 'const Struct::A' {{[{][{]}}1, 7.000000e-01}, 1, 7.978900e+01, {9}} + +//CHECK: VarDecl {{.*}} Vector_Int +//CHECK-NEXT: ConstantExpr {{.*}} 'Vector::v4si':'__attribute__((__vector_size__(4 * sizeof(int)))) int' {8, 2, 3, 0} + +//CHECK: VarDecl {{.*}} Array_Int +//CHECK-NEXT: ConstantExpr {{.*}} 'const int [6]' {1, 2, 3, 4, 5, 6} + +//CHECK: VarDecl {{.*}} Array2_Struct +//CHECK-NEXT: ConstantExpr {{.*}} 'Array::A const [2][3]' {{[{][{]}}{789, 6.789010e+04}, {-45678, 9.800000e+00}, {9, 6.789010e+04}}, {{[{][{]}}789, 6.789010e+04}, {789, 6.789010e+04}, {789, 6.789010e+04}}} + +//CHECK: VarDecl {{.*}} Array_Vector +//CHECK-NEXT: ConstantExpr {{.*}} 'const Array::v4si [2]' {{[{][{]}}1, 2, 3, 4}, {4, 5, 6, 7}} + +//CHECK: VarDecl {{.*}} Unique_Union +//CHECK-NEXT: ConstantExpr {{.*}} 'const Union::U' {.i = 0} + +//CHECK: VarDecl {{.*}} Unique_Union +//CHECK-NEXT: ConstantExpr {{.*}} 'const Union::U' {.a = {567890, 9.876567e+03}} + +//CHECK: VarDecl {{.*}} MemberPointer1 +//CHECK-NEXT: ConstantExpr {{.*}} 'int MemberPointer::A::B::C::D::E::F::G::*' &G::i + +//CHECK: VarDecl {{.*}} MemberPointer2 +//CHECK-NEXT: ConstantExpr {{.*}} 'int (MemberPointer::A1::B1::*)() const' &B1::f + +//CHECK: VarDecl {{.*}} ConstIntRef +//CHECK-NEXT: ConstantExpr {{.*}} 'const int' lvalue &LValueInt + +//CHECK: VarDecl {{.*}} IntPtr +//CHECK-NEXT: ConstantExpr {{.*}} 'const int *' &LValueInt + +//CHECK: VarDecl {{.*}} NullPtr +//CHECK-NEXT: ConstantExpr {{.*}} 'const int *const' nullptr + +//CHECK: VarDecl {{.*}} ArrayStructRef1 +//CHECK-NEXT: ConstantExpr {{.*}} 'const int' lvalue &Arr[0].i + +//CHECK: VarDecl {{.*}} ArrayStructRef2 +//CHECK-NEXT: ConstantExpr {{.*}} 'const int' lvalue &Arr[1].Arr[5] + +//CHECK: VarDecl {{.*}} ArrayStructRef3 +//CHECK-NEXT: ConstantExpr {{.*}} 'const int *' &Arr[1].Arr[5] + +//CHECK: VarDecl {{.*}} StructPathRef +//CHECK-NEXT: ConstantExpr {{.*}} 'const int' lvalue &c.b.A::i + +//CHECK: VarDecl {{.*}} TypeID +//CHECK-NEXT: ConstantExpr {{.*}} 'const std::type_info' lvalue &typeid(LValue::C) + +//CHECK: VarDecl {{.*}} TypeID2 +//CHECK-NEXT: ConstantExpr {{.*}} 'const std::type_info' lvalue &typeid(int) Index: clang/test/PCH/APValue.cpp =================================================================== --- /dev/null +++ clang/test/PCH/APValue.cpp @@ -0,0 +1,210 @@ + +// RUN: %clang_cc1 -std=gnu++2a -emit-pch %s -o %t.pch +// RUN: %clang_cc1 -std=gnu++2a -x c++ -include-pch %t.pch -ast-dump-all | FileCheck %s + +#ifndef EMIT +#define EMIT + +namespace Integer { + +constexpr int Unique_Int = int(6789); +//CHECK: VarDecl {{.*}} Unique_Int +//CHECK-NEXT: ConstantExpr {{.*}} 'int' 6789 + +constexpr __uint128_t Unique_Int128 = ((__uint128_t)0x75f17d6b3588f843 << 64) | 0xb13dea7c9c324e51; +//CHECK: VarDecl {{.*}} Unique_Int128 +//CHECK-NEXT: ConstantExpr {{.*}} 'unsigned __int128' 156773562844924187900898496343692168785 + +} + +namespace FloatingPoint { + +constexpr double Unique_Double = double(567890.67890); +//CHECK: VarDecl {{.*}} Unique_Double +//CHECK-NEXT: ConstantExpr {{.*}} 'double' 5.678907e+05 + +} + +// FIXME: Add test for FixePoint, ComplexInt, ComplexFloat, AddrLabelDiff. + +namespace Struct { + +struct B { + int i; + double d; +}; + +constexpr B Basic_Struct = B{1, 0.7}; +//CHECK: VarDecl {{.*}} Basic_Struct +//CHECK-NEXT: ConstantExpr {{.*}} 'const Struct::B' {1, 7.000000e-01} + +struct C { + int i = 9; +}; + +struct A : B { + int i; + double d; + C c; +}; + +constexpr A Advanced_Struct = A{Basic_Struct, 1, 79.789, {}}; +//CHECK: VarDecl {{.*}} Advanced_Struct +//CHECK-NEXT: ConstantExpr {{.*}} 'const Struct::A' {{[{][{]}}1, 7.000000e-01}, 1, 7.978900e+01, {9}} + +} + +namespace Vector { + +using v4si = int __attribute__((__vector_size__(16))); + +constexpr v4si Vector_Int = (v4si){8, 2, 3}; +//CHECK: VarDecl {{.*}} Vector_Int +//CHECK-NEXT: ConstantExpr {{.*}} 'Vector::v4si':'__attribute__((__vector_size__(4 * sizeof(int)))) int' {8, 2, 3, 0} + +} + +namespace Array { + +constexpr int Array_Int[] = {1, 2, 3, 4, 5, 6}; +//CHECK: VarDecl {{.*}} Array_Int +//CHECK-NEXT: ConstantExpr {{.*}} 'const int [6]' {1, 2, 3, 4, 5, 6} + +struct A { + int i = 789; + double d = 67890.09876; +}; + +constexpr A Array2_Struct[][3] = {{{}, {-45678, 9.8}, {9}}, {{}}}; +//CHECK: VarDecl {{.*}} Array2_Struct +//CHECK-NEXT: ConstantExpr {{.*}} 'Array::A const [2][3]' {{[{][{]}}{789, 6.789010e+04}, {-45678, 9.800000e+00}, {9, 6.789010e+04}}, {{[{][{]}}789, 6.789010e+04}, {789, 6.789010e+04}, {789, 6.789010e+04}}} + +using v4si = int __attribute__((__vector_size__(16))); + +constexpr v4si Array_Vector[] = {{1, 2, 3, 4}, {4, 5, 6, 7}}; +//CHECK: VarDecl {{.*}} Array_Vector +//CHECK-NEXT: ConstantExpr {{.*}} 'const Array::v4si [2]' {{[{][{]}}1, 2, 3, 4}, {4, 5, 6, 7}} + +} + +namespace Union { + +struct A { + int i = 6789; + float f = 987.9876; +}; + +union U { + int i; + A a{567890, 9876.5678f}; +}; + +constexpr U Unique_Union1 = U{0}; +//CHECK: VarDecl {{.*}} Unique_Union +//CHECK-NEXT: ConstantExpr {{.*}} 'const Union::U' {.i = 0} + +constexpr U Unique_Union2 = U{}; +//CHECK: VarDecl {{.*}} Unique_Union +//CHECK-NEXT: ConstantExpr {{.*}} 'const Union::U' {.a = {567890, 9.876567e+03}} + +} + +namespace MemberPointer{ + +struct A { + struct B { + struct C { + struct D { + struct E { + struct F { + struct G { + int i; + }; + }; + }; + }; + }; + }; +}; + +constexpr auto MemberPointer1 = &A::B::C::D::E::F::G::i; +//CHECK: VarDecl {{.*}} MemberPointer1 +//CHECK-NEXT: ConstantExpr {{.*}} 'int MemberPointer::A::B::C::D::E::F::G::*' &G::i + +struct A1 { + struct B1 { + int f() const { + return 0; + } + }; + +}; + +constexpr auto MemberPointer2 = &A1::B1::f; +//CHECK: VarDecl {{.*}} MemberPointer2 +//CHECK-NEXT: ConstantExpr {{.*}} 'int (MemberPointer::A1::B1::*)() const' &B1::f + +} + +namespace std { + struct type_info; +}; + +namespace LValue { + +constexpr int LValueInt = 0; +constexpr const int& ConstIntRef = LValueInt; +//CHECK: VarDecl {{.*}} ConstIntRef +//CHECK-NEXT: ConstantExpr {{.*}} 'const int' lvalue &LValueInt +constexpr const int* IntPtr = &LValueInt; +//CHECK: VarDecl {{.*}} IntPtr +//CHECK-NEXT: ConstantExpr {{.*}} 'const int *' &LValueInt + +constexpr const int* NullPtr = nullptr; +//CHECK: VarDecl {{.*}} NullPtr +//CHECK-NEXT: ConstantExpr {{.*}} 'const int *const' nullptr + +struct A { + int Arr[6] = {0, 1, 3, 4, 5, 9}; + int i = 0; +}; + +constexpr A Arr[] = {{}, {}}; + +constexpr const int& ArrayStructRef1 = Arr[0].i; +//CHECK: VarDecl {{.*}} ArrayStructRef1 +//CHECK-NEXT: ConstantExpr {{.*}} 'const int' lvalue &Arr[0].i + +constexpr const int& ArrayStructRef2 = Arr[1].Arr[5]; +//CHECK: VarDecl {{.*}} ArrayStructRef2 +//CHECK-NEXT: ConstantExpr {{.*}} 'const int' lvalue &Arr[1].Arr[5] + +constexpr const int* ArrayStructRef3 = &ArrayStructRef2; +//CHECK: VarDecl {{.*}} ArrayStructRef3 +//CHECK-NEXT: ConstantExpr {{.*}} 'const int *' &Arr[1].Arr[5] + +struct B : A { +}; + +struct C { + B b; +}; + +constexpr C c; + +constexpr const int& StructPathRef = c.b.i; +//CHECK: VarDecl {{.*}} StructPathRef +//CHECK-NEXT: ConstantExpr {{.*}} 'const int' lvalue &c.b.A::i + +constexpr const std::type_info &TypeID = typeid(c); +//CHECK: VarDecl {{.*}} TypeID +//CHECK-NEXT: ConstantExpr {{.*}} 'const std::type_info' lvalue &typeid(LValue::C) + +constexpr const std::type_info &TypeID2 = typeid(Arr[1].Arr[2]); +//CHECK: VarDecl {{.*}} TypeID2 +//CHECK-NEXT: ConstantExpr {{.*}} 'const std::type_info' lvalue &typeid(int) + +} + +#endif +