diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -235,8 +235,10 @@ struct UninitArray {}; struct UninitStruct {}; - friend class ASTReader; + friend class ASTRecordReader; friend class ASTWriter; + friend class ASTImporter; + friend class ASTNodeImporter; private: ValueKind Kind; @@ -569,11 +571,9 @@ *(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; + MutableArrayRef InternalElts = setVectorUninit(N); for (unsigned i = 0; i != N; ++i) - ((Vec*)(char*)Data.buffer)->Elts[i] = E[i]; + InternalElts[i] = E[i]; } void setComplexInt(APSInt R, APSInt I) { assert(R.getBitWidth() == I.getBitWidth() && @@ -656,6 +656,24 @@ new ((void*)(char*)Data.buffer) AddrLabelDiffData(); Kind = AddrLabelDiff; } + +private: + /// The following functions are used as part of initialization, during + /// deserialization and importing. Reserve the space so that it can be + /// filled in by those steps. + MutableArrayRef setVectorUninit(unsigned N) { + assert(isVector() && "Invalid accessor"); + Vec *V = ((Vec *)(char *)Data.buffer); + V->Elts = new APValue[N]; + V->NumElts = N; + return {V->Elts, V->NumElts}; + } + MutableArrayRef + setLValueUninit(LValueBase B, const CharUnits &O, unsigned Size, + bool OnePastTheEnd, bool IsNullPtr); + MutableArrayRef + setMemberPointerUninit(const ValueDecl *Member, bool IsDerivedMember, + unsigned Size); }; } // end namespace clang. diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -289,9 +289,6 @@ /// Mapping from GUIDs to the corresponding MSGuidDecl. mutable llvm::FoldingSet MSGuidDecls; - /// 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. /// diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h --- a/clang/include/clang/AST/ASTImporter.h +++ b/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/ExprCXX.h" @@ -503,6 +504,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); diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -882,17 +882,26 @@ LVal.IsNullPtr = IsNullPtr; } -void APValue::setLValue(LValueBase B, const CharUnits &O, - ArrayRef Path, bool IsOnePastTheEnd, - bool IsNullPtr) { +MutableArrayRef +APValue::setLValueUninit(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); + return {LVal.getPath(), Size}; +} + +void APValue::setLValue(LValueBase B, const CharUnits &O, + ArrayRef Path, bool IsOnePastTheEnd, + bool IsNullPtr) { + MutableArrayRef InternalPath = + setLValueUninit(B, O, Path.size(), IsOnePastTheEnd, IsNullPtr); + memcpy(InternalPath.data(), Path.data(), + Path.size() * sizeof(LValuePathEntry)); } const ValueDecl *APValue::getMemberPointerDecl() const { @@ -929,15 +938,27 @@ Kind = Array; } -void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, - ArrayRef Path) { +MutableArrayRef +setLValueUninit(APValue::LValueBase B, const CharUnits &O, unsigned Size, + bool OnePastTheEnd, bool IsNullPtr); + +MutableArrayRef +APValue::setMemberPointerUninit(const ValueDecl *Member, bool IsDerivedMember, + unsigned Size) { assert(isAbsent() && "Bad state change"); - MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData; + MemberPointerData *MPD = new ((void *)(char *)Data.buffer) MemberPointerData; Kind = MemberPointer; MPD->MemberAndIsDerivedMember.setPointer( Member ? cast(Member->getCanonicalDecl()) : nullptr); MPD->MemberAndIsDerivedMember.setInt(IsDerivedMember); - MPD->resizePath(Path.size()); + MPD->resizePath(Size); + return {MPD->getPath(), MPD->PathLength}; +} + +void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, + ArrayRef Path) { + MutableArrayRef InternalPath = + setMemberPointerUninit(Member, IsDerivedMember, Path.size()); for (unsigned I = 0; I != Path.size(); ++I) - MPD->getPath()[I] = Path[I]->getCanonicalDecl(); + InternalPath[I] = Path[I]->getCanonicalDecl(); } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1005,9 +1005,6 @@ for (const auto &Value : ModuleInitializers) Value.second->~PerModuleInitializers(); - - for (APValue *Value : APValueCleanups) - Value->~APValue(); } void ASTContext::setTraversalScope(const std::vector &TopLevelDecls) { diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -397,6 +397,7 @@ Error ImportImplicitMethods(const CXXRecordDecl *From, CXXRecordDecl *To); Expected ImportCastPath(CastExpr *E); + Expected ImportAPValue(const APValue &FromValue); using Designator = DesignatedInitExpr::Designator; @@ -6692,18 +6693,11 @@ ExpectedStmt ASTNodeImporter::VisitConstantExpr(ConstantExpr *E) { Error Err = Error::success(); auto ToSubExpr = importChecked(Err, E->getSubExpr()); + auto ToResult = importChecked(Err, E->getAPValueResult()); if (Err) return std::move(Err); - // 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) { Error Err = Error::success(); @@ -8804,6 +8798,11 @@ return Imported; } +llvm::Expected ASTImporter::Import(const APValue &FromValue) { + ASTNodeImporter Importer(*this); + return Importer.ImportAPValue(FromValue); +} + Error ASTImporter::ImportDefinition(Decl *From) { ExpectedDecl ToOrErr = Import(From); if (!ToOrErr) @@ -8934,6 +8933,172 @@ return ToContext.Selectors.getSelector(FromSel.getNumArgs(), Idents.data()); } +llvm::Expected +ASTNodeImporter::ImportAPValue(const APValue &FromValue) { + APValue Result; + llvm::Error Err = llvm::Error::success(); + auto ImportLoop = [&](const APValue *From, APValue *To, unsigned Size) { + for (unsigned Idx = 0; Idx < Size; Idx++) { + APValue Tmp = importChecked(Err, From[Idx]); + To[Idx] = Tmp; + } + }; + 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(); + MutableArrayRef Elts = + Result.setVectorUninit(FromValue.getVectorLength()); + ImportLoop( + ((const APValue::Vec *)(const char *)FromValue.Data.buffer)->Elts, + Elts.data(), 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(); + const Decl *ImpFDecl = importChecked(Err, FromValue.getUnionField()); + APValue ImpValue = importChecked(Err, FromValue.getUnionValue()); + if (Err) + return std::move(Err); + Result.setUnion(cast(ImpFDecl), ImpValue); + break; + } + case APValue::AddrLabelDiff: { + Result.MakeAddrLabelDiff(); + const Expr *ImpLHS = importChecked(Err, FromValue.getAddrLabelDiffLHS()); + const Expr *ImpRHS = importChecked(Err, FromValue.getAddrLabelDiffRHS()); + if (Err) + return std::move(Err); + Result.setAddrLabelDiff(cast(ImpLHS), + cast(ImpRHS)); + break; + } + case APValue::MemberPointer: { + const Decl *ImpMemPtrDecl = + importChecked(Err, FromValue.getMemberPointerDecl()); + if (Err) + return std::move(Err); + MutableArrayRef ToPath = + Result.setMemberPointerUninit( + cast(ImpMemPtrDecl), + FromValue.isMemberPointerToDerivedMember(), + FromValue.getMemberPointerPath().size()); + llvm::ArrayRef FromPath = + Result.getMemberPointerPath(); + for (unsigned Idx = 0; Idx < FromValue.getMemberPointerPath().size(); + Idx++) { + const Decl *ImpDecl = importChecked(Err, FromPath[Idx]); + if (Err) + return std::move(Err); + ToPath[Idx] = cast(ImpDecl->getCanonicalDecl()); + } + break; + } + case APValue::LValue: + APValue::LValueBase Base; + QualType FromElemTy; + if (FromValue.getLValueBase()) { + assert(!FromValue.getLValueBase().is() && + "in C++20 dynamic allocation are transient so they shouldn't " + "appear in the AST"); + if (!FromValue.getLValueBase().is()) { + if (const auto *E = + FromValue.getLValueBase().dyn_cast()) { + FromElemTy = E->getType(); + const Expr *ImpExpr = importChecked(Err, E); + if (Err) + return std::move(Err); + Base = APValue::LValueBase(ImpExpr, + FromValue.getLValueBase().getCallIndex(), + FromValue.getLValueBase().getVersion()); + } else { + FromElemTy = + FromValue.getLValueBase().get()->getType(); + const Decl *ImpDecl = importChecked( + Err, FromValue.getLValueBase().get()); + if (Err) + return std::move(Err); + Base = APValue::LValueBase(cast(ImpDecl), + FromValue.getLValueBase().getCallIndex(), + FromValue.getLValueBase().getVersion()); + } + } else { + FromElemTy = FromValue.getLValueBase().getTypeInfoType(); + QualType ImpTypeInfo = importChecked( + Err, + QualType(FromValue.getLValueBase().get().getType(), + 0)); + QualType ImpType = + importChecked(Err, FromValue.getLValueBase().getTypeInfoType()); + if (Err) + return std::move(Err); + Base = APValue::LValueBase::getTypeInfo( + TypeInfoLValue(ImpTypeInfo.getTypePtr()), ImpType); + } + } + CharUnits Offset = FromValue.getLValueOffset(); + unsigned PathLength = FromValue.getLValuePath().size(); + Result.MakeLValue(); + if (FromValue.hasLValuePath()) { + MutableArrayRef ToPath = Result.setLValueUninit( + Base, Offset, PathLength, FromValue.isLValueOnePastTheEnd(), + FromValue.isNullPointer()); + llvm::ArrayRef FromPath = + FromValue.getLValuePath(); + for (unsigned LoopIdx = 0; LoopIdx < PathLength; LoopIdx++) { + if (FromElemTy->isRecordType()) { + const Decl *FromDecl = + FromPath[LoopIdx].getAsBaseOrMember().getPointer(); + const Decl *ImpDecl = importChecked(Err, FromDecl); + if (Err) + return std::move(Err); + if (auto *RD = dyn_cast(FromDecl)) + FromElemTy = Importer.FromContext.getRecordType(RD); + else + FromElemTy = cast(FromDecl)->getType(); + ToPath[LoopIdx] = APValue::LValuePathEntry(APValue::BaseOrMemberType( + ImpDecl, FromPath[LoopIdx].getAsBaseOrMember().getInt())); + } else { + FromElemTy = + Importer.FromContext.getAsArrayType(FromElemTy)->getElementType(); + ToPath[LoopIdx] = APValue::LValuePathEntry::ArrayIndex( + FromPath[LoopIdx].getAsArrayIndex()); + } + } + } else + Result.setLValue(Base, Offset, APValue::NoLValuePath{}, + FromValue.isNullPointer()); + } + if (Err) + return std::move(Err); + return Result; +} + Expected ASTImporter::HandleNameConflict(DeclarationName Name, DeclContext *DC, unsigned IDNS, diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -360,7 +360,6 @@ } APValue ConstantExpr::getAPValueResult() const { - assert(hasAPValueResult()); switch (ConstantExprBits.ResultKind) { case ConstantExpr::RSK_APValue: @@ -370,6 +369,8 @@ llvm::APSInt(llvm::APInt(ConstantExprBits.BitWidth, Int64Result()), ConstantExprBits.IsUnsigned)); case ConstantExpr::RSK_None: + if (ConstantExprBits.APValueKind == APValue::Indeterminate) + return APValue::IndeterminateValue(); return APValue(); } llvm_unreachable("invalid ResultKind"); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -8963,48 +8963,146 @@ 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: { llvm::FixedPointSemantics FPSema = ReadFixedPointSemantics(Record, Idx); return APValue(llvm::APFixedPoint(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); - 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 &FloatSema = llvm::APFloatBase::EnumToSemantics( + static_cast(asImpl().readUInt32())); + llvm::APFloat First = readAPFloat(FloatSema); + return APValue(std::move(First), asImpl().readAPFloat(FloatSema)); + } + case APValue::Vector: { + APValue Result; + Result.MakeVector(); + unsigned Length = asImpl().readUInt32(); + (void)Result.setVectorUninit(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(); + const CXXRecordDecl **PathArray = + Result.setMemberPointerUninit(Member, IsDerived, PathSize).data(); + for (unsigned LoopIdx = 0; LoopIdx < PathSize; LoopIdx++) + PathArray[LoopIdx] = + asImpl().readDeclAs()->getCanonicalDecl(); + 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) { + APValue::LValuePathEntry *Path = + Result + .setLValueUninit(Base, Offset, PathLength, IsLValueOnePastTheEnd, + IsNullPtr) + .data(); + 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"); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5155,22 +5155,103 @@ return; } case APValue::ComplexFloat: { + assert(llvm::APFloatBase::SemanticsToEnum( + Value.getComplexFloatImag().getSemantics()) == + llvm::APFloatBase::SemanticsToEnum( + Value.getComplexFloatReal().getSemantics())); push_back(static_cast(llvm::APFloatBase::SemanticsToEnum( Value.getComplexFloatReal().getSemantics()))); AddAPFloat(Value.getComplexFloatReal()); - push_back(static_cast(llvm::APFloatBase::SemanticsToEnum( - Value.getComplexFloatImag().getSemantics()))); 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()) { + assert(!Value.getLValueBase().is() && + "in C++20 dynamic allocation are transient so they shouldn't " + "appear in the AST"); + 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"); diff --git a/clang/test/ASTMerge/APValue/APValue.cpp b/clang/test/ASTMerge/APValue/APValue.cpp new file mode 100644 --- /dev/null +++ b/clang/test/ASTMerge/APValue/APValue.cpp @@ -0,0 +1,462 @@ +// 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 + +// XFAIL: * + +#ifndef EMIT +#define EMIT + +namespace Integer { + +consteval int fint() { + return 6789; +} + +int Unique_Int = fint(); +//CHECK: VarDecl {{.*}} Unique_Int +//CHECK-NEXT: ConstantExpr {{.*}} 'int' +//CHECK-NEXT: value: Int 6789 + +consteval __uint128_t fint128() { + return ((__uint128_t)0x75f17d6b3588f843 << 64) | 0xb13dea7c9c324e51; +} + +constexpr __uint128_t Unique_Int128 = fint128(); +//CHECK: VarDecl {{.*}} Unique_Int128 +//CHECK-NEXT: value: Int 156773562844924187900898496343692168785 +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: Int 156773562844924187900898496343692168785 + +} // namespace Integer + +namespace FloatingPoint { + +consteval double fdouble() { + return double(567890.67890); +} + +double Unique_Double = fdouble(); +//CHECK: VarDecl {{.*}} Unique_Double +//CHECK-NEXT: ConstantExpr {{.*}} +//CHECK-NEXT: value: Float 5.678907e+05 + +} // namespace FloatingPoint + +// FIXME: Add test for FixedPoint, ComplexInt, ComplexFloat, AddrLabelDiff. + +namespace Struct { + +struct B { + int i; + double d; +}; + +consteval B fB() { + return B{1, 0.7}; +} + +constexpr B Basic_Struct = fB(); +//CHECK: VarDecl {{.*}} Basic_Struct +//CHECK-NEXT: value: Struct +//CHECK-NEXT: fields: Int 1, Float 7.000000e-01 +//CHECK-NEXT: ImplicitCastExpr +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: Struct +//CHECK-NEXT: fields: Int 1, Float 7.000000e-01 + +struct C { + int i = 9; +}; + +struct A : B { + constexpr A(B b, int I, double D, C _c) : B(b), i(I), d(D), c(_c) {} + int i; + double d; + C c; +}; + +consteval A fA() { + return A(Basic_Struct, 1, 79.789, {}); +} + +A Advanced_Struct = fA(); +//CHECK: VarDecl {{.*}} Advanced_Struct +//CHECK-NEXT: ConstantExpr {{.*}} +//CHECK-NEXT: value: Struct +//CHECK-NEXT: base: Struct +//CHECK-NEXT: fields: Int 1, Float 7.000000e-01 +//CHECK-NEXT: fields: Int 1, Float 7.978900e+01 +//CHECK-NEXT: field: Struct +//CHECK-NEXT: field: Int 9 + +} // namespace Struct + +namespace Vector { + +using v4si = int __attribute__((__vector_size__(16))); + +consteval v4si fv4si() { + return (v4si){8, 2, 3}; +} + +v4si Vector_Int = fv4si(); +//CHECK: VarDecl {{.*}} Vector_Int +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: Vector length=4 +//CHECK-NEXT: elements: Int 8, Int 2, Int 3, Int 0 + +} // namespace Vector + +namespace Array { + +struct B { + int arr[6]; +}; + +consteval B fint() { + return B{1, 2, 3, 4, 5, 6}; +} + +B Array_Int = fint(); +//CHECK: VarDecl {{.*}} Array_Int +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: Struct +//CHECK-NEXT: field: Array size=6 +//CHECK-NEXT: elements: Int 1, Int 2, Int 3, Int 4 +//CHECK-NEXT: elements: Int 5, Int 6 + +struct A { + int i = 789; + double d = 67890.09876; +}; + +struct C { + A arr[3]; +}; + +consteval C fA() { + return {{A{}, A{-45678, 9.8}, A{9}}}; +} + +C Array2_Struct = fA(); +//CHECK: VarDecl {{.*}} Array2_Struct +//CHECK-NEXT: ConstantExpr {{.*}} + +using v4si = int __attribute__((__vector_size__(16))); + +struct D { + v4si arr[2]; +}; + +consteval D fv4si() { + return {{{1, 2, 3, 4}, {4, 5, 6, 7}}}; +} + +D Array_Vector = fv4si(); +//CHECK: VarDecl {{.*}} Array_Vector +//CHECK-NEXT: ConstantExpr {{.*}} +//CHECK-NEXT: value: Struct +//CHECK-NEXT: field: Array size=2 +//CHECK-NEXT: element: Vector length=4 +//CHECK-NEXT: elements: Int 1, Int 2, Int 3, Int 4 +//CHECK-NEXT: element: Vector length=4 +//CHECK-NEXT: elements: Int 4, Int 5, Int 6, Int 7 + +} // namespace Array + +namespace Union { + +struct A { + int i = 6789; + float f = 987.9876; +}; + +union U { + int i; + A a{567890, 9876.5678f}; +}; + +consteval U fU1() { + return U{0}; +} + +U Unique_Union1 = fU1(); +//CHECK: VarDecl {{.*}} Unique_Union +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: Union .i Int 0 + +consteval U fU() { + return U{}; +} + +U Unique_Union2 = fU(); +//CHECK: VarDecl {{.*}} Unique_Union +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: Union .a +//CHECK-NEXT: Struct +//CHECK-NEXT: fields: Int 567890, Float 9.876567e+03 + +} // namespace Union + +namespace MemberPointer { + +struct A { + struct B { + struct C { + struct D { + struct E { + struct F { + struct G { + int i; + }; + }; + }; + }; + }; + }; +}; + +consteval auto fmem_ptr() -> decltype(&A::B::C::D::E::F::G::i) { + return &A::B::C::D::E::F::G::i; +} + +auto MemberPointer1 = fmem_ptr(); +//CHECK: VarDecl {{.*}} MemberPointer1 +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: MemberPointer &G::i + +struct A1 { + struct B1 { + int f() const { + return 0; + } + }; +}; + +consteval auto fmem_ptr2() { + return &A1::B1::f; +} + +auto MemberPointer2 = fmem_ptr2(); +//CHECK: VarDecl {{.*}} MemberPointer2 +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: MemberPointer &B1::f + +} // namespace MemberPointer + +namespace std { +struct type_info; +}; + +namespace LValue { + +constexpr int g = 0; + +consteval const int &fg_ref() { + return g; +} + +const int &g_ref = fg_ref(); +//CHECK: VarDecl {{.*}} g_ref +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: LValue &g + +consteval const int *fint_ptr() { + return &g; +} + +const int *g_ptr = fint_ptr(); +//CHECK: VarDecl {{.*}} g_ptr +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: LValue &g + +consteval const int *fnull_ptr() { + return nullptr; +} + +const int *ptr2 = fnull_ptr(); +//CHECK: VarDecl {{.*}} ptr2 +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: LValue nullptr + +int fconst(); + +consteval auto ffunc_ptr() { + return &fconst; +} + +int (*func_ptr)() = ffunc_ptr(); +//CHECK: VarDecl {{.*}} func_ptr +//CHECK-NEXT: ConstantExpr {{.*}} +//CHECK-NEXT: value: LValue &fconst + +struct A { + int Arr[6] = {0, 1, 3, 4, 5, 9}; + int i = 0; +}; + +struct D { + A arr[6] = {}; +}; + +consteval D fA() { + return {}; +} + +constexpr D Arr = fA(); +// CHECK: VarDecl {{.*}} Arr +// CHECK-NEXT: value: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 +// CHECK-NEXT: ImplicitCastExpr +// CHECK-NEXT: ConstantExpr +// CHECK-NEXT: value: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 +// CHECK-NEXT: element: Struct +// CHECK-NEXT: field: Array size=6 +// CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +// CHECK-NEXT: elements: Int 5, Int 9 +// CHECK-NEXT: field: Int 0 + +consteval const int &fconstintref() { + return Arr.arr[0].i; +} + +const int &ArrayStructRef1 = fconstintref(); +//CHECK: VarDecl {{.*}} ArrayStructRef1 +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: LValue &Arr.arr[0].i + +consteval const int &fconstintref2() { + return Arr.arr[1].Arr[5]; +} + +const int &ArrayStructRef2 = fconstintref2(); +//CHECK: VarDecl {{.*}} ArrayStructRef2 +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: LValue &Arr.arr[1].Arr[5] + +consteval const int *fconststar() { + return &ArrayStructRef2; +} + +const int *ArrayStructRef3 = fconststar(); +//CHECK: VarDecl {{.*}} ArrayStructRef3 +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: LValue &Arr.arr[1].Arr[5] + +struct B : A { +}; + +struct C { + B b; +}; + +consteval C fC() { + return {}; +} + +C c = fC(); +//CHECK: VarDecl {{.*}} c +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: Struct +//CHECK-NEXT: field: Struct +//CHECK-NEXT: base: Struct +//CHECK-NEXT: field: Array size=6 +//CHECK-NEXT: elements: Int 0, Int 1, Int 3, Int 4 +//CHECK-NEXT: elements: Int 5, Int 9 +//CHECK-NEXT: field: Int 0 + +consteval const int &f2constintref() { + return c.b.i; +} + +const int &StructPathRef = f2constintref(); +//CHECK: VarDecl {{.*}} StructPathRef +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: LValue &c.b.A::i + +consteval const std::type_info *ftype_info() { + return &typeid(c); +} + +const std::type_info *T1 = ftype_info(); +//CHECK: VarDecl {{.*}} T1 +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT:value: LValue &typeid(LValue::C) + +consteval const std::type_info *ftype_info2() { + return &typeid(Arr.arr[1].Arr[2]); +} + +const std::type_info *T2 = ftype_info2(); +//CHECK: VarDecl {{.*}} T2 +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: LValue &typeid(int) + +consteval const char *fstring() { + return "test"; +} + +const char *cptr = fstring(); +//CHECK: VarDecl {{.*}} cptr +//CHECK-NEXT: ConstantExpr +//CHECK-NEXT: value: LValue &"test"[0] + +} // namespace LValue + +#endif