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" @@ -227,8 +228,9 @@ struct UninitArray {}; struct UninitStruct {}; - friend class ASTReader; + friend class ASTRecordReader; friend class ASTWriter; + friend class ASTImporter; private: ValueKind Kind; @@ -374,6 +376,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; @@ -553,9 +559,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]; } @@ -646,6 +650,21 @@ new ((void*)(char*)Data.buffer) AddrLabelDiffData(); Kind = AddrLabelDiff; } + + /// The following functions are used as part of initialization. during + /// Deserialization and Importing. Reserve the space then write element + /// directly in place as after importing/deserialization 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 @@ -263,9 +263,6 @@ /// Mapping from __block VarDecls to BlockVarCopyInit. llvm::DenseMap BlockVarCopyInits; - /// 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/DeclBase.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/NestedNameSpecifier.h" @@ -498,6 +499,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 @@ -984,6 +984,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 @@ -58,9 +58,9 @@ 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), - PrintCanonicalTypes(false) {} + MSVCFormatting(false), UseNullptr(LO.CPlusPlus11), + ConstantsAsWritten(false), SuppressImplicitBase(false), + FullyQualifiedName(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 @@ -209,6 +209,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/lib/AST/APValue.cpp =================================================================== --- clang/lib/AST/APValue.cpp +++ clang/lib/AST/APValue.cpp @@ -470,9 +470,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; @@ -481,33 +482,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->castAs()->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(); @@ -516,28 +517,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(); } @@ -546,23 +549,21 @@ 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 if (DynamicAllocLValue DA = Base.dyn_cast()) { - Out << "{*new " - << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#" + Out << "{*new " << Base.getDynamicAllocType().stream(Policy) << "#" << DA.getIndex() << "}"; } 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 << ')'; } @@ -572,42 +573,44 @@ // 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 if (DynamicAllocLValue DA = Base.dyn_cast()) { - Out << "{*new " - << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#" + Out << "{*new " << Base.getDynamicAllocType().stream(Policy) << "#" << DA.getIndex() << "}"; ElemTy = Base.getDynamicAllocType(); } else { const Expr *E = Base.get(); assert(E != nullptr && "Expecting non-null Expr"); - E->printPretty(Out, nullptr, Ctx.getPrintingPolicy()); + E->printPretty(Out, nullptr, Policy); // FIXME: This is wrong if E is a MaterializeTemporaryExpr with an lvalue // adjustment. 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 << "::"; @@ -617,12 +620,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"; @@ -632,11 +635,12 @@ 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) { @@ -644,7 +648,8 @@ Out << "..."; break; } - getArrayInitializedElt(I).printPretty(Out, Ctx, ElemTy); + ::InternalPrinter(Out, Value.getArrayInitializedElt(I), ElemTy, Ctx, + Policy); } } Out << '}'; @@ -654,14 +659,15 @@ Out << '{'; const RecordDecl *RD = Ty->castAs()->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; } } @@ -669,8 +675,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 << '}'; @@ -678,30 +684,40 @@ } 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); @@ -771,6 +787,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"); @@ -782,17 +802,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 { @@ -829,13 +856,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 @@ -910,9 +910,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 @@ -6613,21 +6613,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) { @@ -8897,6 +8891,198 @@ 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 @@ -2387,6 +2387,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 @@ -269,6 +269,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(); @@ -287,8 +289,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, @@ -317,12 +318,14 @@ } 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; + llvm_unreachable("invalid APValue"); case RSK_Int64: Int64Result() = *Value.getInt().getRawData(); ConstantExprBits.BitWidth = Value.getInt().getBitWidth(); @@ -352,6 +355,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 @@ -690,7 +690,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 @@ -11864,6 +11864,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 @@ -8804,61 +8804,152 @@ return SourceRange(beg, end); } -static FixedPointSemantics -ReadFixedPointSemantics(const SmallVectorImpl &Record, - unsigned &Idx) { - unsigned Width = Record[Idx++]; - unsigned Scale = Record[Idx++]; - uint64_t Tmp = Record[Idx++]; - bool IsSigned = Tmp & 0x1; - bool IsSaturated = Tmp & 0x2; - bool HasUnsignedPadding = Tmp & 0x4; - return FixedPointSemantics(Width, Scale, IsSigned, IsSaturated, - HasUnsignedPadding); -} - -static const llvm::fltSemantics & -readAPFloatSemantics(ASTRecordReader &reader) { - return llvm::APFloatBase::EnumToSemantics( - static_cast(reader.readInt())); -} - APValue ASTRecordReader::readAPValue() { - unsigned Kind = readInt(); - switch ((APValue::ValueKind) Kind) { + auto Kind = static_cast(asImpl().readUInt32()); + switch (Kind) { case APValue::None: return APValue(); case APValue::Indeterminate: return APValue::IndeterminateValue(); case APValue::Int: - return APValue(readAPSInt()); + return APValue(asImpl().readAPSInt()); case APValue::Float: { - const llvm::fltSemantics &FloatSema = readAPFloatSemantics(*this); - return APValue(readAPFloat(FloatSema)); + const llvm::fltSemantics &FloatSema = llvm::APFloatBase::EnumToSemantics( + static_cast(asImpl().readUInt32())); + return APValue(asImpl().readAPFloat(FloatSema)); } case APValue::FixedPoint: { - FixedPointSemantics FPSema = ReadFixedPointSemantics(Record, Idx); - return APValue(APFixedPoint(readAPInt(), FPSema)); + unsigned Width = asImpl().readUInt32(); + unsigned Scale = asImpl().readUInt32(); + unsigned Tmp = asImpl().readUInt32(); + bool IsSigned = Tmp & 0x1; + bool IsSaturated = Tmp & 0x2; + bool HasUnsignedPadding = Tmp & 0x4; + FixedPointSemantics FPSema = FixedPointSemantics( + Width, Scale, IsSigned, IsSaturated, HasUnsignedPadding); + return APValue(APFixedPoint(asImpl().readAPInt(), FPSema)); } case APValue::ComplexInt: { - llvm::APSInt First = readAPSInt(); - return APValue(std::move(First), readAPSInt()); + llvm::APSInt First = asImpl().readAPSInt(); + return APValue(std::move(First), asImpl().readAPSInt()); } case APValue::ComplexFloat: { - const llvm::fltSemantics &FloatSema1 = readAPFloatSemantics(*this); + const llvm::fltSemantics &FloatSema1 = llvm::APFloatBase::EnumToSemantics( + static_cast(asImpl().readUInt32())); llvm::APFloat First = readAPFloat(FloatSema1); - const llvm::fltSemantics &FloatSema2 = readAPFloatSemantics(*this); - return APValue(std::move(First), readAPFloat(FloatSema2)); - } - 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(); + const llvm::fltSemantics &FloatSema2 = llvm::APFloatBase::EnumToSemantics( + static_cast(asImpl().readUInt32())); + return APValue(std::move(First), asImpl().readAPFloat(FloatSema2)); + } + case APValue::Vector: { + APValue Result; + Result.MakeVector(); + unsigned Length = asImpl().readUInt32(); + Result.ReserveVector(Length); + for (unsigned LoopIdx = 0; LoopIdx < Length; LoopIdx++) + Result.getVectorElt(LoopIdx) = asImpl().readAPValue(); + return Result; + } + case APValue::Array: { + APValue Result; + unsigned InitLength = asImpl().readUInt32(); + unsigned TotalLength = asImpl().readUInt32(); + Result.MakeArray(InitLength, TotalLength); + for (unsigned LoopIdx = 0; LoopIdx < InitLength; LoopIdx++) + Result.getArrayInitializedElt(LoopIdx) = asImpl().readAPValue(); + return Result; + } + case APValue::Struct: { + APValue Result; + unsigned BasesLength = asImpl().readUInt32(); + unsigned FieldsLength = asImpl().readUInt32(); + Result.MakeStruct(BasesLength, FieldsLength); + for (unsigned LoopIdx = 0; LoopIdx < BasesLength; LoopIdx++) + Result.getStructBase(LoopIdx) = asImpl().readAPValue(); + for (unsigned LoopIdx = 0; LoopIdx < FieldsLength; LoopIdx++) + Result.getStructField(LoopIdx) = asImpl().readAPValue(); + return Result; + } + case APValue::Union: { + auto *FDecl = asImpl().readDeclAs(); + APValue Value = asImpl().readAPValue(); + return APValue(FDecl, std::move(Value)); + } + case APValue::AddrLabelDiff: { + auto *LHS = cast(asImpl().readExpr()); + auto *RHS = cast(asImpl().readExpr()); + return APValue(LHS, RHS); + } + case APValue::MemberPointer: { + APValue Result; + bool IsDerived = asImpl().readUInt32(); + auto *Member = asImpl().readDeclAs(); + unsigned PathSize = asImpl().readUInt32(); + Result.MakeEmptyMemberPointer(Member, IsDerived, PathSize); + const CXXRecordDecl **PathArray = Result.GetInternalMemberPointerPathPtr(); + for (unsigned LoopIdx = 0; LoopIdx < PathSize; LoopIdx++) + PathArray[LoopIdx] = asImpl().readDeclAs(); + return Result; + } + case APValue::LValue: { + uint64_t Bits = asImpl().readUInt32(); + 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 = asImpl().readUInt32(); + unsigned Version = asImpl().readUInt32(); + if (IsExpr) { + Base = APValue::LValueBase(asImpl().readExpr(), CallIndex, Version); + ElemTy = Base.get()->getType(); + } else { + Base = APValue::LValueBase(asImpl().readDeclAs(), + CallIndex, Version); + ElemTy = Base.get()->getType(); + } + } else { + QualType TypeInfo = asImpl().readType(); + QualType Type = asImpl().readType(); + Base = APValue::LValueBase::getTypeInfo( + TypeInfoLValue(TypeInfo.getTypePtr()), Type); + Base.getTypeInfoType(); + } + } + CharUnits Offset = CharUnits::fromQuantity(asImpl().readUInt32()); + unsigned PathLength = asImpl().readUInt32(); + 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 = asImpl().readUInt32(); + Decl *D = asImpl().readDeclAs(); + if (auto *RD = dyn_cast(D)) + ElemTy = getASTContext().getRecordType(RD); + else + ElemTy = cast(D)->getType(); + Path[LoopIdx] = + APValue::LValuePathEntry(APValue::BaseOrMemberType(D, Int)); + } else { + ElemTy = getASTContext().getAsArrayType(ElemTy)->getElementType(); + Path[LoopIdx] = + APValue::LValuePathEntry::ArrayIndex(asImpl().readUInt32()); + } + } + } else + Result.setLValue(Base, Offset, APValue::NoLValuePath{}, IsNullPtr); + return Result; + } } llvm_unreachable("Invalid APValue::ValueKind"); } @@ -10589,18 +10680,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) { @@ -10613,6 +10692,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 @@ -527,13 +527,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) & 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 @@ -5065,14 +5065,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 @@ -473,7 +473,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]]>{{$}}