Index: clang/include/clang/AST/APValue.h =================================================================== --- clang/include/clang/AST/APValue.h +++ clang/include/clang/AST/APValue.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_AST_APVALUE_H #define LLVM_CLANG_AST_APVALUE_H +#include "clang/AST/PrettyPrinter.h" #include "clang/Basic/FixedPoint.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/APFloat.h" @@ -185,6 +186,7 @@ friend class ASTReader; friend class ASTWriter; + friend class ASTImporter; private: ValueKind Kind; @@ -330,6 +332,10 @@ void dump() const; void dump(raw_ostream &OS) const; + void dumpPretty(raw_ostream &OS, QualType Ty, + const clang::PrintingPolicy &Policy = + PrintingPolicy(LangOptions())) const; + void printPretty(raw_ostream &OS, const ASTContext &Ctx, QualType Ty) const; std::string getAsString(const ASTContext &Ctx, QualType Ty) const; @@ -509,9 +515,7 @@ *(APFixedPoint *)(char *)Data.buffer = std::move(FX); } void setVector(const APValue *E, unsigned N) { - assert(isVector() && "Invalid accessor"); - ((Vec*)(char*)Data.buffer)->Elts = new APValue[N]; - ((Vec*)(char*)Data.buffer)->NumElts = N; + ReserveVector(N); for (unsigned i = 0; i != N; ++i) ((Vec*)(char*)Data.buffer)->Elts[i] = E[i]; } @@ -602,6 +606,21 @@ new ((void*)(char*)Data.buffer) AddrLabelDiffData(); Kind = AddrLabelDiff; } + + /// The following functions are used as part of initialization. during + /// Serialization and Importing. Reserve the space then write element directly + /// in place as after importing/deserializating then. + void ReserveVector(unsigned N) { + assert(isVector() && "Invalid accessor"); + ((Vec*)(char*)Data.buffer)->Elts = new APValue[N]; + ((Vec*)(char*)Data.buffer)->NumElts = N; + } + void MakeEmptyMemberPointer(const ValueDecl *Member, bool IsDerivedMember, + unsigned Size); + void SetLValueEmptyPath(LValueBase B, const CharUnits &O, unsigned Size, + bool OnePastTheEnd, bool IsNullPtr); + const CXXRecordDecl **GetInternalMemberPointerPathPtr(); + LValuePathEntry *GetInternalLValuePathPtr(); }; } // end namespace clang. Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -277,9 +277,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 @@ -15,6 +15,7 @@ #define LLVM_CLANG_AST_ASTIMPORTER_H #include "clang/AST/DeclBase.h" +#include "clang/AST/APValue.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" @@ -494,6 +495,13 @@ /// "to" context, or the import error. llvm::Expected Import(const CXXBaseSpecifier *FromSpec); + /// Import the given APValue from the "from" context into + /// the "to" context. + /// + /// \return the equivalent APValue in the "to" context 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 @@ -959,6 +959,8 @@ public: /// Describes the kind of result that can be trail-allocated. + /// Enumerators need to stay ordered by size of their storage. + /// Smallest storage first. enum ResultStorageKind { RSK_None, RSK_Int64, RSK_APValue }; private: Index: clang/include/clang/AST/PrettyPrinter.h =================================================================== --- clang/include/clang/AST/PrettyPrinter.h +++ clang/include/clang/AST/PrettyPrinter.h @@ -48,9 +48,10 @@ UseVoidForZeroParams(!LO.CPlusPlus), TerseOutput(false), PolishForDeclaration(false), Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), - MSVCFormatting(false), ConstantsAsWritten(false), - SuppressImplicitBase(false), FullyQualifiedName(false), - RemapFilePaths(false), PrintCanonicalTypes(false) {} + MSVCFormatting(false), UseNullptr(LO.CPlusPlus11), + ConstantsAsWritten(false), SuppressImplicitBase(false), + FullyQualifiedName(false), RemapFilePaths(false), + PrintCanonicalTypes(false) {} /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -199,6 +200,9 @@ /// after template arguments. unsigned MSVCFormatting : 1; + /// Whether null pointers should be printed as nullptr or as NULL. + unsigned UseNullptr : 1; + /// Whether we should print the constant expressions as written in the /// sources. /// Index: clang/include/clang/Serialization/ASTReader.h =================================================================== --- clang/include/clang/Serialization/ASTReader.h +++ clang/include/clang/Serialization/ASTReader.h @@ -2222,7 +2222,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); @@ -2617,7 +2617,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 @@ -456,9 +456,10 @@ llvm_unreachable("Unknown APValue kind!"); } -void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, - QualType Ty) const { - switch (getKind()) { +static void InternalPrinter(raw_ostream &Out, const APValue &Value, QualType Ty, + const ASTContext *Ctx, + const clang::PrintingPolicy &Policy) { + switch (Value.getKind()) { case APValue::None: Out << ""; return; @@ -467,33 +468,33 @@ return; case APValue::Int: if (Ty->isBooleanType()) - Out << (getInt().getBoolValue() ? "true" : "false"); + Out << (Value.getInt().getBoolValue() ? "true" : "false"); else - Out << getInt(); + Out << Value.getInt(); return; case APValue::Float: - Out << GetApproxValue(getFloat()); + Out << GetApproxValue(Value.getFloat()); return; case APValue::FixedPoint: - Out << getFixedPoint(); + Out << Value.getFixedPoint(); return; case APValue::Vector: { Out << '{'; QualType ElemTy = Ty->getAs()->getElementType(); - getVectorElt(0).printPretty(Out, Ctx, ElemTy); - for (unsigned i = 1; i != getVectorLength(); ++i) { + ::InternalPrinter(Out, Value.getVectorElt(0), ElemTy, Ctx, Policy); + for (unsigned i = 1; i != Value.getVectorLength(); ++i) { Out << ", "; - getVectorElt(i).printPretty(Out, Ctx, ElemTy); + ::InternalPrinter(Out, Value.getVectorElt(i), ElemTy, Ctx, Policy); } Out << '}'; return; } case APValue::ComplexInt: - Out << getComplexIntReal() << "+" << getComplexIntImag() << "i"; + Out << Value.getComplexIntReal() << "+" << Value.getComplexIntImag() << "i"; return; case APValue::ComplexFloat: - Out << GetApproxValue(getComplexFloatReal()) << "+" - << GetApproxValue(getComplexFloatImag()) << "i"; + Out << GetApproxValue(Value.getComplexFloatReal()) << "+" + << GetApproxValue(Value.getComplexFloatImag()) << "i"; return; case APValue::LValue: { bool IsReference = Ty->isReferenceType(); @@ -502,28 +503,30 @@ if (InnerTy.isNull()) InnerTy = Ty; - LValueBase Base = getLValueBase(); + APValue::LValueBase Base = Value.getLValueBase(); if (!Base) { - if (isNullPointer()) { - Out << (Ctx.getLangOpts().CPlusPlus11 ? "nullptr" : "0"); + if (Value.isNullPointer()) { + Out << (Policy.UseNullptr ? "nullptr" : "NULL"); } else if (IsReference) { - Out << "*(" << InnerTy.stream(Ctx.getPrintingPolicy()) << "*)" - << getLValueOffset().getQuantity(); + Out << "*(" << InnerTy.stream(Policy) << "*)" + << Value.getLValueOffset().getQuantity(); } else { - Out << "(" << Ty.stream(Ctx.getPrintingPolicy()) << ")" - << getLValueOffset().getQuantity(); + Out << "(" << Ty.stream(Policy) << ")" + << Value.getLValueOffset().getQuantity(); } return; } - if (!hasLValuePath()) { + if (!Value.hasLValuePath()) { // No lvalue path: just print the offset. - CharUnits O = getLValueOffset(); - CharUnits S = Ctx.getTypeSizeInChars(InnerTy); + CharUnits O = Value.getLValueOffset(); + CharUnits S; + if (Ctx) + S = Ctx->getTypeSizeInChars(InnerTy); if (!O.isZero()) { if (IsReference) Out << "*("; - if (O % S) { + if (!Ctx || O % S) { Out << "(char*)"; S = CharUnits::One(); } @@ -531,19 +534,18 @@ } else if (!IsReference) Out << '&'; - if (const ValueDecl *VD = Base.dyn_cast()) + if (const auto *VD = Base.dyn_cast()) Out << *VD; else if (TypeInfoLValue TI = Base.dyn_cast()) { - TI.print(Out, Ctx.getPrintingPolicy()); + TI.print(Out, Policy); } else { assert(Base.get() != nullptr && "Expecting non-null Expr"); - Base.get()->printPretty(Out, nullptr, - Ctx.getPrintingPolicy()); + Base.get()->printPretty(Out, nullptr, Policy); } if (!O.isZero()) { - Out << " + " << (O / S); + Out << " + " << (Ctx ? (O / S) : O.getQuantity()); if (IsReference) Out << ')'; } @@ -553,35 +555,38 @@ // We have an lvalue path. Print it out nicely. if (!IsReference) Out << '&'; - else if (isLValueOnePastTheEnd()) + else if (Value.isLValueOnePastTheEnd()) Out << "*(&"; QualType ElemTy; - if (const ValueDecl *VD = Base.dyn_cast()) { + bool IsRecord = false; + if (const auto *VD = Base.dyn_cast()) { Out << *VD; ElemTy = VD->getType(); } else if (TypeInfoLValue TI = Base.dyn_cast()) { - TI.print(Out, Ctx.getPrintingPolicy()); + TI.print(Out, Policy); ElemTy = Base.getTypeInfoType(); } else { const Expr *E = Base.get(); assert(E != nullptr && "Expecting non-null Expr"); - E->printPretty(Out, nullptr, Ctx.getPrintingPolicy()); + E->printPretty(Out, nullptr, Policy); ElemTy = E->getType(); } - ArrayRef Path = getLValuePath(); + ArrayRef Path = Value.getLValuePath(); const CXXRecordDecl *CastToBase = nullptr; for (unsigned I = 0, N = Path.size(); I != N; ++I) { - if (ElemTy->getAs()) { + if (IsRecord || ElemTy->getAs()) { + IsRecord = false; // The lvalue refers to a class type, so the next path entry is a base // or member. const Decl *BaseOrMember = Path[I].getAsBaseOrMember().getPointer(); - if (const CXXRecordDecl *RD = dyn_cast(BaseOrMember)) { + if (const auto *RD = dyn_cast(BaseOrMember)) { CastToBase = RD; - ElemTy = Ctx.getRecordType(RD); + ElemTy = QualType(); + IsRecord = true; } else { - const ValueDecl *VD = cast(BaseOrMember); + const auto *VD = cast(BaseOrMember); Out << "."; if (CastToBase) Out << *CastToBase << "::"; @@ -591,12 +596,12 @@ } else { // The lvalue must refer to an array. Out << '[' << Path[I].getAsArrayIndex() << ']'; - ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType(); + ElemTy = cast(ElemTy.getCanonicalType())->getElementType(); } } // Handle formatting of one-past-the-end lvalues. - if (isLValueOnePastTheEnd()) { + if (Value.isLValueOnePastTheEnd()) { // FIXME: If CastToBase is non-0, we should prefix the output with // "(CastToBase*)". Out << " + 1"; @@ -606,11 +611,11 @@ return; } case APValue::Array: { - const ArrayType *AT = Ctx.getAsArrayType(Ty); + const auto *AT = cast(Ty.getCanonicalType()); QualType ElemTy = AT->getElementType(); Out << '{'; - if (unsigned N = getArrayInitializedElts()) { - getArrayInitializedElt(0).printPretty(Out, Ctx, ElemTy); + if (unsigned N = Value.getArrayInitializedElts()) { + ::InternalPrinter(Out, Value.getArrayInitializedElt(0), ElemTy, Ctx, Policy); for (unsigned I = 1; I != N; ++I) { Out << ", "; if (I == 10) { @@ -618,7 +623,8 @@ Out << "..."; break; } - getArrayInitializedElt(I).printPretty(Out, Ctx, ElemTy); + ::InternalPrinter(Out, Value.getArrayInitializedElt(I), ElemTy, Ctx, + Policy); } } Out << '}'; @@ -628,14 +634,15 @@ Out << '{'; const RecordDecl *RD = Ty->getAs()->getDecl(); bool First = true; - if (unsigned N = getStructNumBases()) { - const CXXRecordDecl *CD = cast(RD); + if (unsigned N = Value.getStructNumBases()) { + const auto *CD = cast(RD); CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin(); for (unsigned I = 0; I != N; ++I, ++BI) { assert(BI != CD->bases_end()); if (!First) Out << ", "; - getStructBase(I).printPretty(Out, Ctx, BI->getType()); + ::InternalPrinter(Out, Value.getStructBase(I), BI->getType(), Ctx, + Policy); First = false; } } @@ -643,8 +650,8 @@ if (!First) Out << ", "; if (FI->isUnnamedBitfield()) continue; - getStructField(FI->getFieldIndex()). - printPretty(Out, Ctx, FI->getType()); + ::InternalPrinter(Out, Value.getStructField(FI->getFieldIndex()), + FI->getType(), Ctx, Policy); First = false; } Out << '}'; @@ -652,30 +659,39 @@ } case APValue::Union: Out << '{'; - if (const FieldDecl *FD = getUnionField()) { + if (const FieldDecl *FD = Value.getUnionField()) { Out << "." << *FD << " = "; - getUnionValue().printPretty(Out, Ctx, FD->getType()); + ::InternalPrinter(Out, Value.getUnionValue(), FD->getType(), Ctx, Policy); } Out << '}'; return; case APValue::MemberPointer: // FIXME: This is not enough to unambiguously identify the member in a // multiple-inheritance scenario. - if (const ValueDecl *VD = getMemberPointerDecl()) { + if (const ValueDecl *VD = Value.getMemberPointerDecl()) { Out << '&' << *cast(VD->getDeclContext()) << "::" << *VD; return; } Out << "0"; return; case APValue::AddrLabelDiff: - Out << "&&" << getAddrLabelDiffLHS()->getLabel()->getName(); + Out << "&&" << Value.getAddrLabelDiffLHS()->getLabel()->getName(); Out << " - "; - Out << "&&" << getAddrLabelDiffRHS()->getLabel()->getName(); + Out << "&&" << Value.getAddrLabelDiffRHS()->getLabel()->getName(); return; } llvm_unreachable("Unknown APValue kind!"); } +void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, QualType Ty) const { + ::InternalPrinter(Out, *this, Ty, &Ctx, Ctx.getPrintingPolicy()); +} + +void APValue::dumpPretty(raw_ostream &OS, QualType Ty, + const clang::PrintingPolicy &Policy) const { + ::InternalPrinter(OS, *this, Ty, nullptr, Policy); +} + std::string APValue::getAsString(const ASTContext &Ctx, QualType Ty) const { std::string Result; llvm::raw_string_ostream Out(Result); @@ -745,6 +761,10 @@ return ((const LV*)(const char*)Data.buffer)->IsNullPtr; } +APValue::LValuePathEntry *APValue::GetInternalLValuePathPtr() { + return ((LV *)(char *)Data.buffer)->getPath(); +} + void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath, bool IsNullPtr) { assert(isLValue() && "Invalid accessor"); @@ -756,17 +776,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 +830,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 *)); +} + +const CXXRecordDecl **APValue::GetInternalMemberPointerPathPtr() { + return ((MemberPointerData *)(char *)Data.buffer)->getPath(); } Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -880,9 +880,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 @@ -6518,21 +6518,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) { @@ -8767,6 +8761,197 @@ 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(); + llvm::Expected ImpFDecl = Import(FromValue.getUnionField()); + if (!ImpFDecl) { + Error = ImpFDecl.takeError(); + break; + } + llvm::Expected ImpValue = Import(FromValue.getUnionValue()); + if (!ImpValue) { + Error = ImpValue.takeError(); + break; + } + Result.setUnion(cast(ImpFDecl.get()), ImpValue.get()); + break; + } + case APValue::AddrLabelDiff: { + Result.MakeAddrLabelDiff(); + llvm::Expected ImpLHS = + Import(const_cast(FromValue.getAddrLabelDiffLHS())); + if (!ImpLHS) { + Error = ImpLHS.takeError(); + break; + } + llvm::Expected ImpRHS = + Import(const_cast(FromValue.getAddrLabelDiffRHS())); + if (!ImpRHS) { + Error = ImpRHS.takeError(); + break; + } + Result.setAddrLabelDiff(cast(ImpLHS.get()), + cast(ImpRHS.get())); + break; + } + case APValue::MemberPointer: { + llvm::Expected 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(); + const CXXRecordDecl **ToPath = Result.GetInternalMemberPointerPathPtr(); + for (unsigned Idx = 0; Idx < FromValue.getMemberPointerPath().size(); + Idx++) { + llvm::Expected 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(); + llvm::Expected 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(); + llvm::Expected 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(); + llvm::Expected ImpTypeInfo = Import(QualType( + FromValue.getLValueBase().get().getType(), 0)); + if (!ImpTypeInfo) { + Error = ImpTypeInfo.takeError(); + break; + } + llvm::Expected 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.GetInternalLValuePathPtr(); + for (unsigned LoopIdx = 0; LoopIdx < PathLength; LoopIdx++) { + if (FromElemTy->getAs()) { + const Decl *FromDecl = + FromPath[LoopIdx].getAsBaseOrMember().getPointer(); + llvm::Expected 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; +} + Expected ASTImporter::HandleNameConflict(DeclarationName Name, DeclContext *DC, unsigned IDNS, Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -2374,6 +2374,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 @@ -266,6 +266,8 @@ 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) ::new (getTrailingObjects()) APValue(); @@ -284,8 +286,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, @@ -314,9 +315,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; @@ -349,6 +352,10 @@ } APValue ConstantExpr::getAPValueResult() const { + if (ConstantExprBits.APValueKind == APValue::None) + return APValue(); + else if (ConstantExprBits.APValueKind == APValue::Indeterminate) + return APValue::IndeterminateValue(); switch (ConstantExprBits.ResultKind) { case ConstantExpr::RSK_APValue: return APValueResult(); Index: clang/lib/AST/TextNodeDumper.cpp =================================================================== --- clang/lib/AST/TextNodeDumper.cpp +++ clang/lib/AST/TextNodeDumper.cpp @@ -687,7 +687,7 @@ if (Node->getResultAPValueKind() != APValue::None) { ColorScope Color(OS, ShowColors, ValueColor); OS << " "; - Node->getAPValueResult().dump(OS); + Node->getAPValueResult().dumpPretty(OS, Node->getType(), PrintPolicy); } } Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -11723,6 +11723,11 @@ 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 @@ -9532,45 +9532,150 @@ 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)); + case APValue::ComplexInt: { + 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: { + auto *FDecl = cast(GetDecl(ReadDeclID(F, Record, RecordIdx))); + APValue Value = ReadAPValue(F, Record, RecordIdx); + return APValue(FDecl, Value); + } + case APValue::AddrLabelDiff: { + auto *LHS = cast(ReadExpr(F)); + auto *RHS = cast(ReadExpr(F)); + return APValue(LHS, RHS); + } + case APValue::MemberPointer: { + APValue Result; + bool IsDerived = Record[RecordIdx++]; + auto *Member = cast(GetDecl(ReadDeclID(F, Record, RecordIdx))); + unsigned PathSize = Record[RecordIdx++]; + Result.MakeEmptyMemberPointer(Member, IsDerived, PathSize); + const CXXRecordDecl **PathArray = Result.GetInternalMemberPointerPathPtr(); + for (unsigned LoopIdx = 0; LoopIdx < PathSize; LoopIdx++) + PathArray[LoopIdx] = + cast(GetDecl(ReadDeclID(F, Record, RecordIdx))); + return Result; + } + case APValue::LValue: { + uint64_t Bits = Record[RecordIdx++]; + bool HasLValuePath = Bits & 0x1; + bool IsLValueOnePastTheEnd = Bits & 0x2; + bool IsExpr = Bits & 0x4; + bool IsTypeInfo = Bits & 0x8; + bool IsNullPtr = Bits & 0x10; + bool HasBase = Bits & 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.GetInternalLValuePathPtr(); + for (unsigned LoopIdx = 0; LoopIdx < PathLength; LoopIdx++) { + if (ElemTy->getAs()) { + unsigned Int = Record[RecordIdx++]; + Decl *D = GetDecl(ReadDeclID(F, Record, RecordIdx)); + if (auto *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"); } @@ -11318,18 +11423,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) { @@ -11342,6 +11435,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 @@ -537,13 +537,14 @@ switch (E->ConstantExprBits.ResultKind) { case ConstantExpr::RSK_Int64: { E->Int64Result() = Record.readInt(); - uint64_t tmp = Record.readInt(); - E->ConstantExprBits.IsUnsigned = tmp & 0x1; - E->ConstantExprBits.BitWidth = tmp >> 1; + uint64_t Bits = Record.readInt(); + E->ConstantExprBits.IsUnsigned = Bits & 0x1; + E->ConstantExprBits.BitWidth = (Bits >> 1) & /*7 bottom bits set*/ 0x7f; + E->ConstantExprBits.APValueKind = Bits >> 8; 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 @@ -5452,14 +5452,90 @@ 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: { + push_back(Value.hasLValuePath() | Value.isLValueOnePastTheEnd() << 1 | + Value.getLValueBase().is() << 2 | + Value.getLValueBase().is() << 3 | + Value.isNullPointer() << 4 | + static_cast(Value.getLValueBase()) << 5); + QualType ElemTy; + if (Value.getLValueBase()) { + if (!Value.getLValueBase().is()) { + push_back(Value.getLValueBase().getCallIndex()); + push_back(Value.getLValueBase().getVersion()); + if (const 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 auto *RD = dyn_cast(BaseOrMember)) { + AddDeclRef(RD); + ElemTy = Writer->Context->getRecordType(RD); + } else { + const auto *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"); Index: clang/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- clang/lib/Serialization/ASTWriterStmt.cpp +++ clang/lib/Serialization/ASTWriterStmt.cpp @@ -437,7 +437,8 @@ case ConstantExpr::RSK_Int64: Record.push_back(E->Int64Result()); Record.push_back(E->ConstantExprBits.IsUnsigned | - E->ConstantExprBits.BitWidth << 1); + E->ConstantExprBits.BitWidth << 1 | + E->ConstantExprBits.APValueKind << 8); break; case ConstantExpr::RSK_APValue: Record.AddAPValue(E->APValueResult()); Index: clang/test/AST/ast-dump-color.cpp =================================================================== --- clang/test/AST/ast-dump-color.cpp +++ clang/test/AST/ast-dump-color.cpp @@ -49,13 +49,13 @@ //CHECK: {{^}}[[Blue]]| | |-[[RESET]][[MAGENTA]]IntegerLiteral[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:10:11[[RESET]]> [[Green]]'int'[[RESET]][[Cyan:.\[0;36m]][[RESET]][[Cyan]][[RESET]][[CYAN]] 1[[RESET]]{{$}} //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]CompoundStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:14[[RESET]], [[Yellow]]line:15:3[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | |-[[RESET]][[MAGENTA]]CaseStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:11:3[[RESET]], [[Yellow]]line:12:27[[RESET]]>{{$}} -//CHECK: {{^}}[[Blue]]| | | |-[[RESET]][[MAGENTA]]ConstantExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:11:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] Int: 1[[RESET]]{{$}} +//CHECK: {{^}}[[Blue]]| | | |-[[RESET]][[MAGENTA]]ConstantExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:11:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] 1[[RESET]]{{$}} //CHECK: {{^}}[[Blue]]| | | | `-[[RESET]][[MAGENTA]]IntegerLiteral[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] 1[[RESET]]{{$}} //CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[MAGENTA]]AttributedStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:12:5[[RESET]], [[Yellow]]col:27[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | | |-[[RESET]][[BLUE]]FallThroughAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:7[[RESET]], [[Yellow]]col:14[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[MAGENTA]]NullStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:27[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]CaseStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:13:3[[RESET]], [[Yellow]]line:14:5[[RESET]]>{{$}} -//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[MAGENTA]]ConstantExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:13:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] Int: 2[[RESET]]{{$}} +//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[MAGENTA]]ConstantExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:13:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] 2[[RESET]]{{$}} //CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[MAGENTA]]IntegerLiteral[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] 2[[RESET]]{{$}} //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]NullStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:14:5[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| `-[[RESET]][[Blue]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:8:4[[RESET]], [[Yellow]]col:11[[RESET]]>{{$}} Index: clang/test/ASTMerge/APValue/APValue.cpp =================================================================== --- /dev/null +++ clang/test/ASTMerge/APValue/APValue.cpp @@ -0,0 +1,209 @@ +// RUN: %clang_cc1 -std=gnu++2a -emit-pch %s -o %t.pch +// RUN: %clang_cc1 -std=gnu++2a %s -DEMIT -ast-merge %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 FixedPoint, 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 +