Index: clang/include/clang/AST/APValue.h =================================================================== --- clang/include/clang/AST/APValue.h +++ clang/include/clang/AST/APValue.h @@ -185,6 +185,7 @@ friend class ASTReader; friend class ASTWriter; + friend class ASTImporter; private: ValueKind Kind; @@ -508,10 +509,13 @@ assert(isFixedPoint() && "Invalid accessor"); *(APFixedPoint *)(char *)Data.buffer = std::move(FX); } - void setVector(const APValue *E, unsigned N) { + void ReserveVector(unsigned N) { assert(isVector() && "Invalid accessor"); ((Vec*)(char*)Data.buffer)->Elts = new APValue[N]; ((Vec*)(char*)Data.buffer)->NumElts = N; + } + void setVector(const APValue *E, unsigned N) { + ReserveVector(N); for (unsigned i = 0; i != N; ++i) ((Vec*)(char*)Data.buffer)->Elts[i] = E[i]; } Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -271,9 +271,6 @@ llvm::DenseMap MaterializedTemporaryValues; - /// Used to cleanups APValues stored in the AST. - mutable llvm::SmallVector APValueCleanups; - /// A cache mapping a string value to a StringLiteral object with the same /// value. /// Index: clang/include/clang/AST/ASTImporter.h =================================================================== --- clang/include/clang/AST/ASTImporter.h +++ clang/include/clang/AST/ASTImporter.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_ASTIMPORTER_H #define LLVM_CLANG_AST_ASTIMPORTER_H +#include "clang/AST/APValue.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" @@ -324,6 +325,13 @@ /// "to" context, or the import error. llvm::Expected Import(const CXXBaseSpecifier *FromSpec); + /// Import the gieven APValue from the "from" context into + /// the "to" context. + /// + /// \return the equivalent APValue in the "from" Constext or the import + /// error. + llvm::Expected Import(const APValue &FromValue); + /// Import the definition of the given declaration, including all of /// the declarations it contains. LLVM_NODISCARD llvm::Error ImportDefinition(Decl *From); Index: clang/include/clang/AST/Expr.h =================================================================== --- clang/include/clang/AST/Expr.h +++ clang/include/clang/AST/Expr.h @@ -954,6 +954,7 @@ public: /// Describes the kind of result that can be trail-allocated. + /// Enumerator need to stay ordered by size of there storage. enum ResultStorageKind { RSK_None, RSK_Int64, RSK_APValue }; private: Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -827,9 +827,6 @@ for (const auto &Value : ModuleInitializers) Value.second->~PerModuleInitializers(); - - for (APValue *Value : APValueCleanups) - Value->~APValue(); } class ASTContext::ParentMap { Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -6369,21 +6369,15 @@ } ExpectedStmt ASTNodeImporter::VisitConstantExpr(ConstantExpr *E) { - auto Imp = importSeq(E->getSubExpr()); + auto Imp = importSeq(E->getSubExpr(), E->getAPValueResult()); if (!Imp) return Imp.takeError(); Expr *ToSubExpr; - std::tie(ToSubExpr) = *Imp; + APValue ToResult; + std::tie(ToSubExpr, ToResult) = *Imp; - // TODO : Handle APValue::ValueKind that require importing. - APValue::ValueKind Kind = E->getResultAPValueKind(); - if (Kind == APValue::Int || Kind == APValue::Float || - Kind == APValue::FixedPoint || Kind == APValue::ComplexFloat || - Kind == APValue::ComplexInt) - return ConstantExpr::Create(Importer.getToContext(), ToSubExpr, - E->getAPValueResult()); - return ConstantExpr::Create(Importer.getToContext(), ToSubExpr); + return ConstantExpr::Create(Importer.getToContext(), ToSubExpr, ToResult); } ExpectedStmt ASTNodeImporter::VisitParenExpr(ParenExpr *E) { @@ -8506,6 +8500,65 @@ 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 = [&](APValue *From, APValue *To, unsigned Size) { + for (unsigned Idx = 0; Idx < Size; Idx++) { + llvm::Expected Tmp = Import(From[Idx]); + if (Tmp.errorIsA()) { + 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: + case APValue::LValue: + case APValue::AddrLabelDiff: + case APValue::MemberPointer:; + // TODO: handle special cases. + } + if (Error) + return std::move(Error); + return Result; +} + DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name, DeclContext *DC, unsigned IDNS, Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -2347,6 +2347,11 @@ else if (Eval->Evaluated.needsCleanup()) getASTContext().addDestruction(&Eval->Evaluated); + if (auto *ConstantInit = dyn_cast(Eval->Value)) + if (ConstantExpr::getStorageKind(Eval->Evaluated) <= + ConstantInit->getResultStorageKind()) + ConstantInit->SetResult(Eval->Evaluated, getASTContext()); + Eval->IsEvaluating = false; Eval->WasEvaluated = true; Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -260,8 +260,9 @@ void ConstantExpr::DefaultInit(ResultStorageKind StorageKind) { ConstantExprBits.ResultKind = StorageKind; ConstantExprBits.APValueKind = APValue::None; - ConstantExprBits.HasCleanup = false; - if (StorageKind == ConstantExpr::RSK_APValue) + ConstantExprBits.BitWidth = 0; + ConstantExprBits.IsUnsigned = false; + if (StorageKind == RSK_APValue) ::new (getTrailingObjects()) APValue(); } @@ -308,9 +309,11 @@ } void ConstantExpr::MoveIntoResult(APValue &Value, const ASTContext &Context) { - assert(getStorageKind(Value) == ConstantExprBits.ResultKind && + assert(getStorageKind(Value) <= ConstantExprBits.ResultKind && "Invalid storage for this value kind"); ConstantExprBits.APValueKind = Value.getKind(); + if (!Value.hasValue()) + return; switch (ConstantExprBits.ResultKind) { case RSK_None: return; @@ -343,6 +346,8 @@ } APValue ConstantExpr::getAPValueResult() const { + if (ConstantExprBits.APValueKind == APValue::None) + return APValue(); switch (ConstantExprBits.ResultKind) { case ConstantExpr::RSK_APValue: return APValueResult(); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -11287,6 +11287,12 @@ FSI->markSafeWeakUse(Init); } + if (VDecl->isConstexpr()) { + Init = ConstantExpr::Create( + Context, Init, + ConstantExpr::getStorageKind(VDecl->getType()->getAs(), Context)); + } + // The initialization is usually a full-expression. // // FIXME: If this is a braced initialization of an aggregate, it is not Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -9115,41 +9115,69 @@ HasUnsignedPadding); } -APValue ASTReader::ReadAPValue(const RecordData &Record, unsigned &Idx) { - unsigned Kind = Record[Idx++]; +APValue ASTReader::ReadAPValue(const RecordData &Record, unsigned &RecordIdx) { + unsigned Kind = Record[RecordIdx++]; switch (Kind) { case APValue::None: return APValue(); case APValue::Indeterminate: return APValue::IndeterminateValue(); case APValue::Int: - return APValue(ReadAPSInt(Record, Idx)); + return APValue(ReadAPSInt(Record, RecordIdx)); case APValue::Float: { const llvm::fltSemantics &FloatSema = llvm::APFloatBase::EnumToSemantics( - static_cast(Record[Idx++])); - return APValue(ReadAPFloat(Record, FloatSema, Idx)); + static_cast(Record[RecordIdx++])); + return APValue(ReadAPFloat(Record, FloatSema, RecordIdx)); } case APValue::FixedPoint: { - FixedPointSemantics FPSema = ReadFixedPointSemantics(Record, Idx); - return APValue(APFixedPoint(ReadAPInt(Record, Idx), FPSema)); + FixedPointSemantics FPSema = ReadFixedPointSemantics(Record, RecordIdx); + return APValue(APFixedPoint(ReadAPInt(Record, RecordIdx), FPSema)); } case APValue::ComplexInt: { - llvm::APSInt First = ReadAPSInt(Record, Idx); - return APValue(std::move(First), ReadAPSInt(Record, Idx)); + llvm::APSInt First = ReadAPSInt(Record, RecordIdx); + return APValue(std::move(First), ReadAPSInt(Record, RecordIdx)); } case APValue::ComplexFloat: { const llvm::fltSemantics &FloatSema1 = llvm::APFloatBase::EnumToSemantics( - static_cast(Record[Idx++])); - llvm::APFloat First = ReadAPFloat(Record, FloatSema1, Idx); + static_cast(Record[RecordIdx++])); + llvm::APFloat First = ReadAPFloat(Record, FloatSema1, RecordIdx); const llvm::fltSemantics &FloatSema2 = llvm::APFloatBase::EnumToSemantics( - static_cast(Record[Idx++])); - return APValue(std::move(First), ReadAPFloat(Record, FloatSema2, Idx)); + 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(Record, LoopIdx); + 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(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(Record, RecordIdx); + for (unsigned LoopIdx = 0; LoopIdx < BasesLength; LoopIdx++) + Result.getStructField(LoopIdx) = ReadAPValue(Record, RecordIdx); + return Result; } - case APValue::LValue: - case APValue::Vector: - case APValue::Array: - case APValue::Struct: + case APValue::Union: + case APValue::LValue: case APValue::MemberPointer: case APValue::AddrLabelDiff: // TODO : Handle all these APValue::ValueKind. @@ -10883,18 +10911,6 @@ break; } - if (FirstInit && SecondInit && - ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { - ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), - VarDifferentInitializer) - << FirstName << FirstInit->getSourceRange(); - ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), - VarDifferentInitializer) - << SecondName << SecondInit->getSourceRange(); - Diagnosed = true; - break; - } - const bool FirstIsConstexpr = FirstVD->isConstexpr(); const bool SecondIsConstexpr = SecondVD->isConstexpr(); if (FirstIsConstexpr != SecondIsConstexpr) { @@ -10907,6 +10923,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/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -5441,10 +5441,26 @@ 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::LValue: case APValue::Union: case APValue::MemberPointer: case APValue::AddrLabelDiff: Index: clang/test/PCH/APValue.cpp =================================================================== --- /dev/null +++ clang/test/PCH/APValue.cpp @@ -0,0 +1,91 @@ + +// RUN: %clang_cc1 -std=gnu++17 -emit-pch %s -o %t.pch +// RUN: %clang_cc1 -std=gnu++17 -x c++ -include-pch %t.pch -ast-dump-all | FileCheck %s + +#ifndef EMIT +#define EMIT + +namespace Integer { + +constexpr int Unique_Int = int(6789); +//CHECK: VarDecl {{.*}} Unique_Int +//CHECK-NEXT: ConstantExpr {{.*}} 'int' 6789 + +constexpr __uint128_t Unique_Int128 = ((__uint128_t)0x75f17d6b3588f843 << 64) | 0xb13dea7c9c324e51; +//CHECK: VarDecl {{.*}} Unique_Int128 +//CHECK-NEXT: ConstantExpr {{.*}} 'unsigned __int128' 156773562844924187900898496343692168785 + +} + +namespace FloatingPoint { + +constexpr double Unique_Double = double(567890.67890); +//CHECK: VarDecl {{.*}} Unique_Double +//CHECK-NEXT: ConstantExpr {{.*}} 'double' 5.678907e+05 + +} + +// FIXME: Add test for FixePoint, ComplexInt, ComplexFloat. +// as they are C features they need to be treated differently. + +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}} + +} + +#endif \ No newline at end of file