[clang] cf34dd0 - [clang] Improve Serialization/Imporing/Dumping of APValues

via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 21 10:04:46 PDT 2020


Author: Tyker
Date: 2020-10-21T19:03:13+02:00
New Revision: cf34dd0c4e84b69bb901f9cd4f3491852238ec44

URL: https://github.com/llvm/llvm-project/commit/cf34dd0c4e84b69bb901f9cd4f3491852238ec44
DIFF: https://github.com/llvm/llvm-project/commit/cf34dd0c4e84b69bb901f9cd4f3491852238ec44.diff

LOG: [clang] Improve Serialization/Imporing/Dumping of APValues

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 all the missing Serialization and Importing for APValue.
 - Improve dumping of APValue when ASTContext isn't available.
 - Cleanup leftover from last patch.
 - Add Tests for Import and serialization.

Differential Revision: https://reviews.llvm.org/D63640

Added: 
    clang/test/ASTMerge/APValue/APValue.cpp

Modified: 
    clang/include/clang/AST/APValue.h
    clang/include/clang/AST/ASTContext.h
    clang/include/clang/AST/ASTImporter.h
    clang/lib/AST/APValue.cpp
    clang/lib/AST/ASTContext.cpp
    clang/lib/AST/ASTImporter.cpp
    clang/lib/AST/Expr.cpp
    clang/lib/Serialization/ASTReader.cpp
    clang/lib/Serialization/ASTWriter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h
index 0ee48f35a20a..04892d43e4a0 100644
--- a/clang/include/clang/AST/APValue.h
+++ b/clang/include/clang/AST/APValue.h
@@ -235,8 +235,10 @@ class APValue {
   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 @@ class APValue {
     *(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<APValue> 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 @@ class APValue {
     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<APValue> 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<LValuePathEntry>
+  setLValueUninit(LValueBase B, const CharUnits &O, unsigned Size,
+                  bool OnePastTheEnd, bool IsNullPtr);
+  MutableArrayRef<const CXXRecordDecl *>
+  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
index 60c4c1ce788e..d8c0b624ef71 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -289,9 +289,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// Mapping from GUIDs to the corresponding MSGuidDecl.
   mutable llvm::FoldingSet<MSGuidDecl> MSGuidDecls;
 
-  /// 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.
   ///

diff  --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h
index 205d7ec67754..a6d822ba2ea6 100644
--- 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 @@ class TypeSourceInfo;
     /// "to" context, or the import error.
     llvm::Expected<CXXBaseSpecifier *> 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<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);

diff  --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index 8d402ee8e3dc..919cd86ea9cf 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -882,17 +882,26 @@ void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
   LVal.IsNullPtr = IsNullPtr;
 }
 
-void APValue::setLValue(LValueBase B, const CharUnits &O,
-                        ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd,
-                        bool IsNullPtr) {
+MutableArrayRef<APValue::LValuePathEntry>
+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<LValuePathEntry> Path, bool IsOnePastTheEnd,
+                        bool IsNullPtr) {
+  MutableArrayRef<APValue::LValuePathEntry> 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 @@ void APValue::MakeArray(unsigned InitElts, unsigned Size) {
   Kind = Array;
 }
 
-void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
-                                ArrayRef<const CXXRecordDecl*> Path) {
+MutableArrayRef<APValue::LValuePathEntry>
+setLValueUninit(APValue::LValueBase B, const CharUnits &O, unsigned Size,
+                bool OnePastTheEnd, bool IsNullPtr);
+
+MutableArrayRef<const CXXRecordDecl *>
+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<ValueDecl>(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<const CXXRecordDecl *> Path) {
+  MutableArrayRef<const CXXRecordDecl *> 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
index bddaaa6e19ec..32bb3f991d95 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1005,9 +1005,6 @@ ASTContext::~ASTContext() {
 
   for (const auto &Value : ModuleInitializers)
     Value.second->~PerModuleInitializers();
-
-  for (APValue *Value : APValueCleanups)
-    Value->~APValue();
 }
 
 void ASTContext::setTraversalScope(const std::vector<Decl *> &TopLevelDecls) {

diff  --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 5a70d0ee9590..23720bf75a65 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -397,6 +397,7 @@ namespace clang {
     Error ImportImplicitMethods(const CXXRecordDecl *From, CXXRecordDecl *To);
 
     Expected<CXXCastPath> ImportCastPath(CastExpr *E);
+    Expected<APValue> ImportAPValue(const APValue &FromValue);
 
     using Designator = DesignatedInitExpr::Designator;
 
@@ -6692,18 +6693,11 @@ ExpectedStmt ASTNodeImporter::VisitAddrLabelExpr(AddrLabelExpr *E) {
 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 @@ ASTImporter::Import(const CXXBaseSpecifier *BaseSpec) {
   return Imported;
 }
 
+llvm::Expected<APValue> 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 @@ Expected<Selector> ASTImporter::Import(Selector FromSel) {
   return ToContext.Selectors.getSelector(FromSel.getNumArgs(), Idents.data());
 }
 
+llvm::Expected<APValue>
+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<APValue> 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<FieldDecl>(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<AddrLabelExpr>(ImpLHS),
+                            cast<AddrLabelExpr>(ImpRHS));
+    break;
+  }
+  case APValue::MemberPointer: {
+    const Decl *ImpMemPtrDecl =
+        importChecked(Err, FromValue.getMemberPointerDecl());
+    if (Err)
+      return std::move(Err);
+    MutableArrayRef<const CXXRecordDecl *> ToPath =
+        Result.setMemberPointerUninit(
+            cast<const ValueDecl>(ImpMemPtrDecl),
+            FromValue.isMemberPointerToDerivedMember(),
+            FromValue.getMemberPointerPath().size());
+    llvm::ArrayRef<const CXXRecordDecl *> 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<const CXXRecordDecl>(ImpDecl->getCanonicalDecl());
+    }
+    break;
+  }
+  case APValue::LValue:
+    APValue::LValueBase Base;
+    QualType FromElemTy;
+    if (FromValue.getLValueBase()) {
+      assert(!FromValue.getLValueBase().is<DynamicAllocLValue>() &&
+             "in C++20 dynamic allocation are transient so they shouldn't "
+             "appear in the AST");
+      if (!FromValue.getLValueBase().is<TypeInfoLValue>()) {
+        if (const auto *E =
+                FromValue.getLValueBase().dyn_cast<const Expr *>()) {
+          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<const ValueDecl *>()->getType();
+          const Decl *ImpDecl = importChecked(
+              Err, FromValue.getLValueBase().get<const ValueDecl *>());
+          if (Err)
+            return std::move(Err);
+          Base = APValue::LValueBase(cast<ValueDecl>(ImpDecl),
+                                     FromValue.getLValueBase().getCallIndex(),
+                                     FromValue.getLValueBase().getVersion());
+        }
+      } else {
+        FromElemTy = FromValue.getLValueBase().getTypeInfoType();
+        QualType ImpTypeInfo = importChecked(
+            Err,
+            QualType(FromValue.getLValueBase().get<TypeInfoLValue>().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<APValue::LValuePathEntry> ToPath = Result.setLValueUninit(
+          Base, Offset, PathLength, FromValue.isLValueOnePastTheEnd(),
+          FromValue.isNullPointer());
+      llvm::ArrayRef<APValue::LValuePathEntry> 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<CXXRecordDecl>(FromDecl))
+            FromElemTy = Importer.FromContext.getRecordType(RD);
+          else
+            FromElemTy = cast<ValueDecl>(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<DeclarationName> ASTImporter::HandleNameConflict(DeclarationName Name,
                                                           DeclContext *DC,
                                                           unsigned IDNS,

diff  --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 919d3220875c..c6b2c47a48fb 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -360,7 +360,6 @@ llvm::APSInt ConstantExpr::getResultAsAPSInt() const {
 }
 
 APValue ConstantExpr::getAPValueResult() const {
-  assert(hasAPValueResult());
 
   switch (ConstantExprBits.ResultKind) {
   case ConstantExpr::RSK_APValue:
@@ -370,6 +369,8 @@ APValue ConstantExpr::getAPValueResult() const {
         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
index b2780db85166..79fabfec54b4 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -8963,48 +8963,146 @@ ReadFixedPointSemantics(const SmallVectorImpl<uint64_t> &Record,
                                    HasUnsignedPadding);
 }
 
-static const llvm::fltSemantics &
-readAPFloatSemantics(ASTRecordReader &reader) {
-  return llvm::APFloatBase::EnumToSemantics(
-    static_cast<llvm::APFloatBase::Semantics>(reader.readInt()));
-}
-
 APValue ASTRecordReader::readAPValue() {
-  unsigned Kind = readInt();
-  switch ((APValue::ValueKind) Kind) {
+  auto Kind = static_cast<APValue::ValueKind>(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<llvm::APFloatBase::Semantics>(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<llvm::APFloatBase::Semantics>(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<FieldDecl>();
+    APValue Value = asImpl().readAPValue();
+    return APValue(FDecl, std::move(Value));
+  }
+  case APValue::AddrLabelDiff: {
+    auto *LHS = cast<AddrLabelExpr>(asImpl().readExpr());
+    auto *RHS = cast<AddrLabelExpr>(asImpl().readExpr());
+    return APValue(LHS, RHS);
+  }
+  case APValue::MemberPointer: {
+    APValue Result;
+    bool IsDerived = asImpl().readUInt32();
+    auto *Member = asImpl().readDeclAs<ValueDecl>();
+    unsigned PathSize = asImpl().readUInt32();
+    const CXXRecordDecl **PathArray =
+        Result.setMemberPointerUninit(Member, IsDerived, PathSize).data();
+    for (unsigned LoopIdx = 0; LoopIdx < PathSize; LoopIdx++)
+      PathArray[LoopIdx] =
+          asImpl().readDeclAs<const CXXRecordDecl>()->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<const Expr *>()->getType();
+        } else {
+          Base = APValue::LValueBase(asImpl().readDeclAs<const ValueDecl>(),
+                                     CallIndex, Version);
+          ElemTy = Base.get<const ValueDecl *>()->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<RecordType>()) {
+          unsigned Int = asImpl().readUInt32();
+          Decl *D = asImpl().readDeclAs<Decl>();
+          if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+            ElemTy = getASTContext().getRecordType(RD);
+          else
+            ElemTy = cast<ValueDecl>(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
index ed00a3bc6281..bbc8248ae22e 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5155,22 +5155,103 @@ void ASTRecordWriter::AddAPValue(const APValue &Value) {
     return;
   }
   case APValue::ComplexFloat: {
+    assert(llvm::APFloatBase::SemanticsToEnum(
+               Value.getComplexFloatImag().getSemantics()) ==
+           llvm::APFloatBase::SemanticsToEnum(
+               Value.getComplexFloatReal().getSemantics()));
     push_back(static_cast<uint64_t>(llvm::APFloatBase::SemanticsToEnum(
         Value.getComplexFloatReal().getSemantics())));
     AddAPFloat(Value.getComplexFloatReal());
-    push_back(static_cast<uint64_t>(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<AddrLabelExpr *>(Value.getAddrLabelDiffLHS()));
+    AddStmt(const_cast<AddrLabelExpr *>(Value.getAddrLabelDiffRHS()));
+    return;
+  case APValue::MemberPointer: {
+    push_back(Value.isMemberPointerToDerivedMember());
+    AddDeclRef(Value.getMemberPointerDecl());
+    ArrayRef<const CXXRecordDecl *> 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<const Expr *>() << 2 |
+              Value.getLValueBase().is<TypeInfoLValue>() << 3 |
+              Value.isNullPointer() << 4 |
+              static_cast<bool>(Value.getLValueBase()) << 5);
+    QualType ElemTy;
+    if (Value.getLValueBase()) {
+      assert(!Value.getLValueBase().is<DynamicAllocLValue>() &&
+             "in C++20 dynamic allocation are transient so they shouldn't "
+             "appear in the AST");
+      if (!Value.getLValueBase().is<TypeInfoLValue>()) {
+        push_back(Value.getLValueBase().getCallIndex());
+        push_back(Value.getLValueBase().getVersion());
+        if (const auto *E = Value.getLValueBase().dyn_cast<const Expr *>()) {
+          AddStmt(const_cast<Expr *>(E));
+          ElemTy = E->getType();
+        } else {
+          AddDeclRef(Value.getLValueBase().get<const ValueDecl *>());
+          ElemTy = Value.getLValueBase().get<const ValueDecl *>()->getType();
+        }
+      } else {
+        AddTypeRef(
+            QualType(Value.getLValueBase().get<TypeInfoLValue>().getType(), 0));
+        AddTypeRef(Value.getLValueBase().getTypeInfoType());
+        ElemTy = Value.getLValueBase().getTypeInfoType();
+      }
+    }
+    push_back(Value.getLValueOffset().getQuantity());
+    push_back(Value.getLValuePath().size());
+    if (Value.hasLValuePath()) {
+      ArrayRef<APValue::LValuePathEntry> Path = Value.getLValuePath();
+      for (auto Elem : Path) {
+        if (ElemTy->getAs<RecordType>()) {
+          push_back(Elem.getAsBaseOrMember().getInt());
+          const Decl *BaseOrMember = Elem.getAsBaseOrMember().getPointer();
+          if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
+            AddDeclRef(RD);
+            ElemTy = Writer->Context->getRecordType(RD);
+          } else {
+            const auto *VD = cast<ValueDecl>(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
index 000000000000..c8695fb6074b
--- /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


        


More information about the cfe-commits mailing list