[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
This commit is contained in:
		
							parent
							
								
									8b7dac81d3
								
							
						
					
					
						commit
						cf34dd0c4e
					
				| 
						 | 
				
			
			@ -235,8 +235,10 @@ public:
 | 
			
		|||
  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 @@ public:
 | 
			
		|||
    *(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 @@ private:
 | 
			
		|||
    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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
  ///
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
  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;
 | 
			
		||||
  Kind = MemberPointer;
 | 
			
		||||
  MPD->MemberAndIsDerivedMember.setPointer(
 | 
			
		||||
      Member ? cast<ValueDecl>(Member->getCanonicalDecl()) : nullptr);
 | 
			
		||||
  MPD->MemberAndIsDerivedMember.setInt(IsDerivedMember);
 | 
			
		||||
  MPD->resizePath(Path.size());
 | 
			
		||||
  for (unsigned I = 0; I != Path.size(); ++I)
 | 
			
		||||
    MPD->getPath()[I] = Path[I]->getCanonicalDecl();
 | 
			
		||||
  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)
 | 
			
		||||
    InternalPath[I] = Path[I]->getCanonicalDecl();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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));
 | 
			
		||||
    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;
 | 
			
		||||
  }
 | 
			
		||||
  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();
 | 
			
		||||
  }
 | 
			
		||||
  llvm_unreachable("Invalid APValue::ValueKind");
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
		Loading…
	
		Reference in New Issue