Tyker created this revision.
Tyker added a reviewer: rsmith.
Herald added a reviewer: martong.
Herald added a reviewer: shafik.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Tyker edited the summary of this revision.
Herald added a subscriber: rnkovacs.
Changes:
- initializer expressions of constexpr variable are now wraped in a
ConstantExpr. this is mainly used for testing purposes. the old caching system
has not yet been removed.
- Add Serialization and Importing of APValues for Struct, Array and Vectors.
- Cleanup leftover from last patch.
- Add Tests.
Repository:
rC Clang
https://reviews.llvm.org/D63640
Files:
clang/include/clang/AST/APValue.h
clang/include/clang/AST/ASTContext.h
clang/include/clang/AST/ASTImporter.h
clang/include/clang/AST/Expr.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/Decl.cpp
clang/lib/AST/Expr.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/PCH/APValue.cpp
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
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/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<llvm::APFloatBase::Semantics>(Record[Idx++]));
- return APValue(ReadAPFloat(Record, FloatSema, Idx));
+ static_cast<llvm::APFloatBase::Semantics>(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<llvm::APFloatBase::Semantics>(Record[Idx++]));
- llvm::APFloat First = ReadAPFloat(Record, FloatSema1, Idx);
+ static_cast<llvm::APFloatBase::Semantics>(Record[RecordIdx++]));
+ llvm::APFloat First = ReadAPFloat(Record, FloatSema1, RecordIdx);
const llvm::fltSemantics &FloatSema2 = llvm::APFloatBase::EnumToSemantics(
- static_cast<llvm::APFloatBase::Semantics>(Record[Idx++]));
- return APValue(std::move(First), ReadAPFloat(Record, FloatSema2, Idx));
+ static_cast<llvm::APFloatBase::Semantics>(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/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<Type>(), Context));
+ }
+
// The initialization is usually a full-expression.
//
// FIXME: If this is a braced initialization of an aggregate, it is not
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>()) 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/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<ConstantExpr>(Eval->Value))
+ if (ConstantExpr::getStorageKind(Eval->Evaluated) <=
+ ConstantInit->getResultStorageKind())
+ ConstantInit->SetResult(Eval->Evaluated, getASTContext());
+
Eval->IsEvaluating = false;
Eval->WasEvaluated = true;
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<APValue> 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<APValue> Tmp = Import(From[Idx]);
+ if (Tmp.errorIsA<ImportError>()) {
+ 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/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/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -954,6 +954,7 @@
public:
/// Describes the kind of result that can be trail-allocated.
+ /// Enumerator need to stay ordered by size of there storage.
enum ResultStorageKind { RSK_None, RSK_Int64, RSK_APValue };
private:
Index: clang/include/clang/AST/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<CXXBaseSpecifier *> 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<APValue> 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/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -271,9 +271,6 @@
llvm::DenseMap<const MaterializeTemporaryExpr *, APValue *>
MaterializedTemporaryValues;
- /// Used to cleanups APValues stored in the AST.
- mutable llvm::SmallVector<APValue *, 0> APValueCleanups;
-
/// A cache mapping a string value to a StringLiteral object with the same
/// value.
///
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];
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits