summaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/AST')
-rw-r--r--contrib/llvm-project/clang/lib/AST/APValue.cpp38
-rw-r--r--contrib/llvm-project/clang/lib/AST/ASTConcept.cpp68
-rw-r--r--contrib/llvm-project/clang/lib/AST/ASTContext.cpp1169
-rw-r--r--contrib/llvm-project/clang/lib/AST/ASTDiagnostic.cpp25
-rw-r--r--contrib/llvm-project/clang/lib/AST/ASTImporter.cpp991
-rw-r--r--contrib/llvm-project/clang/lib/AST/ASTStructuralEquivalence.cpp116
-rw-r--r--contrib/llvm-project/clang/lib/AST/ASTTypeTraits.cpp17
-rw-r--r--contrib/llvm-project/clang/lib/AST/CXXInheritance.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/AST/Comment.cpp21
-rw-r--r--contrib/llvm-project/clang/lib/AST/CommentLexer.cpp7
-rw-r--r--contrib/llvm-project/clang/lib/AST/CommentParser.cpp6
-rw-r--r--contrib/llvm-project/clang/lib/AST/CommentSema.cpp61
-rw-r--r--contrib/llvm-project/clang/lib/AST/ComparisonCategories.cpp53
-rw-r--r--contrib/llvm-project/clang/lib/AST/Decl.cpp242
-rw-r--r--contrib/llvm-project/clang/lib/AST/DeclBase.cpp18
-rw-r--r--contrib/llvm-project/clang/lib/AST/DeclCXX.cpp293
-rw-r--r--contrib/llvm-project/clang/lib/AST/DeclObjC.cpp66
-rw-r--r--contrib/llvm-project/clang/lib/AST/DeclPrinter.cpp86
-rw-r--r--contrib/llvm-project/clang/lib/AST/DeclTemplate.cpp311
-rw-r--r--contrib/llvm-project/clang/lib/AST/DeclarationName.cpp25
-rw-r--r--contrib/llvm-project/clang/lib/AST/Expr.cpp261
-rw-r--r--contrib/llvm-project/clang/lib/AST/ExprCXX.cpp119
-rw-r--r--contrib/llvm-project/clang/lib/AST/ExprClassification.cpp6
-rw-r--r--contrib/llvm-project/clang/lib/AST/ExprConcepts.cpp218
-rw-r--r--contrib/llvm-project/clang/lib/AST/ExprConstant.cpp2812
-rw-r--r--contrib/llvm-project/clang/lib/AST/ExternalASTMerger.cpp128
-rw-r--r--contrib/llvm-project/clang/lib/AST/ExternalASTSource.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/AST/FormatString.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/AST/FormatStringParsing.h13
-rw-r--r--contrib/llvm-project/clang/lib/AST/InheritViz.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Block.cpp87
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Block.h140
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Boolean.h148
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/ByteCodeEmitter.cpp175
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/ByteCodeEmitter.h112
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.cpp580
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.h331
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/ByteCodeGenError.cpp14
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/ByteCodeGenError.h46
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/ByteCodeStmtGen.cpp263
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/ByteCodeStmtGen.h89
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Context.cpp128
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Context.h86
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Descriptor.cpp292
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Descriptor.h220
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Disasm.cpp69
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.cpp253
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.h129
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Frame.cpp14
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Frame.h45
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Function.cpp48
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Function.h163
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Integral.h269
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Interp.cpp417
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Interp.h957
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/InterpFrame.cpp193
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/InterpFrame.h153
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/InterpStack.cpp78
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/InterpStack.h113
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/InterpState.cpp74
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/InterpState.h112
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Opcode.h30
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Opcodes.td422
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Pointer.cpp193
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Pointer.h353
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/PrimType.cpp23
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/PrimType.h115
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Program.cpp364
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Program.h220
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Record.cpp46
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Record.h121
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Source.cpp39
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Source.h118
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/State.cpp158
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/State.h133
-rw-r--r--contrib/llvm-project/clang/lib/AST/ItaniumCXXABI.cpp70
-rw-r--r--contrib/llvm-project/clang/lib/AST/ItaniumMangle.cpp168
-rw-r--r--contrib/llvm-project/clang/lib/AST/JSONNodeDumper.cpp66
-rw-r--r--contrib/llvm-project/clang/lib/AST/Mangle.cpp20
-rw-r--r--contrib/llvm-project/clang/lib/AST/MicrosoftCXXABI.cpp36
-rw-r--r--contrib/llvm-project/clang/lib/AST/MicrosoftMangle.cpp101
-rw-r--r--contrib/llvm-project/clang/lib/AST/NSAPI.cpp14
-rw-r--r--contrib/llvm-project/clang/lib/AST/NestedNameSpecifier.cpp6
-rw-r--r--contrib/llvm-project/clang/lib/AST/ODRHash.cpp12
-rw-r--r--contrib/llvm-project/clang/lib/AST/OpenMPClause.cpp128
-rw-r--r--contrib/llvm-project/clang/lib/AST/PrintfFormatString.cpp20
-rw-r--r--contrib/llvm-project/clang/lib/AST/QualTypeNames.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/AST/RawCommentList.cpp64
-rw-r--r--contrib/llvm-project/clang/lib/AST/RecordLayoutBuilder.cpp6
-rw-r--r--contrib/llvm-project/clang/lib/AST/Stmt.cpp18
-rw-r--r--contrib/llvm-project/clang/lib/AST/StmtOpenMP.cpp396
-rw-r--r--contrib/llvm-project/clang/lib/AST/StmtPrinter.cpp118
-rw-r--r--contrib/llvm-project/clang/lib/AST/StmtProfile.cpp102
-rw-r--r--contrib/llvm-project/clang/lib/AST/TemplateBase.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/AST/TextNodeDumper.cpp43
-rw-r--r--contrib/llvm-project/clang/lib/AST/Type.cpp160
-rw-r--r--contrib/llvm-project/clang/lib/AST/TypeLoc.cpp118
-rw-r--r--contrib/llvm-project/clang/lib/AST/TypePrinter.cpp125
-rw-r--r--contrib/llvm-project/clang/lib/AST/VTTBuilder.cpp12
-rw-r--r--contrib/llvm-project/clang/lib/AST/VTableBuilder.cpp16
100 files changed, 14944 insertions, 2198 deletions
diff --git a/contrib/llvm-project/clang/lib/AST/APValue.cpp b/contrib/llvm-project/clang/lib/AST/APValue.cpp
index 1993bba9bd1a..50f8d05dacb4 100644
--- a/contrib/llvm-project/clang/lib/AST/APValue.cpp
+++ b/contrib/llvm-project/clang/lib/AST/APValue.cpp
@@ -42,6 +42,14 @@ APValue::LValueBase::LValueBase(const ValueDecl *P, unsigned I, unsigned V)
APValue::LValueBase::LValueBase(const Expr *P, unsigned I, unsigned V)
: Ptr(P), Local{I, V} {}
+APValue::LValueBase APValue::LValueBase::getDynamicAlloc(DynamicAllocLValue LV,
+ QualType Type) {
+ LValueBase Base;
+ Base.Ptr = LV;
+ Base.DynamicAllocType = Type.getAsOpaquePtr();
+ return Base;
+}
+
APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV,
QualType TypeInfo) {
LValueBase Base;
@@ -51,11 +59,12 @@ APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV,
}
unsigned APValue::LValueBase::getCallIndex() const {
- return is<TypeInfoLValue>() ? 0 : Local.CallIndex;
+ return (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) ? 0
+ : Local.CallIndex;
}
unsigned APValue::LValueBase::getVersion() const {
- return is<TypeInfoLValue>() ? 0 : Local.Version;
+ return (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) ? 0 : Local.Version;
}
QualType APValue::LValueBase::getTypeInfoType() const {
@@ -63,6 +72,11 @@ QualType APValue::LValueBase::getTypeInfoType() const {
return QualType::getFromOpaquePtr(TypeInfoType);
}
+QualType APValue::LValueBase::getDynamicAllocType() const {
+ assert(is<DynamicAllocLValue>() && "not a dynamic allocation lvalue");
+ return QualType::getFromOpaquePtr(DynamicAllocType);
+}
+
namespace clang {
bool operator==(const APValue::LValueBase &LHS,
const APValue::LValueBase &RHS) {
@@ -111,7 +125,7 @@ llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() {
namespace clang {
llvm::hash_code hash_value(const APValue::LValueBase &Base) {
- if (Base.is<TypeInfoLValue>())
+ if (Base.is<TypeInfoLValue>() || Base.is<DynamicAllocLValue>())
return llvm::hash_value(Base.getOpaqueValue());
return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(),
Base.getVersion());
@@ -479,7 +493,7 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx,
return;
case APValue::Vector: {
Out << '{';
- QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ QualType ElemTy = Ty->castAs<VectorType>()->getElementType();
getVectorElt(0).printPretty(Out, Ctx, ElemTy);
for (unsigned i = 1; i != getVectorLength(); ++i) {
Out << ", ";
@@ -528,13 +542,18 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx,
S = CharUnits::One();
}
Out << '&';
- } else if (!IsReference)
+ } else if (!IsReference) {
Out << '&';
+ }
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
Out << *VD;
else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
TI.print(Out, Ctx.getPrintingPolicy());
+ } else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
+ Out << "{*new "
+ << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#"
+ << DA.getIndex() << "}";
} else {
assert(Base.get<const Expr *>() != nullptr &&
"Expecting non-null Expr");
@@ -563,10 +582,17 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx,
} else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
TI.print(Out, Ctx.getPrintingPolicy());
ElemTy = Base.getTypeInfoType();
+ } else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
+ Out << "{*new "
+ << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#"
+ << DA.getIndex() << "}";
+ ElemTy = Base.getDynamicAllocType();
} else {
const Expr *E = Base.get<const Expr*>();
assert(E != nullptr && "Expecting non-null Expr");
E->printPretty(Out, nullptr, Ctx.getPrintingPolicy());
+ // FIXME: This is wrong if E is a MaterializeTemporaryExpr with an lvalue
+ // adjustment.
ElemTy = E->getType();
}
@@ -626,7 +652,7 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx,
}
case APValue::Struct: {
Out << '{';
- const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
+ const RecordDecl *RD = Ty->castAs<RecordType>()->getDecl();
bool First = true;
if (unsigned N = getStructNumBases()) {
const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD);
diff --git a/contrib/llvm-project/clang/lib/AST/ASTConcept.cpp b/contrib/llvm-project/clang/lib/AST/ASTConcept.cpp
new file mode 100644
index 000000000000..549088ad4a8a
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/ASTConcept.cpp
@@ -0,0 +1,68 @@
+//===--- ASTConcept.cpp - Concepts Related AST Data Structures --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file defines AST data structures related to concepts.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConcept.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/TemplateBase.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/FoldingSet.h"
+using namespace clang;
+
+ASTConstraintSatisfaction::ASTConstraintSatisfaction(const ASTContext &C,
+ const ConstraintSatisfaction &Satisfaction):
+ NumRecords{Satisfaction.Details.size()},
+ IsSatisfied{Satisfaction.IsSatisfied} {
+ for (unsigned I = 0; I < NumRecords; ++I) {
+ auto &Detail = Satisfaction.Details[I];
+ if (Detail.second.is<Expr *>())
+ new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I)
+ UnsatisfiedConstraintRecord{Detail.first,
+ UnsatisfiedConstraintRecord::second_type(
+ Detail.second.get<Expr *>())};
+ else {
+ auto &SubstitutionDiagnostic =
+ *Detail.second.get<std::pair<SourceLocation, StringRef> *>();
+ unsigned MessageSize = SubstitutionDiagnostic.second.size();
+ char *Mem = new (C) char[MessageSize];
+ memcpy(Mem, SubstitutionDiagnostic.second.data(), MessageSize);
+ auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>(
+ SubstitutionDiagnostic.first, StringRef(Mem, MessageSize));
+ new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I)
+ UnsatisfiedConstraintRecord{Detail.first,
+ UnsatisfiedConstraintRecord::second_type(
+ NewSubstDiag)};
+ }
+ }
+}
+
+
+ASTConstraintSatisfaction *
+ASTConstraintSatisfaction::Create(const ASTContext &C,
+ const ConstraintSatisfaction &Satisfaction) {
+ std::size_t size =
+ totalSizeToAlloc<UnsatisfiedConstraintRecord>(
+ Satisfaction.Details.size());
+ void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction));
+ return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
+}
+
+void ConstraintSatisfaction::Profile(
+ llvm::FoldingSetNodeID &ID, const ASTContext &C,
+ const NamedDecl *ConstraintOwner, ArrayRef<TemplateArgument> TemplateArgs) {
+ ID.AddPointer(ConstraintOwner);
+ ID.AddInteger(TemplateArgs.size());
+ for (auto &Arg : TemplateArgs)
+ Arg.Profile(ID, C);
+}
diff --git a/contrib/llvm-project/clang/lib/AST/ASTContext.cpp b/contrib/llvm-project/clang/lib/AST/ASTContext.cpp
index 93bdaafc2ac6..1be72efe4de8 100644
--- a/contrib/llvm-project/clang/lib/AST/ASTContext.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ASTContext.cpp
@@ -12,7 +12,9 @@
#include "clang/AST/ASTContext.h"
#include "CXXABI.h"
+#include "Interp/Context.h"
#include "clang/AST/APValue.h"
+#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Attr.h"
@@ -97,63 +99,87 @@ using namespace clang;
enum FloatingRank {
Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank
};
+const Expr *ASTContext::traverseIgnored(const Expr *E) const {
+ return traverseIgnored(const_cast<Expr *>(E));
+}
-RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
- assert(D);
-
- // If we already tried to load comments but there are none,
- // we won't find anything.
- if (CommentsLoaded && Comments.getComments().empty())
+Expr *ASTContext::traverseIgnored(Expr *E) const {
+ if (!E)
return nullptr;
+ switch (Traversal) {
+ case ast_type_traits::TK_AsIs:
+ return E;
+ case ast_type_traits::TK_IgnoreImplicitCastsAndParentheses:
+ return E->IgnoreParenImpCasts();
+ case ast_type_traits::TK_IgnoreUnlessSpelledInSource:
+ return E->IgnoreUnlessSpelledInSource();
+ }
+ llvm_unreachable("Invalid Traversal type!");
+}
+
+ast_type_traits::DynTypedNode
+ASTContext::traverseIgnored(const ast_type_traits::DynTypedNode &N) const {
+ if (const auto *E = N.get<Expr>()) {
+ return ast_type_traits::DynTypedNode::create(*traverseIgnored(E));
+ }
+ return N;
+}
+
+/// \returns location that is relevant when searching for Doc comments related
+/// to \p D.
+static SourceLocation getDeclLocForCommentSearch(const Decl *D,
+ SourceManager &SourceMgr) {
+ assert(D);
+
// User can not attach documentation to implicit declarations.
if (D->isImplicit())
- return nullptr;
+ return {};
// User can not attach documentation to implicit instantiations.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return nullptr;
+ return {};
}
if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (VD->isStaticDataMember() &&
VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return nullptr;
+ return {};
}
if (const auto *CRD = dyn_cast<CXXRecordDecl>(D)) {
if (CRD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return nullptr;
+ return {};
}
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
TemplateSpecializationKind TSK = CTSD->getSpecializationKind();
if (TSK == TSK_ImplicitInstantiation ||
TSK == TSK_Undeclared)
- return nullptr;
+ return {};
}
if (const auto *ED = dyn_cast<EnumDecl>(D)) {
if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return nullptr;
+ return {};
}
if (const auto *TD = dyn_cast<TagDecl>(D)) {
// When tag declaration (but not definition!) is part of the
// decl-specifier-seq of some other declaration, it doesn't get comment
if (TD->isEmbeddedInDeclarator() && !TD->isCompleteDefinition())
- return nullptr;
+ return {};
}
// TODO: handle comments for function parameters properly.
if (isa<ParmVarDecl>(D))
- return nullptr;
+ return {};
// TODO: we could look up template parameter documentation in the template
// documentation.
if (isa<TemplateTypeParmDecl>(D) ||
isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTemplateParmDecl>(D))
- return nullptr;
+ return {};
// Find declaration location.
// For Objective-C declarations we generally don't expect to have multiple
@@ -161,20 +187,21 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// location".
// For all other declarations multiple declarators are used quite frequently,
// so we use the location of the identifier as the "declaration location".
- SourceLocation DeclLoc;
if (isa<ObjCMethodDecl>(D) || isa<ObjCContainerDecl>(D) ||
isa<ObjCPropertyDecl>(D) ||
isa<RedeclarableTemplateDecl>(D) ||
- isa<ClassTemplateSpecializationDecl>(D))
- DeclLoc = D->getBeginLoc();
+ isa<ClassTemplateSpecializationDecl>(D) ||
+ // Allow association with Y across {} in `typedef struct X {} Y`.
+ isa<TypedefDecl>(D))
+ return D->getBeginLoc();
else {
- DeclLoc = D->getLocation();
+ const SourceLocation DeclLoc = D->getLocation();
if (DeclLoc.isMacroID()) {
if (isa<TypedefDecl>(D)) {
// If location of the typedef name is in a macro, it is because being
// declared via a macro. Try using declaration's starting location as
// the "declaration location".
- DeclLoc = D->getBeginLoc();
+ return D->getBeginLoc();
} else if (const auto *TD = dyn_cast<TagDecl>(D)) {
// If location of the tag decl is inside a macro, but the spelling of
// the tag name comes from a macro argument, it looks like a special
@@ -183,102 +210,73 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// attach the comment to the tag decl.
if (SourceMgr.isMacroArgExpansion(DeclLoc) &&
TD->isCompleteDefinition())
- DeclLoc = SourceMgr.getExpansionLoc(DeclLoc);
+ return SourceMgr.getExpansionLoc(DeclLoc);
}
}
+ return DeclLoc;
}
+ return {};
+}
+
+RawComment *ASTContext::getRawCommentForDeclNoCacheImpl(
+ const Decl *D, const SourceLocation RepresentativeLocForDecl,
+ const std::map<unsigned, RawComment *> &CommentsInTheFile) const {
// If the declaration doesn't map directly to a location in a file, we
// can't find the comment.
- if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
+ if (RepresentativeLocForDecl.isInvalid() ||
+ !RepresentativeLocForDecl.isFileID())
return nullptr;
- if (!CommentsLoaded && ExternalSource) {
- ExternalSource->ReadComments();
-
-#ifndef NDEBUG
- ArrayRef<RawComment *> RawComments = Comments.getComments();
- assert(std::is_sorted(RawComments.begin(), RawComments.end(),
- BeforeThanCompare<RawComment>(SourceMgr)));
-#endif
-
- CommentsLoaded = true;
- }
-
- ArrayRef<RawComment *> RawComments = Comments.getComments();
// If there are no comments anywhere, we won't find anything.
- if (RawComments.empty())
+ if (CommentsInTheFile.empty())
return nullptr;
- // Find the comment that occurs just after this declaration.
- ArrayRef<RawComment *>::iterator Comment;
- {
- // When searching for comments during parsing, the comment we are looking
- // for is usually among the last two comments we parsed -- check them
- // first.
- RawComment CommentAtDeclLoc(
- SourceMgr, SourceRange(DeclLoc), LangOpts.CommentOpts, false);
- BeforeThanCompare<RawComment> Compare(SourceMgr);
- ArrayRef<RawComment *>::iterator MaybeBeforeDecl = RawComments.end() - 1;
- bool Found = Compare(*MaybeBeforeDecl, &CommentAtDeclLoc);
- if (!Found && RawComments.size() >= 2) {
- MaybeBeforeDecl--;
- Found = Compare(*MaybeBeforeDecl, &CommentAtDeclLoc);
- }
-
- if (Found) {
- Comment = MaybeBeforeDecl + 1;
- assert(Comment ==
- llvm::lower_bound(RawComments, &CommentAtDeclLoc, Compare));
- } else {
- // Slow path.
- Comment = llvm::lower_bound(RawComments, &CommentAtDeclLoc, Compare);
- }
- }
-
// Decompose the location for the declaration and find the beginning of the
// file buffer.
- std::pair<FileID, unsigned> DeclLocDecomp = SourceMgr.getDecomposedLoc(DeclLoc);
+ const std::pair<FileID, unsigned> DeclLocDecomp =
+ SourceMgr.getDecomposedLoc(RepresentativeLocForDecl);
+
+ // Slow path.
+ auto OffsetCommentBehindDecl =
+ CommentsInTheFile.lower_bound(DeclLocDecomp.second);
// First check whether we have a trailing comment.
- if (Comment != RawComments.end() &&
- ((*Comment)->isDocumentation() || LangOpts.CommentOpts.ParseAllComments)
- && (*Comment)->isTrailingComment() &&
- (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) ||
- isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D))) {
- std::pair<FileID, unsigned> CommentBeginDecomp
- = SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getBegin());
- // Check that Doxygen trailing comment comes after the declaration, starts
- // on the same line and in the same file as the declaration.
- if (DeclLocDecomp.first == CommentBeginDecomp.first &&
- SourceMgr.getLineNumber(DeclLocDecomp.first, DeclLocDecomp.second)
- == SourceMgr.getLineNumber(CommentBeginDecomp.first,
- CommentBeginDecomp.second)) {
- (**Comment).setAttached();
- return *Comment;
+ if (OffsetCommentBehindDecl != CommentsInTheFile.end()) {
+ RawComment *CommentBehindDecl = OffsetCommentBehindDecl->second;
+ if ((CommentBehindDecl->isDocumentation() ||
+ LangOpts.CommentOpts.ParseAllComments) &&
+ CommentBehindDecl->isTrailingComment() &&
+ (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) ||
+ isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D))) {
+
+ // Check that Doxygen trailing comment comes after the declaration, starts
+ // on the same line and in the same file as the declaration.
+ if (SourceMgr.getLineNumber(DeclLocDecomp.first, DeclLocDecomp.second) ==
+ Comments.getCommentBeginLine(CommentBehindDecl, DeclLocDecomp.first,
+ OffsetCommentBehindDecl->first)) {
+ return CommentBehindDecl;
+ }
}
}
// The comment just after the declaration was not a trailing comment.
// Let's look at the previous comment.
- if (Comment == RawComments.begin())
+ if (OffsetCommentBehindDecl == CommentsInTheFile.begin())
return nullptr;
- --Comment;
+
+ auto OffsetCommentBeforeDecl = --OffsetCommentBehindDecl;
+ RawComment *CommentBeforeDecl = OffsetCommentBeforeDecl->second;
// Check that we actually have a non-member Doxygen comment.
- if (!((*Comment)->isDocumentation() ||
+ if (!(CommentBeforeDecl->isDocumentation() ||
LangOpts.CommentOpts.ParseAllComments) ||
- (*Comment)->isTrailingComment())
+ CommentBeforeDecl->isTrailingComment())
return nullptr;
// Decompose the end of the comment.
- std::pair<FileID, unsigned> CommentEndDecomp
- = SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getEnd());
-
- // If the comment and the declaration aren't in the same file, then they
- // aren't related.
- if (DeclLocDecomp.first != CommentEndDecomp.first)
- return nullptr;
+ const unsigned CommentEndOffset =
+ Comments.getCommentEndOffset(CommentBeforeDecl);
// Get the corresponding buffer.
bool Invalid = false;
@@ -288,26 +286,49 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
return nullptr;
// Extract text between the comment and declaration.
- StringRef Text(Buffer + CommentEndDecomp.second,
- DeclLocDecomp.second - CommentEndDecomp.second);
+ StringRef Text(Buffer + CommentEndOffset,
+ DeclLocDecomp.second - CommentEndOffset);
// There should be no other declarations or preprocessor directives between
// comment and declaration.
if (Text.find_first_of(";{}#@") != StringRef::npos)
return nullptr;
- (**Comment).setAttached();
- return *Comment;
+ return CommentBeforeDecl;
+}
+
+RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
+ const SourceLocation DeclLoc = getDeclLocForCommentSearch(D, SourceMgr);
+
+ // If the declaration doesn't map directly to a location in a file, we
+ // can't find the comment.
+ if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
+ return nullptr;
+
+ if (ExternalSource && !CommentsLoaded) {
+ ExternalSource->ReadComments();
+ CommentsLoaded = true;
+ }
+
+ if (Comments.empty())
+ return nullptr;
+
+ const FileID File = SourceMgr.getDecomposedLoc(DeclLoc).first;
+ const auto CommentsInThisFile = Comments.getCommentsInFile(File);
+ if (!CommentsInThisFile || CommentsInThisFile->empty())
+ return nullptr;
+
+ return getRawCommentForDeclNoCacheImpl(D, DeclLoc, *CommentsInThisFile);
}
/// If we have a 'templated' declaration for a template, adjust 'D' to
/// refer to the actual template.
/// If we have an implicit instantiation, adjust 'D' to refer to template.
-static const Decl *adjustDeclToTemplate(const Decl *D) {
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+static const Decl &adjustDeclToTemplate(const Decl &D) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(&D)) {
// Is this function declaration part of a function template?
if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate())
- return FTD;
+ return *FTD;
// Nothing to do if function is not an implicit instantiation.
if (FD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
@@ -315,28 +336,28 @@ static const Decl *adjustDeclToTemplate(const Decl *D) {
// Function is an implicit instantiation of a function template?
if (const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate())
- return FTD;
+ return *FTD;
// Function is instantiated from a member definition of a class template?
if (const FunctionDecl *MemberDecl =
FD->getInstantiatedFromMemberFunction())
- return MemberDecl;
+ return *MemberDecl;
return D;
}
- if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ if (const auto *VD = dyn_cast<VarDecl>(&D)) {
// Static data member is instantiated from a member definition of a class
// template?
if (VD->isStaticDataMember())
if (const VarDecl *MemberDecl = VD->getInstantiatedFromStaticDataMember())
- return MemberDecl;
+ return *MemberDecl;
return D;
}
- if (const auto *CRD = dyn_cast<CXXRecordDecl>(D)) {
+ if (const auto *CRD = dyn_cast<CXXRecordDecl>(&D)) {
// Is this class declaration part of a class template?
if (const ClassTemplateDecl *CTD = CRD->getDescribedClassTemplate())
- return CTD;
+ return *CTD;
// Class is an implicit instantiation of a class template or partial
// specialization?
@@ -346,23 +367,23 @@ static const Decl *adjustDeclToTemplate(const Decl *D) {
llvm::PointerUnion<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *>
PU = CTSD->getSpecializedTemplateOrPartial();
- return PU.is<ClassTemplateDecl*>() ?
- static_cast<const Decl*>(PU.get<ClassTemplateDecl *>()) :
- static_cast<const Decl*>(
- PU.get<ClassTemplatePartialSpecializationDecl *>());
+ return PU.is<ClassTemplateDecl *>()
+ ? *static_cast<const Decl *>(PU.get<ClassTemplateDecl *>())
+ : *static_cast<const Decl *>(
+ PU.get<ClassTemplatePartialSpecializationDecl *>());
}
// Class is instantiated from a member definition of a class template?
if (const MemberSpecializationInfo *Info =
- CRD->getMemberSpecializationInfo())
- return Info->getInstantiatedFrom();
+ CRD->getMemberSpecializationInfo())
+ return *Info->getInstantiatedFrom();
return D;
}
- if (const auto *ED = dyn_cast<EnumDecl>(D)) {
+ if (const auto *ED = dyn_cast<EnumDecl>(&D)) {
// Enum is instantiated from a member definition of a class template?
if (const EnumDecl *MemberDecl = ED->getInstantiatedFromMemberEnum())
- return MemberDecl;
+ return *MemberDecl;
return D;
}
@@ -373,72 +394,81 @@ static const Decl *adjustDeclToTemplate(const Decl *D) {
const RawComment *ASTContext::getRawCommentForAnyRedecl(
const Decl *D,
const Decl **OriginalDecl) const {
- D = adjustDeclToTemplate(D);
+ if (!D) {
+ if (OriginalDecl)
+ OriginalDecl = nullptr;
+ return nullptr;
+ }
- // Check whether we have cached a comment for this declaration already.
+ D = &adjustDeclToTemplate(*D);
+
+ // Any comment directly attached to D?
{
- llvm::DenseMap<const Decl *, RawCommentAndCacheFlags>::iterator Pos =
- RedeclComments.find(D);
- if (Pos != RedeclComments.end()) {
- const RawCommentAndCacheFlags &Raw = Pos->second;
- if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) {
- if (OriginalDecl)
- *OriginalDecl = Raw.getOriginalDecl();
- return Raw.getRaw();
- }
+ auto DeclComment = DeclRawComments.find(D);
+ if (DeclComment != DeclRawComments.end()) {
+ if (OriginalDecl)
+ *OriginalDecl = D;
+ return DeclComment->second;
}
}
- // Search for comments attached to declarations in the redeclaration chain.
- const RawComment *RC = nullptr;
- const Decl *OriginalDeclForRC = nullptr;
- for (auto I : D->redecls()) {
- llvm::DenseMap<const Decl *, RawCommentAndCacheFlags>::iterator Pos =
- RedeclComments.find(I);
- if (Pos != RedeclComments.end()) {
- const RawCommentAndCacheFlags &Raw = Pos->second;
- if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) {
- RC = Raw.getRaw();
- OriginalDeclForRC = Raw.getOriginalDecl();
- break;
- }
- } else {
- RC = getRawCommentForDeclNoCache(I);
- OriginalDeclForRC = I;
- RawCommentAndCacheFlags Raw;
- if (RC) {
- // Call order swapped to work around ICE in VS2015 RTM (Release Win32)
- // https://connect.microsoft.com/VisualStudio/feedback/details/1741530
- Raw.setKind(RawCommentAndCacheFlags::FromDecl);
- Raw.setRaw(RC);
- } else
- Raw.setKind(RawCommentAndCacheFlags::NoCommentInDecl);
- Raw.setOriginalDecl(I);
- RedeclComments[I] = Raw;
- if (RC)
- break;
+ // Any comment attached to any redeclaration of D?
+ const Decl *CanonicalD = D->getCanonicalDecl();
+ if (!CanonicalD)
+ return nullptr;
+
+ {
+ auto RedeclComment = RedeclChainComments.find(CanonicalD);
+ if (RedeclComment != RedeclChainComments.end()) {
+ if (OriginalDecl)
+ *OriginalDecl = RedeclComment->second;
+ auto CommentAtRedecl = DeclRawComments.find(RedeclComment->second);
+ assert(CommentAtRedecl != DeclRawComments.end() &&
+ "This decl is supposed to have comment attached.");
+ return CommentAtRedecl->second;
}
}
- // If we found a comment, it should be a documentation comment.
- assert(!RC || RC->isDocumentation() || LangOpts.CommentOpts.ParseAllComments);
+ // Any redeclarations of D that we haven't checked for comments yet?
+ // We can't use DenseMap::iterator directly since it'd get invalid.
+ auto LastCheckedRedecl = [this, CanonicalD]() -> const Decl * {
+ auto LookupRes = CommentlessRedeclChains.find(CanonicalD);
+ if (LookupRes != CommentlessRedeclChains.end())
+ return LookupRes->second;
+ return nullptr;
+ }();
+
+ for (const auto Redecl : D->redecls()) {
+ assert(Redecl);
+ // Skip all redeclarations that have been checked previously.
+ if (LastCheckedRedecl) {
+ if (LastCheckedRedecl == Redecl) {
+ LastCheckedRedecl = nullptr;
+ }
+ continue;
+ }
+ const RawComment *RedeclComment = getRawCommentForDeclNoCache(Redecl);
+ if (RedeclComment) {
+ cacheRawCommentForDecl(*Redecl, *RedeclComment);
+ if (OriginalDecl)
+ *OriginalDecl = Redecl;
+ return RedeclComment;
+ }
+ CommentlessRedeclChains[CanonicalD] = Redecl;
+ }
if (OriginalDecl)
- *OriginalDecl = OriginalDeclForRC;
-
- // Update cache for every declaration in the redeclaration chain.
- RawCommentAndCacheFlags Raw;
- Raw.setRaw(RC);
- Raw.setKind(RawCommentAndCacheFlags::FromRedecl);
- Raw.setOriginalDecl(OriginalDeclForRC);
-
- for (auto I : D->redecls()) {
- RawCommentAndCacheFlags &R = RedeclComments[I];
- if (R.getKind() == RawCommentAndCacheFlags::NoCommentInDecl)
- R = Raw;
- }
+ *OriginalDecl = nullptr;
+ return nullptr;
+}
- return RC;
+void ASTContext::cacheRawCommentForDecl(const Decl &OriginalD,
+ const RawComment &Comment) const {
+ assert(Comment.isDocumentation() || LangOpts.CommentOpts.ParseAllComments);
+ DeclRawComments.try_emplace(&OriginalD, &Comment);
+ const Decl *const CanonicalDecl = OriginalD.getCanonicalDecl();
+ RedeclChainComments.try_emplace(CanonicalDecl, &OriginalD);
+ CommentlessRedeclChains.erase(CanonicalDecl);
}
static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
@@ -458,6 +488,52 @@ static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
}
}
+void ASTContext::attachCommentsToJustParsedDecls(ArrayRef<Decl *> Decls,
+ const Preprocessor *PP) {
+ if (Comments.empty() || Decls.empty())
+ return;
+
+ // See if there are any new comments that are not attached to a decl.
+ // The location doesn't have to be precise - we care only about the file.
+ const FileID File =
+ SourceMgr.getDecomposedLoc((*Decls.begin())->getLocation()).first;
+ auto CommentsInThisFile = Comments.getCommentsInFile(File);
+ if (!CommentsInThisFile || CommentsInThisFile->empty() ||
+ CommentsInThisFile->rbegin()->second->isAttached())
+ return;
+
+ // There is at least one comment not attached to a decl.
+ // Maybe it should be attached to one of Decls?
+ //
+ // Note that this way we pick up not only comments that precede the
+ // declaration, but also comments that *follow* the declaration -- thanks to
+ // the lookahead in the lexer: we've consumed the semicolon and looked
+ // ahead through comments.
+
+ for (const Decl *D : Decls) {
+ assert(D);
+ if (D->isInvalidDecl())
+ continue;
+
+ D = &adjustDeclToTemplate(*D);
+
+ const SourceLocation DeclLoc = getDeclLocForCommentSearch(D, SourceMgr);
+
+ if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
+ continue;
+
+ if (DeclRawComments.count(D) > 0)
+ continue;
+
+ if (RawComment *const DocComment =
+ getRawCommentForDeclNoCacheImpl(D, DeclLoc, *CommentsInThisFile)) {
+ cacheRawCommentForDecl(*D, *DocComment);
+ comments::FullComment *FC = DocComment->parse(*this, PP, D);
+ ParsedComments[D->getCanonicalDecl()] = FC;
+ }
+ }
+}
+
comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC,
const Decl *D) const {
auto *ThisDeclInfo = new (*this) comments::DeclInfo;
@@ -481,9 +557,9 @@ comments::FullComment *ASTContext::getLocalCommentForDeclUncached(const Decl *D)
comments::FullComment *ASTContext::getCommentForDecl(
const Decl *D,
const Preprocessor *PP) const {
- if (D->isInvalidDecl())
+ if (!D || D->isInvalidDecl())
return nullptr;
- D = adjustDeclToTemplate(D);
+ D = &adjustDeclToTemplate(*D);
const Decl *Canonical = D->getCanonicalDecl();
llvm::DenseMap<const Decl *, comments::FullComment *>::iterator Pos =
@@ -498,7 +574,7 @@ comments::FullComment *ASTContext::getCommentForDecl(
return Pos->second;
}
- const Decl *OriginalDecl;
+ const Decl *OriginalDecl = nullptr;
const RawComment *RC = getRawCommentForAnyRedecl(D, &OriginalDecl);
if (!RC) {
@@ -577,7 +653,7 @@ comments::FullComment *ASTContext::getCommentForDecl(
// should parse the comment in context of that other Decl. This is important
// because comments can contain references to parameter names which can be
// different across redeclarations.
- if (D != OriginalDecl)
+ if (D != OriginalDecl && OriginalDecl)
return getCommentForDecl(OriginalDecl, PP);
comments::FullComment *FC = RC->parse(*this, PP, D);
@@ -585,8 +661,9 @@ comments::FullComment *ASTContext::getCommentForDecl(
return FC;
}
-void
+void
ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &C,
TemplateTemplateParmDecl *Parm) {
ID.AddInteger(Parm->getDepth());
ID.AddInteger(Parm->getPosition());
@@ -600,6 +677,16 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {
ID.AddInteger(0);
ID.AddBoolean(TTP->isParameterPack());
+ const TypeConstraint *TC = TTP->getTypeConstraint();
+ ID.AddBoolean(TC != nullptr);
+ if (TC)
+ TC->getImmediatelyDeclaredConstraint()->Profile(ID, C,
+ /*Canonical=*/true);
+ if (TTP->isExpandedParameterPack()) {
+ ID.AddBoolean(true);
+ ID.AddInteger(TTP->getNumExpansionParameters());
+ } else
+ ID.AddBoolean(false);
continue;
}
@@ -621,8 +708,63 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
auto *TTP = cast<TemplateTemplateParmDecl>(*P);
ID.AddInteger(2);
- Profile(ID, TTP);
+ Profile(ID, C, TTP);
+ }
+ Expr *RequiresClause = Parm->getTemplateParameters()->getRequiresClause();
+ ID.AddBoolean(RequiresClause != nullptr);
+ if (RequiresClause)
+ RequiresClause->Profile(ID, C, /*Canonical=*/true);
+}
+
+static Expr *
+canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,
+ QualType ConstrainedType) {
+ // This is a bit ugly - we need to form a new immediately-declared
+ // constraint that references the new parameter; this would ideally
+ // require semantic analysis (e.g. template<C T> struct S {}; - the
+ // converted arguments of C<T> could be an argument pack if C is
+ // declared as template<typename... T> concept C = ...).
+ // We don't have semantic analysis here so we dig deep into the
+ // ready-made constraint expr and change the thing manually.
+ ConceptSpecializationExpr *CSE;
+ if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC))
+ CSE = cast<ConceptSpecializationExpr>(Fold->getLHS());
+ else
+ CSE = cast<ConceptSpecializationExpr>(IDC);
+ ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments();
+ SmallVector<TemplateArgument, 3> NewConverted;
+ NewConverted.reserve(OldConverted.size());
+ if (OldConverted.front().getKind() == TemplateArgument::Pack) {
+ // The case:
+ // template<typename... T> concept C = true;
+ // template<C<int> T> struct S; -> constraint is C<{T, int}>
+ NewConverted.push_back(ConstrainedType);
+ for (auto &Arg : OldConverted.front().pack_elements().drop_front(1))
+ NewConverted.push_back(Arg);
+ TemplateArgument NewPack(NewConverted);
+
+ NewConverted.clear();
+ NewConverted.push_back(NewPack);
+ assert(OldConverted.size() == 1 &&
+ "Template parameter pack should be the last parameter");
+ } else {
+ assert(OldConverted.front().getKind() == TemplateArgument::Type &&
+ "Unexpected first argument kind for immediately-declared "
+ "constraint");
+ NewConverted.push_back(ConstrainedType);
+ for (auto &Arg : OldConverted.drop_front(1))
+ NewConverted.push_back(Arg);
}
+ Expr *NewIDC = ConceptSpecializationExpr::Create(
+ C, CSE->getNamedConcept(), NewConverted, nullptr,
+ CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack());
+
+ if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
+ NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC,
+ BinaryOperatorKind::BO_LAnd,
+ SourceLocation(), /*RHS=*/nullptr,
+ SourceLocation(), /*NumExpansions=*/None);
+ return NewIDC;
}
TemplateTemplateParmDecl *
@@ -630,7 +772,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
TemplateTemplateParmDecl *TTP) const {
// Check if we already have a canonical template template parameter.
llvm::FoldingSetNodeID ID;
- CanonicalTemplateTemplateParm::Profile(ID, TTP);
+ CanonicalTemplateTemplateParm::Profile(ID, *this, TTP);
void *InsertPos = nullptr;
CanonicalTemplateTemplateParm *Canonical
= CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos);
@@ -644,15 +786,34 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
for (TemplateParameterList::const_iterator P = Params->begin(),
PEnd = Params->end();
P != PEnd; ++P) {
- if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P))
- CanonParams.push_back(
- TemplateTypeParmDecl::Create(*this, getTranslationUnitDecl(),
- SourceLocation(),
- SourceLocation(),
- TTP->getDepth(),
- TTP->getIndex(), nullptr, false,
- TTP->isParameterPack()));
- else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {
+ TemplateTypeParmDecl *NewTTP = TemplateTypeParmDecl::Create(*this,
+ getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
+ TTP->getDepth(), TTP->getIndex(), nullptr, false,
+ TTP->isParameterPack(), TTP->hasTypeConstraint(),
+ TTP->isExpandedParameterPack() ?
+ llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
+ if (const auto *TC = TTP->getTypeConstraint()) {
+ QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0);
+ Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint(
+ *this, TC->getImmediatelyDeclaredConstraint(),
+ ParamAsArgument);
+ TemplateArgumentListInfo CanonArgsAsWritten;
+ if (auto *Args = TC->getTemplateArgsAsWritten())
+ for (const auto &ArgLoc : Args->arguments())
+ CanonArgsAsWritten.addArgument(
+ TemplateArgumentLoc(ArgLoc.getArgument(),
+ TemplateArgumentLocInfo()));
+ NewTTP->setTypeConstraint(
+ NestedNameSpecifierLoc(),
+ DeclarationNameInfo(TC->getNamedConcept()->getDeclName(),
+ SourceLocation()), /*FoundDecl=*/nullptr,
+ // Actually canonicalizing a TemplateArgumentLoc is difficult so we
+ // simply omit the ArgsAsWritten
+ TC->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);
+ }
+ CanonParams.push_back(NewTTP);
+ } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
QualType T = getCanonicalType(NTTP->getType());
TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T);
NonTypeTemplateParmDecl *Param;
@@ -684,6 +845,13 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
NTTP->isParameterPack(),
TInfo);
}
+ if (AutoType *AT = T->getContainedAutoType()) {
+ if (AT->isConstrained()) {
+ Param->setPlaceholderTypeConstraint(
+ canonicalizeImmediatelyDeclaredConstraint(
+ *this, NTTP->getPlaceholderTypeConstraint(), T));
+ }
+ }
CanonParams.push_back(Param);
} else
@@ -691,9 +859,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
cast<TemplateTemplateParmDecl>(*P)));
}
- assert(!TTP->getRequiresClause() &&
- "Unexpected requires-clause on template template-parameter");
- Expr *const CanonRequiresClause = nullptr;
+ Expr *CanonRequiresClause = nullptr;
+ if (Expr *RequiresClause = TTP->getTemplateParameters()->getRequiresClause())
+ CanonRequiresClause = RequiresClause;
TemplateTemplateParmDecl *CanonTTP
= TemplateTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
@@ -722,6 +890,7 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
if (!LangOpts.CPlusPlus) return nullptr;
switch (T.getCXXABI().getKind()) {
+ case TargetCXXABI::Fuchsia:
case TargetCXXABI::GenericARM: // Same as Itanium at this level
case TargetCXXABI::iOS:
case TargetCXXABI::iOS64:
@@ -737,21 +906,31 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
llvm_unreachable("Invalid CXXABI type!");
}
+interp::Context &ASTContext::getInterpContext() {
+ if (!InterpContext) {
+ InterpContext.reset(new interp::Context(*this));
+ }
+ return *InterpContext.get();
+}
+
static const LangASMap *getAddressSpaceMap(const TargetInfo &T,
const LangOptions &LOpts) {
if (LOpts.FakeAddressSpaceMap) {
// The fake address space map must have a distinct entry for each
// language-specific address space.
static const unsigned FakeAddrSpaceMap[] = {
- 0, // Default
- 1, // opencl_global
- 3, // opencl_local
- 2, // opencl_constant
- 0, // opencl_private
- 4, // opencl_generic
- 5, // cuda_device
- 6, // cuda_constant
- 7 // cuda_shared
+ 0, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 0, // opencl_private
+ 4, // opencl_generic
+ 5, // cuda_device
+ 6, // cuda_constant
+ 7, // cuda_shared
+ 8, // ptr32_sptr
+ 9, // ptr32_uptr
+ 10 // ptr64
};
return &FakeAddrSpaceMap;
} else {
@@ -775,9 +954,11 @@ static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI,
ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins)
- : FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()),
- DependentTemplateSpecializationTypes(this_()),
- SubstTemplateTemplateParmPacks(this_()), SourceMgr(SM), LangOpts(LOpts),
+ : ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),
+ TemplateSpecializationTypes(this_()),
+ DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()),
+ SubstTemplateTemplateParmPacks(this_()),
+ CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles,
LangOpts.XRayNeverInstrumentFiles,
@@ -820,10 +1001,6 @@ ASTContext::~ASTContext() {
A != AEnd; ++A)
A->second->~AttrVec();
- for (std::pair<const MaterializeTemporaryExpr *, APValue *> &MTVPair :
- MaterializedTemporaryValues)
- MTVPair.second->~APValue();
-
for (const auto &Value : ModuleInitializers)
Value.second->~PerModuleInitializers();
@@ -840,15 +1017,15 @@ class ASTContext::ParentMap {
/// only storing a unique pointer to them.
using ParentMapPointers = llvm::DenseMap<
const void *,
- llvm::PointerUnion4<const Decl *, const Stmt *,
- ast_type_traits::DynTypedNode *, ParentVector *>>;
+ llvm::PointerUnion<const Decl *, const Stmt *,
+ ast_type_traits::DynTypedNode *, ParentVector *>>;
/// Parent map for nodes without pointer identity. We store a full
/// DynTypedNode for all keys.
using ParentMapOtherNodes = llvm::DenseMap<
ast_type_traits::DynTypedNode,
- llvm::PointerUnion4<const Decl *, const Stmt *,
- ast_type_traits::DynTypedNode *, ParentVector *>>;
+ llvm::PointerUnion<const Decl *, const Stmt *,
+ ast_type_traits::DynTypedNode *, ParentVector *>>;
ParentMapPointers PointerParents;
ParentMapOtherNodes OtherParents;
@@ -904,7 +1081,7 @@ public:
void ASTContext::setTraversalScope(const std::vector<Decl *> &TopLevelDecls) {
TraversalScope = TopLevelDecls;
- Parents.reset();
+ Parents.clear();
}
void ASTContext::AddDeallocation(void (*Callback)(void *), void *Data) const {
@@ -923,7 +1100,7 @@ void ASTContext::PrintStats() const {
unsigned counts[] = {
#define TYPE(Name, Parent) 0,
#define ABSTRACT_TYPE(Name, Parent)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
0 // Extra
};
@@ -943,7 +1120,7 @@ void ASTContext::PrintStats() const {
TotalBytes += counts[Idx] * sizeof(Name##Type); \
++Idx;
#define ABSTRACT_TYPE(Name, Parent)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm::errs() << "Total bytes = " << TotalBytes << "\n";
@@ -1298,6 +1475,12 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
#include "clang/Basic/OpenCLExtensionTypes.def"
}
+ if (Target.hasAArch64SVETypes()) {
+#define SVE_TYPE(Name, Id, SingletonId) \
+ InitBuiltinType(SingletonId, BuiltinType::Id);
+#include "clang/Basic/AArch64SVEACLETypes.def"
+ }
+
// Builtin type for __objc_yes and __objc_no
ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ?
SignedCharTy : BoolTy);
@@ -1515,10 +1698,9 @@ void ASTContext::addedLocalImportDecl(ImportDecl *Import) {
/// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified
/// scalar floating point type.
const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
- const auto *BT = T->getAs<BuiltinType>();
- assert(BT && "Not a floating point type!");
- switch (BT->getKind()) {
- default: llvm_unreachable("Not a floating point type!");
+ switch (T->castAs<BuiltinType>()->getKind()) {
+ default:
+ llvm_unreachable("Not a floating point type!");
case BuiltinType::Float16:
case BuiltinType::Half:
return Target->getHalfFormat();
@@ -1749,7 +1931,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::Class: \
assert(!T->isDependentType() && "should not see dependent types here"); \
return getTypeInfo(cast<Class##Type>(T)->desugar().getTypePtr());
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("Should not see dependent types");
case Type::FunctionNoProto:
@@ -1968,6 +2150,25 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
+ // The SVE types are effectively target-specific. The length of an
+ // SVE_VECTOR_TYPE is only known at runtime, but it is always a multiple
+ // of 128 bits. There is one predicate bit for each vector byte, so the
+ // length of an SVE_PREDICATE_TYPE is always a multiple of 16 bits.
+ //
+ // Because the length is only known at runtime, we use a dummy value
+ // of 0 for the static length. The alignment values are those defined
+ // by the Procedure Call Standard for the Arm Architecture.
+#define SVE_VECTOR_TYPE(Name, Id, SingletonId, ElKind, ElBits, IsSigned, IsFP)\
+ case BuiltinType::Id: \
+ Width = 0; \
+ Align = 128; \
+ break;
+#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, ElKind) \
+ case BuiltinType::Id: \
+ Width = 0; \
+ Align = 16; \
+ break;
+#include "clang/Basic/AArch64SVEACLETypes.def"
}
break;
case Type::ObjCObjectPointer:
@@ -2359,12 +2560,12 @@ structHasUniqueObjectRepresentations(const ASTContext &Context,
return llvm::None;
SmallVector<std::pair<QualType, int64_t>, 4> Bases;
- for (const auto Base : ClassDecl->bases()) {
+ for (const auto &Base : ClassDecl->bases()) {
// Empty types can be inherited from, and non-empty types can potentially
// have tail padding, so just make sure there isn't an error.
if (!isStructEmpty(Base.getType())) {
llvm::Optional<int64_t> Size = structHasUniqueObjectRepresentations(
- Context, Base.getType()->getAs<RecordType>()->getDecl());
+ Context, Base.getType()->castAs<RecordType>()->getDecl());
if (!Size)
return llvm::None;
Bases.emplace_back(Base.getType(), Size.getValue());
@@ -2377,7 +2578,7 @@ structHasUniqueObjectRepresentations(const ASTContext &Context,
Layout.getBaseClassOffset(R.first->getAsCXXRecordDecl());
});
- for (const auto Base : Bases) {
+ for (const auto &Base : Bases) {
int64_t BaseOffset = Context.toBits(
Layout.getBaseClassOffset(Base.first->getAsCXXRecordDecl()));
int64_t BaseSize = Base.second;
@@ -2455,7 +2656,7 @@ bool ASTContext::hasUniqueObjectRepresentations(QualType Ty) const {
}
if (Ty->isRecordType()) {
- const RecordDecl *Record = Ty->getAs<RecordType>()->getDecl();
+ const RecordDecl *Record = Ty->castAs<RecordType>()->getDecl();
if (Record->isInvalidDecl())
return false;
@@ -2575,8 +2776,7 @@ const ObjCInterfaceDecl *ASTContext::getObjContainingInterface(
/// Get the copy initialization expression of VarDecl, or nullptr if
/// none exists.
-ASTContext::BlockVarCopyInit
-ASTContext::getBlockVarCopyInit(const VarDecl*VD) const {
+BlockVarCopyInit ASTContext::getBlockVarCopyInit(const VarDecl *VD) const {
assert(VD && "Passed null params");
assert(VD->hasAttr<BlocksAttr>() &&
"getBlockVarCopyInits - not __block var");
@@ -2730,6 +2930,16 @@ QualType ASTContext::getObjCGCQualType(QualType T,
return getExtQualType(TypeNode, Quals);
}
+QualType ASTContext::removePtrSizeAddrSpace(QualType T) const {
+ if (const PointerType *Ptr = T->getAs<PointerType>()) {
+ QualType Pointee = Ptr->getPointeeType();
+ if (isPtrSizeAddressSpace(Pointee.getAddressSpace())) {
+ return getPointerType(removeAddrSpaceQualType(Pointee));
+ }
+ }
+ return T;
+}
+
const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
FunctionType::ExtInfo Info) {
if (T->getExtInfo() == Info)
@@ -2790,7 +3000,7 @@ QualType ASTContext::getFunctionTypeWithExceptionSpec(
// Anything else must be a function type. Rebuild it with the new exception
// specification.
- const auto *Proto = Orig->getAs<FunctionProtoType>();
+ const auto *Proto = Orig->castAs<FunctionProtoType>();
return getFunctionType(
Proto->getReturnType(), Proto->getParamTypes(),
Proto->getExtProtoInfo().withExceptionSpec(ESI));
@@ -2804,6 +3014,29 @@ bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T,
getFunctionTypeWithExceptionSpec(U, EST_None)));
}
+QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) {
+ if (const auto *Proto = T->getAs<FunctionProtoType>()) {
+ QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType());
+ SmallVector<QualType, 16> Args(Proto->param_types());
+ for (unsigned i = 0, n = Args.size(); i != n; ++i)
+ Args[i] = removePtrSizeAddrSpace(Args[i]);
+ return getFunctionType(RetTy, Args, Proto->getExtProtoInfo());
+ }
+
+ if (const FunctionNoProtoType *Proto = T->getAs<FunctionNoProtoType>()) {
+ QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType());
+ return getFunctionNoProtoType(RetTy, Proto->getExtInfo());
+ }
+
+ return T;
+}
+
+bool ASTContext::hasSameFunctionTypeIgnoringPtrSizes(QualType T, QualType U) {
+ return hasSameType(T, U) ||
+ hasSameType(getFunctionTypeWithoutPtrSizes(T),
+ getFunctionTypeWithoutPtrSizes(U));
+}
+
void ASTContext::adjustExceptionSpec(
FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI,
bool AsWritten) {
@@ -3087,31 +3320,38 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) const {
/// array of the specified element type.
QualType ASTContext::getConstantArrayType(QualType EltTy,
const llvm::APInt &ArySizeIn,
+ const Expr *SizeExpr,
ArrayType::ArraySizeModifier ASM,
unsigned IndexTypeQuals) const {
assert((EltTy->isDependentType() ||
EltTy->isIncompleteType() || EltTy->isConstantSizeType()) &&
"Constant array of VLAs is illegal!");
+ // We only need the size as part of the type if it's instantiation-dependent.
+ if (SizeExpr && !SizeExpr->isInstantiationDependent())
+ SizeExpr = nullptr;
+
// Convert the array size into a canonical width matching the pointer size for
// the target.
llvm::APInt ArySize(ArySizeIn);
ArySize = ArySize.zextOrTrunc(Target->getMaxPointerWidth());
llvm::FoldingSetNodeID ID;
- ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals);
+ ConstantArrayType::Profile(ID, *this, EltTy, ArySize, SizeExpr, ASM,
+ IndexTypeQuals);
void *InsertPos = nullptr;
if (ConstantArrayType *ATP =
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(ATP, 0);
- // If the element type isn't canonical or has qualifiers, this won't
- // be a canonical type either, so fill in the canonical type field.
+ // If the element type isn't canonical or has qualifiers, or the array bound
+ // is instantiation-dependent, this won't be a canonical type either, so fill
+ // in the canonical type field.
QualType Canon;
- if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
+ if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers() || SizeExpr) {
SplitQualType canonSplit = getCanonicalType(EltTy).split();
- Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize,
+ Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize, nullptr,
ASM, IndexTypeQuals);
Canon = getQualifiedType(Canon, canonSplit.Quals);
@@ -3121,8 +3361,11 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
- auto *New = new (*this,TypeAlignment)
- ConstantArrayType(EltTy, Canon, ArySize, ASM, IndexTypeQuals);
+ void *Mem = Allocate(
+ ConstantArrayType::totalSizeToAlloc<const Expr *>(SizeExpr ? 1 : 0),
+ TypeAlignment);
+ auto *New = new (Mem)
+ ConstantArrayType(EltTy, Canon, ArySize, SizeExpr, ASM, IndexTypeQuals);
ConstantArrayTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
@@ -3143,7 +3386,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("didn't desugar past all non-canonical types?");
// These types should never be variably-modified.
@@ -3219,6 +3462,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
result = getConstantArrayType(
getVariableArrayDecayedType(cat->getElementType()),
cat->getSize(),
+ cat->getSizeExpr(),
cat->getSizeModifier(),
cat->getIndexTypeCVRQualifiers());
break;
@@ -3457,10 +3701,10 @@ ASTContext::getDependentVectorType(QualType VecType, Expr *SizeExpr,
(void)CanonCheck;
DependentVectorTypes.InsertNode(New, InsertPos);
} else {
- QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
- SourceLocation());
+ QualType CanonExtTy = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
+ SourceLocation());
New = new (*this, TypeAlignment) DependentVectorType(
- *this, VecType, Canon, SizeExpr, AttrLoc, VecKind);
+ *this, VecType, CanonExtTy, SizeExpr, AttrLoc, VecKind);
}
}
@@ -3530,10 +3774,10 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
(void)CanonCheck;
DependentSizedExtVectorTypes.InsertNode(New, InsertPos);
} else {
- QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
- SourceLocation());
- New = new (*this, TypeAlignment)
- DependentSizedExtVectorType(*this, vecType, Canon, SizeExpr, AttrLoc);
+ QualType CanonExtTy = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
+ SourceLocation());
+ New = new (*this, TypeAlignment) DependentSizedExtVectorType(
+ *this, vecType, CanonExtTy, SizeExpr, AttrLoc);
}
}
@@ -3787,10 +4031,11 @@ QualType ASTContext::getFunctionTypeInternal(
auto ESH = FunctionProtoType::getExceptionSpecSize(
EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size());
size_t Size = FunctionProtoType::totalSizeToAlloc<
- QualType, FunctionType::FunctionTypeExtraBitfields,
+ QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields,
FunctionType::ExceptionType, Expr *, FunctionDecl *,
FunctionProtoType::ExtParameterInfo, Qualifiers>(
- NumArgs, FunctionProtoType::hasExtraBitfields(EPI.ExceptionSpec.Type),
+ NumArgs, EPI.Variadic,
+ FunctionProtoType::hasExtraBitfields(EPI.ExceptionSpec.Type),
ESH.NumExceptionType, ESH.NumExprPtr, ESH.NumFunctionDeclPtr,
EPI.ExtParameterInfos ? NumArgs : 0,
EPI.TypeQuals.hasNonFastQualifiers() ? 1 : 0);
@@ -4624,8 +4869,7 @@ ASTContext::applyObjCProtocolQualifiers(QualType type,
QualType
ASTContext::getObjCTypeParamType(const ObjCTypeParamDecl *Decl,
- ArrayRef<ObjCProtocolDecl *> protocols,
- QualType Canonical) const {
+ ArrayRef<ObjCProtocolDecl *> protocols) const {
// Look in the folding set for an existing type.
llvm::FoldingSetNodeID ID;
ObjCTypeParamType::Profile(ID, Decl, protocols);
@@ -4634,16 +4878,14 @@ ASTContext::getObjCTypeParamType(const ObjCTypeParamDecl *Decl,
ObjCTypeParamTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(TypeParam, 0);
- if (Canonical.isNull()) {
- // We canonicalize to the underlying type.
- Canonical = getCanonicalType(Decl->getUnderlyingType());
- if (!protocols.empty()) {
- // Apply the protocol qualifers.
- bool hasError;
- Canonical = getCanonicalType(applyObjCProtocolQualifiers(
- Canonical, protocols, hasError, true /*allowOnPointerType*/));
- assert(!hasError && "Error when apply protocol qualifier to bound type");
- }
+ // We canonicalize to the underlying type.
+ QualType Canonical = getCanonicalType(Decl->getUnderlyingType());
+ if (!protocols.empty()) {
+ // Apply the protocol qualifers.
+ bool hasError;
+ Canonical = getCanonicalType(applyObjCProtocolQualifiers(
+ Canonical, protocols, hasError, true /*allowOnPointerType*/));
+ assert(!hasError && "Error when apply protocol qualifier to bound type");
}
unsigned size = sizeof(ObjCTypeParamType);
@@ -4895,21 +5137,29 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
/// getAutoType - Return the uniqued reference to the 'auto' type which has been
/// deduced to the given type, or to the canonical undeduced 'auto' type, or the
/// canonical deduced-but-dependent 'auto' type.
-QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
- bool IsDependent, bool IsPack) const {
+QualType
+ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
+ bool IsDependent, bool IsPack,
+ ConceptDecl *TypeConstraintConcept,
+ ArrayRef<TemplateArgument> TypeConstraintArgs) const {
assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack");
- if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent)
+ if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto &&
+ !TypeConstraintConcept && !IsDependent)
return getAutoDeductType();
// Look in the folding set for an existing type.
void *InsertPos = nullptr;
llvm::FoldingSetNodeID ID;
- AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack);
+ AutoType::Profile(ID, *this, DeducedType, Keyword, IsDependent,
+ TypeConstraintConcept, TypeConstraintArgs);
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(AT, 0);
- auto *AT = new (*this, TypeAlignment)
- AutoType(DeducedType, Keyword, IsDependent, IsPack);
+ void *Mem = Allocate(sizeof(AutoType) +
+ sizeof(TemplateArgument) * TypeConstraintArgs.size(),
+ TypeAlignment);
+ auto *AT = new (Mem) AutoType(DeducedType, Keyword, IsDependent, IsPack,
+ TypeConstraintConcept, TypeConstraintArgs);
Types.push_back(AT);
if (InsertPos)
AutoTypes.InsertNode(AT, InsertPos);
@@ -4971,7 +5221,8 @@ QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull())
AutoDeductTy = QualType(
new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto,
- /*dependent*/false, /*pack*/false),
+ /*dependent*/false, /*pack*/false,
+ /*concept*/nullptr, /*args*/{}),
0);
return AutoDeductTy;
}
@@ -5114,7 +5365,7 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type,
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
return getConstantArrayType(unqualElementType, CAT->getSize(),
- CAT->getSizeModifier(), 0);
+ CAT->getSizeExpr(), CAT->getSizeModifier(), 0);
}
if (const auto *IAT = dyn_cast<IncompleteArrayType>(AT)) {
@@ -5487,6 +5738,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
if (const auto *CAT = dyn_cast<ConstantArrayType>(ATy))
return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(),
+ CAT->getSizeExpr(),
CAT->getSizeModifier(),
CAT->getIndexTypeCVRQualifiers()));
if (const auto *IAT = dyn_cast<IncompleteArrayType>(ATy))
@@ -5599,8 +5851,7 @@ static FloatingRank getFloatingRank(QualType T) {
if (const auto *CT = T->getAs<ComplexType>())
return getFloatingRank(CT->getElementType());
- assert(T->getAs<BuiltinType>() && "getFloatingRank(): not a floating type");
- switch (T->getAs<BuiltinType>()->getKind()) {
+ switch (T->castAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("getFloatingRank(): not a floating type");
case BuiltinType::Float16: return Float16Rank;
case BuiltinType::Half: return HalfRank;
@@ -5977,12 +6228,10 @@ QualType ASTContext::getObjCSuperType() const {
}
void ASTContext::setCFConstantStringType(QualType T) {
- const auto *TD = T->getAs<TypedefType>();
- assert(TD && "Invalid CFConstantStringType");
+ const auto *TD = T->castAs<TypedefType>();
CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl());
const auto *TagType =
- CFConstantStringTypeDecl->getUnderlyingType()->getAs<RecordType>();
- assert(TagType && "Invalid CFConstantStringType");
+ CFConstantStringTypeDecl->getUnderlyingType()->castAs<RecordType>();
CFConstantStringTagDecl = TagType->getDecl();
}
@@ -6238,14 +6487,14 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
const BlockDecl *Decl = Expr->getBlockDecl();
QualType BlockTy =
- Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
+ Expr->getType()->castAs<BlockPointerType>()->getPointeeType();
+ QualType BlockReturnTy = BlockTy->castAs<FunctionType>()->getReturnType();
// Encode result type.
if (getLangOpts().EncodeExtendedBlockSig)
- getObjCEncodingForMethodParameter(
- Decl::OBJC_TQ_None, BlockTy->getAs<FunctionType>()->getReturnType(), S,
- true /*Extended*/);
+ getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None, BlockReturnTy, S,
+ true /*Extended*/);
else
- getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getReturnType(), S);
+ getObjCEncodingForType(BlockReturnTy, S);
// Compute size of all parameters.
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
@@ -6556,8 +6805,9 @@ void ASTContext::getObjCEncodingForPropertyType(QualType T,
/*Field=*/nullptr);
}
-static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
- BuiltinType::Kind kind) {
+static char getObjCEncodingForPrimitiveType(const ASTContext *C,
+ const BuiltinType *BT) {
+ BuiltinType::Kind kind = BT->getKind();
switch (kind) {
case BuiltinType::Void: return 'v';
case BuiltinType::Bool: return 'B';
@@ -6617,6 +6867,17 @@ static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
// FIXME: potentially need @encodes for these!
return ' ';
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
+ {
+ DiagnosticsEngine &Diags = C->getDiagnostics();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "cannot yet @encode type %0");
+ Diags.Report(DiagID) << BT->getName(C->getPrintingPolicy());
+ return ' ';
+ }
+
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
@@ -6653,7 +6914,7 @@ static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) {
// The encoding of a fixed enum type matches its fixed underlying type.
const auto *BT = Enum->getIntegerType()->castAs<BuiltinType>();
- return getObjCEncodingForPrimitiveKind(C, BT->getKind());
+ return getObjCEncodingForPrimitiveType(C, BT);
}
static void EncodeBitField(const ASTContext *Ctx, std::string& S,
@@ -6693,7 +6954,7 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
S += ObjCEncodingForEnumType(Ctx, ET);
else {
const auto *BT = T->castAs<BuiltinType>();
- S += getObjCEncodingForPrimitiveKind(Ctx, BT->getKind());
+ S += getObjCEncodingForPrimitiveType(Ctx, BT);
}
}
S += llvm::utostr(FD->getBitWidthValue(*Ctx));
@@ -6711,26 +6972,24 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
if (FD && FD->isBitField())
return EncodeBitField(this, S, T, FD);
if (const auto *BT = dyn_cast<BuiltinType>(CT))
- S += getObjCEncodingForPrimitiveKind(this, BT->getKind());
+ S += getObjCEncodingForPrimitiveType(this, BT);
else
S += ObjCEncodingForEnumType(this, cast<EnumType>(CT));
return;
- case Type::Complex: {
- const auto *CT = T->castAs<ComplexType>();
+ case Type::Complex:
S += 'j';
- getObjCEncodingForTypeImpl(CT->getElementType(), S, ObjCEncOptions(),
+ getObjCEncodingForTypeImpl(T->castAs<ComplexType>()->getElementType(), S,
+ ObjCEncOptions(),
/*Field=*/nullptr);
return;
- }
- case Type::Atomic: {
- const auto *AT = T->castAs<AtomicType>();
+ case Type::Atomic:
S += 'A';
- getObjCEncodingForTypeImpl(AT->getValueType(), S, ObjCEncOptions(),
+ getObjCEncodingForTypeImpl(T->castAs<AtomicType>()->getValueType(), S,
+ ObjCEncOptions(),
/*Field=*/nullptr);
return;
- }
// encoding for pointer or reference types.
case Type::Pointer:
@@ -6760,8 +7019,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
}
} else if (Options.IsOutermostType()) {
QualType P = PointeeTy;
- while (P->getAs<PointerType>())
- P = P->getAs<PointerType>()->getPointeeType();
+ while (auto PT = P->getAs<PointerType>())
+ P = PT->getPointeeType();
if (P.isConstQualified()) {
isReadOnly = true;
S += 'r';
@@ -7033,7 +7292,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
case Type::KIND:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(KIND, BASE) \
case Type::KIND:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("@encode for dependent type!");
}
llvm_unreachable("bad type kind!");
@@ -7384,7 +7643,7 @@ static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
QualType VaListTagArrayType
= Context->getConstantArrayType(VaListTagTypedefType,
- Size, ArrayType::Normal, 0);
+ Size, nullptr, ArrayType::Normal, 0);
return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}
@@ -7437,16 +7696,16 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) {
// typedef struct __va_list_tag __builtin_va_list[1];
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
- QualType VaListTagArrayType =
- Context->getConstantArrayType(VaListTagType, Size, ArrayType::Normal, 0);
+ QualType VaListTagArrayType = Context->getConstantArrayType(
+ VaListTagType, Size, nullptr, ArrayType::Normal, 0);
return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}
static TypedefDecl *CreatePNaClABIBuiltinVaListDecl(const ASTContext *Context) {
// typedef int __builtin_va_list[4];
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 4);
- QualType IntArrayType =
- Context->getConstantArrayType(Context->IntTy, Size, ArrayType::Normal, 0);
+ QualType IntArrayType = Context->getConstantArrayType(
+ Context->IntTy, Size, nullptr, ArrayType::Normal, 0);
return Context->buildImplicitTypedef(IntArrayType, "__builtin_va_list");
}
@@ -7540,8 +7799,8 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) {
// typedef __va_list_tag __builtin_va_list[1];
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
- QualType VaListTagArrayType =
- Context->getConstantArrayType(VaListTagType, Size, ArrayType::Normal, 0);
+ QualType VaListTagArrayType = Context->getConstantArrayType(
+ VaListTagType, Size, nullptr, ArrayType::Normal, 0);
return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}
@@ -7816,7 +8075,7 @@ Qualifiers::GC ASTContext::getObjCGCAttrKind(QualType Ty) const {
if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType())
return Qualifiers::Strong;
else if (Ty->isPointerType())
- return getObjCGCAttrKind(Ty->getAs<PointerType>()->getPointeeType());
+ return getObjCGCAttrKind(Ty->castAs<PointerType>()->getPointeeType());
} else {
// It's not valid to set GC attributes on anything that isn't a
// pointer.
@@ -7853,8 +8112,8 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
// Treat Neon vector types and most AltiVec vector types as if they are the
// equivalent GCC vector types.
- const auto *First = FirstVec->getAs<VectorType>();
- const auto *Second = SecondVec->getAs<VectorType>();
+ const auto *First = FirstVec->castAs<VectorType>();
+ const auto *Second = SecondVec->castAs<VectorType>();
if (First->getNumElements() == Second->getNumElements() &&
hasSameType(First->getElementType(), Second->getElementType()) &&
First->getVectorKind() != VectorType::AltiVecPixel &&
@@ -7866,6 +8125,28 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
return false;
}
+bool ASTContext::hasDirectOwnershipQualifier(QualType Ty) const {
+ while (true) {
+ // __strong id
+ if (const AttributedType *Attr = dyn_cast<AttributedType>(Ty)) {
+ if (Attr->getAttrKind() == attr::ObjCOwnership)
+ return true;
+
+ Ty = Attr->getModifiedType();
+
+ // X *__strong (...)
+ } else if (const ParenType *Paren = dyn_cast<ParenType>(Ty)) {
+ Ty = Paren->getInnerType();
+
+ // We do not want to look through typedefs, typeof(expr),
+ // typeof(type), or any other way that the type is somehow
+ // abstracted.
+ } else {
+ return false;
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's.
//===----------------------------------------------------------------------===//
@@ -7885,15 +8166,11 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
/// ObjCQualifiedClassTypesAreCompatible - compare Class<pr,...> and
/// Class<pr1, ...>.
-bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs,
- QualType rhs) {
- const auto *lhsQID = lhs->getAs<ObjCObjectPointerType>();
- const auto *rhsOPT = rhs->getAs<ObjCObjectPointerType>();
- assert((lhsQID && rhsOPT) && "ObjCQualifiedClassTypesAreCompatible");
-
- for (auto *lhsProto : lhsQID->quals()) {
+bool ASTContext::ObjCQualifiedClassTypesAreCompatible(
+ const ObjCObjectPointerType *lhs, const ObjCObjectPointerType *rhs) {
+ for (auto *lhsProto : lhs->quals()) {
bool match = false;
- for (auto *rhsProto : rhsOPT->quals()) {
+ for (auto *rhsProto : rhs->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto)) {
match = true;
break;
@@ -7907,26 +8184,24 @@ bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs,
/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an
/// ObjCQualifiedIDType.
-bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
- bool compare) {
- // Allow id<P..> and an 'id' or void* type in all cases.
- if (lhs->isVoidPointerType() ||
- lhs->isObjCIdType() || lhs->isObjCClassType())
+bool ASTContext::ObjCQualifiedIdTypesAreCompatible(
+ const ObjCObjectPointerType *lhs, const ObjCObjectPointerType *rhs,
+ bool compare) {
+ // Allow id<P..> and an 'id' in all cases.
+ if (lhs->isObjCIdType() || rhs->isObjCIdType())
return true;
- else if (rhs->isVoidPointerType() ||
- rhs->isObjCIdType() || rhs->isObjCClassType())
- return true;
-
- if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
- const auto *rhsOPT = rhs->getAs<ObjCObjectPointerType>();
- if (!rhsOPT) return false;
+ // Don't allow id<P..> to convert to Class or Class<P..> in either direction.
+ if (lhs->isObjCClassType() || lhs->isObjCQualifiedClassType() ||
+ rhs->isObjCClassType() || rhs->isObjCQualifiedClassType())
+ return false;
- if (rhsOPT->qual_empty()) {
+ if (lhs->isObjCQualifiedIdType()) {
+ if (rhs->qual_empty()) {
// If the RHS is a unqualified interface pointer "NSString*",
// make sure we check the class hierarchy.
- if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
- for (auto *I : lhsQID->quals()) {
+ if (ObjCInterfaceDecl *rhsID = rhs->getInterfaceDecl()) {
+ for (auto *I : lhs->quals()) {
// when comparing an id<P> on lhs with a static type on rhs,
// see if static class implements all of id's protocols, directly or
// through its super class and categories.
@@ -7938,13 +8213,13 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
return true;
}
// Both the right and left sides have qualifiers.
- for (auto *lhsProto : lhsQID->quals()) {
+ for (auto *lhsProto : lhs->quals()) {
bool match = false;
// when comparing an id<P> on lhs with a static type on rhs,
// see if static class implements all of id's protocols, directly or
// through its super class and categories.
- for (auto *rhsProto : rhsOPT->quals()) {
+ for (auto *rhsProto : rhs->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
match = true;
@@ -7953,8 +8228,8 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
}
// If the RHS is a qualified interface pointer "NSString<P>*",
// make sure we check the class hierarchy.
- if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
- for (auto *I : lhsQID->quals()) {
+ if (ObjCInterfaceDecl *rhsID = rhs->getInterfaceDecl()) {
+ for (auto *I : lhs->quals()) {
// when comparing an id<P> on lhs with a static type on rhs,
// see if static class implements all of id's protocols, directly or
// through its super class and categories.
@@ -7971,13 +8246,11 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
return true;
}
- const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
- assert(rhsQID && "One of the LHS/RHS should be id<x>");
+ assert(rhs->isObjCQualifiedIdType() && "One of the LHS/RHS should be id<x>");
- if (const ObjCObjectPointerType *lhsOPT =
- lhs->getAsObjCInterfacePointerType()) {
+ if (lhs->getInterfaceType()) {
// If both the right and left sides have qualifiers.
- for (auto *lhsProto : lhsOPT->quals()) {
+ for (auto *lhsProto : lhs->quals()) {
bool match = false;
// when comparing an id<P> on rhs with a static type on lhs,
@@ -7985,7 +8258,7 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
// through its super class and categories.
// First, lhs protocols in the qualifier list must be found, direct
// or indirect in rhs's qualifier list or it is a mismatch.
- for (auto *rhsProto : rhsQID->quals()) {
+ for (auto *rhsProto : rhs->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
match = true;
@@ -7998,17 +8271,17 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
// Static class's protocols, or its super class or category protocols
// must be found, direct or indirect in rhs's qualifier list or it is a mismatch.
- if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) {
+ if (ObjCInterfaceDecl *lhsID = lhs->getInterfaceDecl()) {
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
CollectInheritedProtocols(lhsID, LHSInheritedProtocols);
// This is rather dubious but matches gcc's behavior. If lhs has
// no type qualifier and its class has no static protocol(s)
// assume that it is mismatch.
- if (LHSInheritedProtocols.empty() && lhsOPT->qual_empty())
+ if (LHSInheritedProtocols.empty() && lhs->qual_empty())
return false;
for (auto *lhsProto : LHSInheritedProtocols) {
bool match = false;
- for (auto *rhsProto : rhsQID->quals()) {
+ for (auto *rhsProto : rhs->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
match = true;
@@ -8032,9 +8305,8 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
const ObjCObjectType* LHS = LHSOPT->getObjectType();
const ObjCObjectType* RHS = RHSOPT->getObjectType();
- // If either type represents the built-in 'id' or 'Class' types, return true.
- if (LHS->isObjCUnqualifiedIdOrClass() ||
- RHS->isObjCUnqualifiedIdOrClass())
+ // If either type represents the built-in 'id' type, return true.
+ if (LHS->isObjCUnqualifiedId() || RHS->isObjCUnqualifiedId())
return true;
// Function object that propagates a successful result or handles
@@ -8052,15 +8324,20 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
LHSOPT->stripObjCKindOfTypeAndQuals(*this));
};
+ // Casts from or to id<P> are allowed when the other side has compatible
+ // protocols.
if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) {
- return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0),
- false));
+ return finish(ObjCQualifiedIdTypesAreCompatible(LHSOPT, RHSOPT, false));
}
+ // Verify protocol compatibility for casts from Class<P1> to Class<P2>.
if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) {
- return finish(ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0)));
+ return finish(ObjCQualifiedClassTypesAreCompatible(LHSOPT, RHSOPT));
+ }
+
+ // Casts from Class to Class<Foo>, or vice-versa, are allowed.
+ if (LHS->isObjCClass() && RHS->isObjCClass()) {
+ return true;
}
// If we have 2 user-defined types, fall into that path.
@@ -8108,9 +8385,9 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer(
}
if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
- return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0),
- false));
+ return finish(ObjCQualifiedIdTypesAreCompatible(
+ (BlockReturnType ? LHSOPT : RHSOPT),
+ (BlockReturnType ? RHSOPT : LHSOPT), false));
const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
@@ -8530,8 +8807,8 @@ QualType ASTContext::mergeFunctionParameterTypes(QualType lhs, QualType rhs,
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
bool OfBlockPointer,
bool Unqualified) {
- const auto *lbase = lhs->getAs<FunctionType>();
- const auto *rbase = rhs->getAs<FunctionType>();
+ const auto *lbase = lhs->castAs<FunctionType>();
+ const auto *rbase = rhs->castAs<FunctionType>();
const auto *lproto = dyn_cast<FunctionProtoType>(lbase);
const auto *rproto = dyn_cast<FunctionProtoType>(rbase);
bool allLTypes = true;
@@ -8834,7 +9111,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("Non-canonical and dependent types shouldn't get here");
case Type::Auto:
@@ -8854,8 +9131,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
case Type::Pointer:
{
// Merge two pointer types, while trying to preserve typedef info
- QualType LHSPointee = LHS->getAs<PointerType>()->getPointeeType();
- QualType RHSPointee = RHS->getAs<PointerType>()->getPointeeType();
+ QualType LHSPointee = LHS->castAs<PointerType>()->getPointeeType();
+ QualType RHSPointee = RHS->castAs<PointerType>()->getPointeeType();
if (Unqualified) {
LHSPointee = LHSPointee.getUnqualifiedType();
RHSPointee = RHSPointee.getUnqualifiedType();
@@ -8873,8 +9150,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
case Type::BlockPointer:
{
// Merge two block pointer types, while trying to preserve typedef info
- QualType LHSPointee = LHS->getAs<BlockPointerType>()->getPointeeType();
- QualType RHSPointee = RHS->getAs<BlockPointerType>()->getPointeeType();
+ QualType LHSPointee = LHS->castAs<BlockPointerType>()->getPointeeType();
+ QualType RHSPointee = RHS->castAs<BlockPointerType>()->getPointeeType();
if (Unqualified) {
LHSPointee = LHSPointee.getUnqualifiedType();
RHSPointee = RHSPointee.getUnqualifiedType();
@@ -8906,8 +9183,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
case Type::Atomic:
{
// Merge two pointer types, while trying to preserve typedef info
- QualType LHSValue = LHS->getAs<AtomicType>()->getValueType();
- QualType RHSValue = RHS->getAs<AtomicType>()->getValueType();
+ QualType LHSValue = LHS->castAs<AtomicType>()->getValueType();
+ QualType RHSValue = RHS->castAs<AtomicType>()->getValueType();
if (Unqualified) {
LHSValue = LHSValue.getUnqualifiedType();
RHSValue = RHSValue.getUnqualifiedType();
@@ -8975,10 +9252,14 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
return LHS;
if (RCAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType))
return RHS;
- if (LCAT) return getConstantArrayType(ResultType, LCAT->getSize(),
- ArrayType::ArraySizeModifier(), 0);
- if (RCAT) return getConstantArrayType(ResultType, RCAT->getSize(),
- ArrayType::ArraySizeModifier(), 0);
+ if (LCAT)
+ return getConstantArrayType(ResultType, LCAT->getSize(),
+ LCAT->getSizeExpr(),
+ ArrayType::ArraySizeModifier(), 0);
+ if (RCAT)
+ return getConstantArrayType(ResultType, RCAT->getSize(),
+ RCAT->getSizeExpr(),
+ ArrayType::ArraySizeModifier(), 0);
if (LVAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType))
return LHS;
if (RVAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType))
@@ -9013,34 +9294,30 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
return {};
case Type::Vector:
// FIXME: The merged type should be an ExtVector!
- if (areCompatVectorTypes(LHSCan->getAs<VectorType>(),
- RHSCan->getAs<VectorType>()))
+ if (areCompatVectorTypes(LHSCan->castAs<VectorType>(),
+ RHSCan->castAs<VectorType>()))
return LHS;
return {};
case Type::ObjCObject: {
// Check if the types are assignment compatible.
// FIXME: This should be type compatibility, e.g. whether
// "LHS x; RHS x;" at global scope is legal.
- const auto *LHSIface = LHS->getAs<ObjCObjectType>();
- const auto *RHSIface = RHS->getAs<ObjCObjectType>();
- if (canAssignObjCInterfaces(LHSIface, RHSIface))
+ if (canAssignObjCInterfaces(LHS->castAs<ObjCObjectType>(),
+ RHS->castAs<ObjCObjectType>()))
return LHS;
-
return {};
}
case Type::ObjCObjectPointer:
if (OfBlockPointer) {
if (canAssignObjCInterfacesInBlockPointer(
- LHS->getAs<ObjCObjectPointerType>(),
- RHS->getAs<ObjCObjectPointerType>(),
- BlockReturnType))
+ LHS->castAs<ObjCObjectPointerType>(),
+ RHS->castAs<ObjCObjectPointerType>(), BlockReturnType))
return LHS;
return {};
}
- if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(),
- RHS->getAs<ObjCObjectPointerType>()))
+ if (canAssignObjCInterfaces(LHS->castAs<ObjCObjectPointerType>(),
+ RHS->castAs<ObjCObjectPointerType>()))
return LHS;
-
return {};
case Type::Pipe:
assert(LHS != RHS &&
@@ -9125,7 +9402,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
if (ResReturnType == NewReturnType || ResReturnType == OldReturnType) {
// id foo(); ... __strong id foo(); or: __strong id foo(); ... id foo();
// In either case, use OldReturnType to build the new function type.
- const auto *F = LHS->getAs<FunctionType>();
+ const auto *F = LHS->castAs<FunctionType>();
if (const auto *FPT = cast<FunctionProtoType>(F)) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = getFunctionExtInfo(LHS);
@@ -9166,8 +9443,8 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
}
if (LHSCan->isObjCObjectPointerType() && RHSCan->isObjCObjectPointerType()) {
- QualType LHSBaseQT = LHS->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType RHSBaseQT = RHS->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType LHSBaseQT = LHS->castAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType RHSBaseQT = RHS->castAs<ObjCObjectPointerType>()->getPointeeType();
QualType ResQT = mergeObjCGCQualifiers(LHSBaseQT, RHSBaseQT);
if (ResQT == LHSBaseQT)
return LHS;
@@ -9203,9 +9480,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
if (const auto *ETy = T->getAs<EnumType>())
T = ETy->getDecl()->getIntegerType();
- const auto *BTy = T->getAs<BuiltinType>();
- assert(BTy && "Unexpected signed integer or fixed point type");
- switch (BTy->getKind()) {
+ switch (T->castAs<BuiltinType>()->getKind()) {
case BuiltinType::Char_S:
case BuiltinType::SChar:
return UnsignedCharTy;
@@ -9814,25 +10089,10 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
return StrongLinkage;
case TSK_ExplicitSpecialization:
- if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
- // If this is a fully specialized constexpr variable template, pretend it
- // was marked inline. MSVC 14.21.27702 headers define _Is_integral in a
- // header this way, and we don't want to emit non-discardable definitions
- // of these variables in every TU that includes <type_traits>. This
- // behavior is non-conforming, since another TU could use an extern
- // template declaration for this variable, but for constexpr variables,
- // it's unlikely for a user to want to do that. This behavior can be
- // removed if the headers change to explicitly mark such variable template
- // specializations inline.
- if (isa<VarTemplateSpecializationDecl>(VD) && VD->isConstexpr())
- return GVA_DiscardableODR;
-
- // Use ODR linkage for static data members of fully specialized templates
- // to prevent duplicate definition errors with MSVC.
- if (VD->isStaticDataMember())
- return GVA_StrongODR;
- }
- return StrongLinkage;
+ return Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ VD->isStaticDataMember()
+ ? GVA_StrongODR
+ : StrongLinkage;
case TSK_ExplicitInstantiationDefinition:
return GVA_StrongODR;
@@ -9875,7 +10135,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return !D->getDeclContext()->isDependentContext();
else if (isa<OMPAllocateDecl>(D))
return !D->getDeclContext()->isDependentContext();
- else if (isa<OMPDeclareReductionDecl>(D))
+ else if (isa<OMPDeclareReductionDecl>(D) || isa<OMPDeclareMapperDecl>(D))
return !D->getDeclContext()->isDependentContext();
else if (isa<ImportDecl>(D))
return true;
@@ -9978,7 +10238,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return false;
// Variables that have destruction with side-effects are required.
- if (VD->getType().isDestructedType())
+ if (VD->needsDestruction(*this))
return true;
// Variables that have initialization with side-effects are required.
@@ -10072,6 +10332,7 @@ MangleContext *ASTContext::createMangleContext(const TargetInfo *T) {
if (!T)
T = Target;
switch (T->getCXXABI().getKind()) {
+ case TargetCXXABI::Fuchsia:
case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericItanium:
case TargetCXXABI::GenericARM:
@@ -10168,6 +10429,16 @@ ASTContext::getManglingNumberContext(const DeclContext *DC) {
return *MCtx;
}
+MangleNumberingContext &
+ASTContext::getManglingNumberContext(NeedExtraManglingDecl_t, const Decl *D) {
+ assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C.
+ std::unique_ptr<MangleNumberingContext> &MCtx =
+ ExtraMangleNumberingContexts[D];
+ if (!MCtx)
+ MCtx = createMangleNumberingContext();
+ return *MCtx;
+}
+
std::unique_ptr<MangleNumberingContext>
ASTContext::createMangleNumberingContext() const {
return ABI->createMangleNumberingContext();
@@ -10216,21 +10487,6 @@ unsigned ASTContext::getParameterIndex(const ParmVarDecl *D) const {
return I->second;
}
-APValue *
-ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
- bool MayCreate) {
- assert(E && E->getStorageDuration() == SD_Static &&
- "don't need to cache the computed value for this temporary");
- if (MayCreate) {
- APValue *&MTVI = MaterializedTemporaryValues[E];
- if (!MTVI)
- MTVI = new (*this) APValue;
- return MTVI;
- }
-
- return MaterializedTemporaryValues.lookup(E);
-}
-
QualType ASTContext::getStringLiteralArrayType(QualType EltTy,
unsigned Length) const {
// A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
@@ -10241,7 +10497,7 @@ QualType ASTContext::getStringLiteralArrayType(QualType EltTy,
// Get an array type for the string, according to C99 6.4.5. This includes
// the null terminator character.
- return getConstantArrayType(EltTy, llvm::APInt(32, Length + 1),
+ return getConstantArrayType(EltTy, llvm::APInt(32, Length + 1), nullptr,
ArrayType::Normal, /*IndexTypeQuals*/ 0);
}
@@ -10302,7 +10558,8 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) {
class ASTContext::ParentMap::ASTVisitor
: public RecursiveASTVisitor<ASTVisitor> {
public:
- ASTVisitor(ParentMap &Map) : Map(Map) {}
+ ASTVisitor(ParentMap &Map, ASTContext &Context)
+ : Map(Map), Context(Context) {}
private:
friend class RecursiveASTVisitor<ASTVisitor>;
@@ -10372,9 +10629,12 @@ private:
}
bool TraverseStmt(Stmt *StmtNode) {
- return TraverseNode(
- StmtNode, StmtNode, [&] { return VisitorBase::TraverseStmt(StmtNode); },
- &Map.PointerParents);
+ Stmt *FilteredNode = StmtNode;
+ if (auto *ExprNode = dyn_cast_or_null<Expr>(FilteredNode))
+ FilteredNode = Context.traverseIgnored(ExprNode);
+ return TraverseNode(FilteredNode, FilteredNode,
+ [&] { return VisitorBase::TraverseStmt(FilteredNode); },
+ &Map.PointerParents);
}
bool TraverseTypeLoc(TypeLoc TypeLocNode) {
@@ -10392,20 +10652,22 @@ private:
}
ParentMap &Map;
+ ASTContext &Context;
llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
};
ASTContext::ParentMap::ParentMap(ASTContext &Ctx) {
- ASTVisitor(*this).TraverseAST(Ctx);
+ ASTVisitor(*this, Ctx).TraverseAST(Ctx);
}
ASTContext::DynTypedNodeList
ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
- if (!Parents)
+ std::unique_ptr<ParentMap> &P = Parents[Traversal];
+ if (!P)
// We build the parent map for the traversal scope (usually whole TU), as
// hasAncestor can escape any subtree.
- Parents = llvm::make_unique<ParentMap>(*this);
- return Parents->getParents(Node);
+ P = std::make_unique<ParentMap>(*this);
+ return P->getParents(Node);
}
bool
@@ -10461,8 +10723,7 @@ QualType ASTContext::getCorrespondingSaturatedType(QualType Ty) const {
if (Ty->isSaturatedFixedPointType()) return Ty;
- const auto &BT = Ty->getAs<BuiltinType>();
- switch (BT->getKind()) {
+ switch (Ty->castAs<BuiltinType>()->getKind()) {
default:
llvm_unreachable("Not a fixed point type!");
case BuiltinType::ShortAccum:
@@ -10514,9 +10775,8 @@ clang::LazyGenerationalUpdatePtr<
unsigned char ASTContext::getFixedPointScale(QualType Ty) const {
assert(Ty->isFixedPointType());
- const auto *BT = Ty->getAs<BuiltinType>();
const TargetInfo &Target = getTargetInfo();
- switch (BT->getKind()) {
+ switch (Ty->castAs<BuiltinType>()->getKind()) {
default:
llvm_unreachable("Not a fixed point type!");
case BuiltinType::ShortAccum:
@@ -10561,9 +10821,8 @@ unsigned char ASTContext::getFixedPointScale(QualType Ty) const {
unsigned char ASTContext::getFixedPointIBits(QualType Ty) const {
assert(Ty->isFixedPointType());
- const auto *BT = Ty->getAs<BuiltinType>();
const TargetInfo &Target = getTargetInfo();
- switch (BT->getKind()) {
+ switch (Ty->castAs<BuiltinType>()->getKind()) {
default:
llvm_unreachable("Not a fixed point type!");
case BuiltinType::ShortAccum:
@@ -10628,9 +10887,8 @@ APFixedPoint ASTContext::getFixedPointMin(QualType Ty) const {
QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
assert(Ty->isUnsignedFixedPointType() &&
"Expected unsigned fixed point type");
- const auto *BTy = Ty->getAs<BuiltinType>();
- switch (BTy->getKind()) {
+ switch (Ty->castAs<BuiltinType>()->getKind()) {
case BuiltinType::UShortAccum:
return ShortAccumTy;
case BuiltinType::UAccum:
@@ -10659,3 +10917,66 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
llvm_unreachable("Unexpected unsigned fixed point type");
}
}
+
+ParsedTargetAttr
+ASTContext::filterFunctionTargetAttrs(const TargetAttr *TD) const {
+ assert(TD != nullptr);
+ ParsedTargetAttr ParsedAttr = TD->parse();
+
+ ParsedAttr.Features.erase(
+ llvm::remove_if(ParsedAttr.Features,
+ [&](const std::string &Feat) {
+ return !Target->isValidFeatureName(
+ StringRef{Feat}.substr(1));
+ }),
+ ParsedAttr.Features.end());
+ return ParsedAttr;
+}
+
+void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
+ const FunctionDecl *FD) const {
+ if (FD)
+ getFunctionFeatureMap(FeatureMap, GlobalDecl().getWithDecl(FD));
+ else
+ Target->initFeatureMap(FeatureMap, getDiagnostics(),
+ Target->getTargetOpts().CPU,
+ Target->getTargetOpts().Features);
+}
+
+// Fills in the supplied string map with the set of target features for the
+// passed in function.
+void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
+ GlobalDecl GD) const {
+ StringRef TargetCPU = Target->getTargetOpts().CPU;
+ const FunctionDecl *FD = GD.getDecl()->getAsFunction();
+ if (const auto *TD = FD->getAttr<TargetAttr>()) {
+ ParsedTargetAttr ParsedAttr = filterFunctionTargetAttrs(TD);
+
+ // Make a copy of the features as passed on the command line into the
+ // beginning of the additional features from the function to override.
+ ParsedAttr.Features.insert(
+ ParsedAttr.Features.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.end());
+
+ if (ParsedAttr.Architecture != "" &&
+ Target->isValidCPUName(ParsedAttr.Architecture))
+ TargetCPU = ParsedAttr.Architecture;
+
+ // Now populate the feature map, first with the TargetCPU which is either
+ // the default or a new one from the target attribute string. Then we'll use
+ // the passed in features (FeaturesAsWritten) along with the new ones from
+ // the attribute.
+ Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU,
+ ParsedAttr.Features);
+ } else if (const auto *SD = FD->getAttr<CPUSpecificAttr>()) {
+ llvm::SmallVector<StringRef, 32> FeaturesTmp;
+ Target->getCPUSpecificCPUDispatchFeatures(
+ SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp);
+ std::vector<std::string> Features(FeaturesTmp.begin(), FeaturesTmp.end());
+ Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
+ } else {
+ Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU,
+ Target->getTargetOpts().Features);
+ }
+}
diff --git a/contrib/llvm-project/clang/lib/AST/ASTDiagnostic.cpp b/contrib/llvm-project/clang/lib/AST/ASTDiagnostic.cpp
index 15df86585294..ea4d0dea58a3 100644
--- a/contrib/llvm-project/clang/lib/AST/ASTDiagnostic.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ASTDiagnostic.cpp
@@ -154,7 +154,7 @@ Underlying = CTy->desugar(); \
} \
break; \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
// If it wasn't sugared, we're done.
@@ -300,8 +300,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
// Give some additional info on vector types. These are either not desugared
// or displaying complex __attribute__ expressions so add details of the
// type and element count.
- if (Ty->isVectorType()) {
- const VectorType *VTy = Ty->getAs<VectorType>();
+ if (const auto *VTy = Ty->getAs<VectorType>()) {
std::string DecoratedString;
llvm::raw_string_ostream OS(DecoratedString);
const char *Values = VTy->getNumElements() > 1 ? "values" : "value";
@@ -338,6 +337,21 @@ void clang::FormatASTNodeDiagnosticArgument(
switch (Kind) {
default: llvm_unreachable("unknown ArgumentKind");
+ case DiagnosticsEngine::ak_addrspace: {
+ assert(Modifier.empty() && Argument.empty() &&
+ "Invalid modifier for Qualfiers argument");
+
+ auto S = Qualifiers::getAddrSpaceAsString(static_cast<LangAS>(Val));
+ if (S.empty()) {
+ OS << (Context.getLangOpts().OpenCL ? "default" : "generic");
+ OS << " address space";
+ } else {
+ OS << "address space";
+ OS << " '" << S << "'";
+ }
+ NeedQuotes = false;
+ break;
+ }
case DiagnosticsEngine::ak_qual: {
assert(Modifier.empty() && Argument.empty() &&
"Invalid modifier for Qualfiers argument");
@@ -348,7 +362,7 @@ void clang::FormatASTNodeDiagnosticArgument(
OS << "unqualified";
NeedQuotes = false;
} else {
- OS << Q.getAsString();
+ OS << S;
}
break;
}
@@ -589,8 +603,7 @@ class TemplateDiff {
unsigned ReadNode;
public:
- DiffTree() :
- CurrentNode(0), NextFreeNode(1) {
+ DiffTree() : CurrentNode(0), NextFreeNode(1), ReadNode(0) {
FlatTree.push_back(DiffNode());
}
diff --git a/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp b/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp
index 9d5dd84161de..1f2ce30398c9 100644
--- a/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp
@@ -44,6 +44,7 @@
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/AST/UnresolvedSet.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
@@ -80,6 +81,7 @@ namespace clang {
using ExpectedExpr = llvm::Expected<Expr *>;
using ExpectedDecl = llvm::Expected<Decl *>;
using ExpectedSLoc = llvm::Expected<SourceLocation>;
+ using ExpectedName = llvm::Expected<DeclarationName>;
std::string ImportError::toString() const {
// FIXME: Improve error texts.
@@ -296,6 +298,48 @@ namespace clang {
return nullptr;
}
+ void addDeclToContexts(Decl *FromD, Decl *ToD) {
+ if (Importer.isMinimalImport()) {
+ // In minimal import case the decl must be added even if it is not
+ // contained in original context, for LLDB compatibility.
+ // FIXME: Check if a better solution is possible.
+ if (!FromD->getDescribedTemplate() &&
+ FromD->getFriendObjectKind() == Decl::FOK_None)
+ ToD->getLexicalDeclContext()->addDeclInternal(ToD);
+ return;
+ }
+
+ DeclContext *FromDC = FromD->getDeclContext();
+ DeclContext *FromLexicalDC = FromD->getLexicalDeclContext();
+ DeclContext *ToDC = ToD->getDeclContext();
+ DeclContext *ToLexicalDC = ToD->getLexicalDeclContext();
+
+ bool Visible = false;
+ if (FromDC->containsDeclAndLoad(FromD)) {
+ ToDC->addDeclInternal(ToD);
+ Visible = true;
+ }
+ if (ToDC != ToLexicalDC && FromLexicalDC->containsDeclAndLoad(FromD)) {
+ ToLexicalDC->addDeclInternal(ToD);
+ Visible = true;
+ }
+
+ // If the Decl was added to any context, it was made already visible.
+ // Otherwise it is still possible that it should be visible.
+ if (!Visible) {
+ if (auto *FromNamed = dyn_cast<NamedDecl>(FromD)) {
+ auto *ToNamed = cast<NamedDecl>(ToD);
+ DeclContextLookupResult FromLookup =
+ FromDC->lookup(FromNamed->getDeclName());
+ for (NamedDecl *ND : FromLookup)
+ if (ND == FromNamed) {
+ ToDC->makeDeclVisibleInContext(ToNamed);
+ break;
+ }
+ }
+ }
+ }
+
public:
explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {}
@@ -426,6 +470,9 @@ namespace clang {
Error ImportFunctionDeclBody(FunctionDecl *FromFD, FunctionDecl *ToFD);
+ Error ImportDefaultArgOfParmVarDecl(const ParmVarDecl *FromParam,
+ ParmVarDecl *ToParam);
+
template <typename T>
bool hasSameVisibilityContext(T *Found, T *From);
@@ -479,6 +526,9 @@ namespace clang {
ExpectedDecl VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
ExpectedDecl VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
ExpectedDecl VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+ ExpectedDecl VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D);
+ ExpectedDecl
+ VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D);
Expected<ObjCTypeParamList *>
ImportObjCTypeParamList(ObjCTypeParamList *list);
@@ -635,10 +685,16 @@ namespace clang {
return ImportArrayChecked(InContainer.begin(), InContainer.end(), Obegin);
}
- void ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod);
+ Error ImportOverriddenMethods(CXXMethodDecl *ToMethod,
+ CXXMethodDecl *FromMethod);
Expected<FunctionDecl *> FindFunctionTemplateSpecialization(
FunctionDecl *FromFD);
+
+ // Returns true if the given function has a placeholder return type and
+ // that type is declared inside the body of the function.
+ // E.g. auto f() { struct X{}; return X(); }
+ bool hasAutoReturnTypeDeclaredInside(FunctionDecl *D);
};
template <typename InContainerTy>
@@ -927,6 +983,27 @@ Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) {
EllipsisLoc);
}
+template <typename T>
+bool ASTNodeImporter::hasSameVisibilityContext(T *Found, T *From) {
+ if (From->hasExternalFormalLinkage())
+ return Found->hasExternalFormalLinkage();
+ if (Importer.GetFromTU(Found) != From->getTranslationUnitDecl())
+ return false;
+ if (From->isInAnonymousNamespace())
+ return Found->isInAnonymousNamespace();
+ else
+ return !Found->isInAnonymousNamespace() &&
+ !Found->hasExternalFormalLinkage();
+}
+
+template <>
+bool ASTNodeImporter::hasSameVisibilityContext(TypedefNameDecl *Found,
+ TypedefNameDecl *From) {
+ if (From->isInAnonymousNamespace() && Found->isInAnonymousNamespace())
+ return Importer.GetFromTU(Found) == From->getTranslationUnitDecl();
+ return From->isInAnonymousNamespace() == Found->isInAnonymousNamespace();
+}
+
} // namespace clang
//----------------------------------------------------------------------------
@@ -959,6 +1036,10 @@ ExpectedType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) {
case BuiltinType::Id: \
return Importer.getToContext().Id##Ty;
#include "clang/Basic/OpenCLExtensionTypes.def"
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id: \
+ return Importer.getToContext().SingletonId;
+#include "clang/Basic/AArch64SVEACLETypes.def"
#define SHARED_SINGLETON_TYPE(Expansion)
#define BUILTIN_TYPE(Id, SingletonId) \
case BuiltinType::Id: return Importer.getToContext().SingletonId;
@@ -1068,14 +1149,16 @@ ASTNodeImporter::VisitMemberPointerType(const MemberPointerType *T) {
ExpectedType
ASTNodeImporter::VisitConstantArrayType(const ConstantArrayType *T) {
- ExpectedType ToElementTypeOrErr = import(T->getElementType());
- if (!ToElementTypeOrErr)
- return ToElementTypeOrErr.takeError();
+ QualType ToElementType;
+ const Expr *ToSizeExpr;
+ if (auto Imp = importSeq(T->getElementType(), T->getSizeExpr()))
+ std::tie(ToElementType, ToSizeExpr) = *Imp;
+ else
+ return Imp.takeError();
- return Importer.getToContext().getConstantArrayType(*ToElementTypeOrErr,
- T->getSize(),
- T->getSizeModifier(),
- T->getIndexTypeCVRQualifiers());
+ return Importer.getToContext().getConstantArrayType(
+ ToElementType, T->getSize(), ToSizeExpr, T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers());
}
ExpectedType
@@ -1283,9 +1366,21 @@ ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) {
if (!ToDeducedTypeOrErr)
return ToDeducedTypeOrErr.takeError();
- return Importer.getToContext().getAutoType(*ToDeducedTypeOrErr,
- T->getKeyword(),
- /*IsDependent*/false);
+ ExpectedDecl ToTypeConstraintConcept = import(T->getTypeConstraintConcept());
+ if (!ToTypeConstraintConcept)
+ return ToTypeConstraintConcept.takeError();
+
+ SmallVector<TemplateArgument, 2> ToTemplateArgs;
+ ArrayRef<TemplateArgument> FromTemplateArgs = T->getTypeConstraintArguments();
+ if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(),
+ FromTemplateArgs.size(),
+ ToTemplateArgs))
+ return std::move(Err);
+
+ return Importer.getToContext().getAutoType(
+ *ToDeducedTypeOrErr, T->getKeyword(), /*IsDependent*/false,
+ /*IsPack=*/false, cast_or_null<ConceptDecl>(*ToTypeConstraintConcept),
+ ToTemplateArgs);
}
ExpectedType ASTNodeImporter::VisitInjectedClassNameType(
@@ -1511,6 +1606,10 @@ Error ASTNodeImporter::ImportDeclParts(
DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc) {
// Check if RecordDecl is in FunctionDecl parameters to avoid infinite loop.
// example: int struct_in_proto(struct data_t{int a;int b;} *d);
+ // FIXME: We could support these constructs by importing a different type of
+ // this parameter and by importing the original type of the parameter only
+ // after the FunctionDecl is created. See
+ // VisitFunctionDecl::UsedDifferentProtoType.
DeclContext *OrigDC = D->getDeclContext();
FunctionDecl *FunDecl;
if (isa<RecordDecl>(D) && (FunDecl = dyn_cast<FunctionDecl>(OrigDC)) &&
@@ -1645,10 +1744,36 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
bool AccumulateChildErrors = isa<TagDecl>(FromDC);
Error ChildErrors = Error::success();
- llvm::SmallVector<Decl *, 8> ImportedDecls;
for (auto *From : FromDC->decls()) {
ExpectedDecl ImportedOrErr = import(From);
- if (!ImportedOrErr) {
+
+ // If we are in the process of ImportDefinition(...) for a RecordDecl we
+ // want to make sure that we are also completing each FieldDecl. There
+ // are currently cases where this does not happen and this is correctness
+ // fix since operations such as code generation will expect this to be so.
+ if (ImportedOrErr) {
+ FieldDecl *FieldFrom = dyn_cast_or_null<FieldDecl>(From);
+ Decl *ImportedDecl = (Decl*)*ImportedOrErr;
+ FieldDecl *FieldTo = dyn_cast_or_null<FieldDecl>(ImportedDecl);
+ if (FieldFrom && FieldTo) {
+ const RecordType *RecordFrom = FieldFrom->getType()->getAs<RecordType>();
+ const RecordType *RecordTo = FieldTo->getType()->getAs<RecordType>();
+ if (RecordFrom && RecordTo) {
+ RecordDecl *FromRecordDecl = RecordFrom->getDecl();
+ RecordDecl *ToRecordDecl = RecordTo->getDecl();
+
+ if (FromRecordDecl->isCompleteDefinition() &&
+ !ToRecordDecl->isCompleteDefinition()) {
+ Error Err = ImportDefinition(FromRecordDecl, ToRecordDecl);
+
+ if (Err && AccumulateChildErrors)
+ ChildErrors = joinErrors(std::move(ChildErrors), std::move(Err));
+ else
+ consumeError(std::move(Err));
+ }
+ }
+ }
+ } else {
if (AccumulateChildErrors)
ChildErrors =
joinErrors(std::move(ChildErrors), ImportedOrErr.takeError());
@@ -1657,6 +1782,59 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
}
}
+ // We reorder declarations in RecordDecls because they may have another order
+ // in the "to" context than they have in the "from" context. This may happen
+ // e.g when we import a class like this:
+ // struct declToImport {
+ // int a = c + b;
+ // int b = 1;
+ // int c = 2;
+ // };
+ // During the import of `a` we import first the dependencies in sequence,
+ // thus the order would be `c`, `b`, `a`. We will get the normal order by
+ // first removing the already imported members and then adding them in the
+ // order as they apper in the "from" context.
+ //
+ // Keeping field order is vital because it determines structure layout.
+ //
+ // Here and below, we cannot call field_begin() method and its callers on
+ // ToDC if it has an external storage. Calling field_begin() will
+ // automatically load all the fields by calling
+ // LoadFieldsFromExternalStorage(). LoadFieldsFromExternalStorage() would
+ // call ASTImporter::Import(). This is because the ExternalASTSource
+ // interface in LLDB is implemented by the means of the ASTImporter. However,
+ // calling an import at this point would result in an uncontrolled import, we
+ // must avoid that.
+ const auto *FromRD = dyn_cast<RecordDecl>(FromDC);
+ if (!FromRD)
+ return ChildErrors;
+
+ auto ToDCOrErr = Importer.ImportContext(FromDC);
+ if (!ToDCOrErr) {
+ consumeError(std::move(ChildErrors));
+ return ToDCOrErr.takeError();
+ }
+
+ DeclContext *ToDC = *ToDCOrErr;
+ // Remove all declarations, which may be in wrong order in the
+ // lexical DeclContext and then add them in the proper order.
+ for (auto *D : FromRD->decls()) {
+ if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) || isa<FriendDecl>(D)) {
+ assert(D && "DC contains a null decl");
+ Decl *ToD = Importer.GetAlreadyImportedOrNull(D);
+ // Remove only the decls which we successfully imported.
+ if (ToD) {
+ assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD));
+ // Remove the decl from its wrong place in the linked list.
+ ToDC->removeDecl(ToD);
+ // Add the decl to the end of the linked list.
+ // This time it will be at the proper place because the enclosing for
+ // loop iterates in the original (good) order of the decls.
+ ToDC->addDeclInternal(ToD);
+ }
+ }
+ }
+
return ChildErrors;
}
@@ -1752,71 +1930,10 @@ Error ASTNodeImporter::ImportDefinition(
struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data();
struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data();
- ToData.UserDeclaredConstructor = FromData.UserDeclaredConstructor;
- ToData.UserDeclaredSpecialMembers = FromData.UserDeclaredSpecialMembers;
- ToData.Aggregate = FromData.Aggregate;
- ToData.PlainOldData = FromData.PlainOldData;
- ToData.Empty = FromData.Empty;
- ToData.Polymorphic = FromData.Polymorphic;
- ToData.Abstract = FromData.Abstract;
- ToData.IsStandardLayout = FromData.IsStandardLayout;
- ToData.IsCXX11StandardLayout = FromData.IsCXX11StandardLayout;
- ToData.HasBasesWithFields = FromData.HasBasesWithFields;
- ToData.HasBasesWithNonStaticDataMembers =
- FromData.HasBasesWithNonStaticDataMembers;
- ToData.HasPrivateFields = FromData.HasPrivateFields;
- ToData.HasProtectedFields = FromData.HasProtectedFields;
- ToData.HasPublicFields = FromData.HasPublicFields;
- ToData.HasMutableFields = FromData.HasMutableFields;
- ToData.HasVariantMembers = FromData.HasVariantMembers;
- ToData.HasOnlyCMembers = FromData.HasOnlyCMembers;
- ToData.HasInClassInitializer = FromData.HasInClassInitializer;
- ToData.HasUninitializedReferenceMember
- = FromData.HasUninitializedReferenceMember;
- ToData.HasUninitializedFields = FromData.HasUninitializedFields;
- ToData.HasInheritedConstructor = FromData.HasInheritedConstructor;
- ToData.HasInheritedAssignment = FromData.HasInheritedAssignment;
- ToData.NeedOverloadResolutionForCopyConstructor
- = FromData.NeedOverloadResolutionForCopyConstructor;
- ToData.NeedOverloadResolutionForMoveConstructor
- = FromData.NeedOverloadResolutionForMoveConstructor;
- ToData.NeedOverloadResolutionForMoveAssignment
- = FromData.NeedOverloadResolutionForMoveAssignment;
- ToData.NeedOverloadResolutionForDestructor
- = FromData.NeedOverloadResolutionForDestructor;
- ToData.DefaultedCopyConstructorIsDeleted
- = FromData.DefaultedCopyConstructorIsDeleted;
- ToData.DefaultedMoveConstructorIsDeleted
- = FromData.DefaultedMoveConstructorIsDeleted;
- ToData.DefaultedMoveAssignmentIsDeleted
- = FromData.DefaultedMoveAssignmentIsDeleted;
- ToData.DefaultedDestructorIsDeleted = FromData.DefaultedDestructorIsDeleted;
- ToData.HasTrivialSpecialMembers = FromData.HasTrivialSpecialMembers;
- ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
- ToData.HasConstexprNonCopyMoveConstructor
- = FromData.HasConstexprNonCopyMoveConstructor;
- ToData.HasDefaultedDefaultConstructor
- = FromData.HasDefaultedDefaultConstructor;
- ToData.DefaultedDefaultConstructorIsConstexpr
- = FromData.DefaultedDefaultConstructorIsConstexpr;
- ToData.HasConstexprDefaultConstructor
- = FromData.HasConstexprDefaultConstructor;
- ToData.HasNonLiteralTypeFieldsOrBases
- = FromData.HasNonLiteralTypeFieldsOrBases;
- // ComputedVisibleConversions not imported.
- ToData.UserProvidedDefaultConstructor
- = FromData.UserProvidedDefaultConstructor;
- ToData.DeclaredSpecialMembers = FromData.DeclaredSpecialMembers;
- ToData.ImplicitCopyConstructorCanHaveConstParamForVBase
- = FromData.ImplicitCopyConstructorCanHaveConstParamForVBase;
- ToData.ImplicitCopyConstructorCanHaveConstParamForNonVBase
- = FromData.ImplicitCopyConstructorCanHaveConstParamForNonVBase;
- ToData.ImplicitCopyAssignmentHasConstParam
- = FromData.ImplicitCopyAssignmentHasConstParam;
- ToData.HasDeclaredCopyConstructorWithConstParam
- = FromData.HasDeclaredCopyConstructorWithConstParam;
- ToData.HasDeclaredCopyAssignmentWithConstParam
- = FromData.HasDeclaredCopyAssignmentWithConstParam;
+
+ #define FIELD(Name, Width, Merge) \
+ ToData.Name = FromData.Name;
+ #include "clang/AST/CXXRecordDeclDefinitionBits.def"
// Copy over the data stored in RecordDeclBits
ToCXX->setArgPassingRestrictions(FromCXX->getArgPassingRestrictions());
@@ -2188,17 +2305,22 @@ ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Namespace,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, Decl::IDNS_Namespace, ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc());
if (!BeginLocOrErr)
return BeginLocOrErr.takeError();
+ ExpectedSLoc RBraceLocOrErr = import(D->getRBraceLoc());
+ if (!RBraceLocOrErr)
+ return RBraceLocOrErr.takeError();
// Create the "to" namespace, if needed.
NamespaceDecl *ToNamespace = MergeWithNamespace;
@@ -2208,6 +2330,7 @@ ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
*BeginLocOrErr, Loc, Name.getAsIdentifierInfo(),
/*PrevDecl=*/nullptr))
return ToNamespace;
+ ToNamespace->setRBraceLoc(*RBraceLocOrErr);
ToNamespace->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToNamespace);
@@ -2281,6 +2404,9 @@ ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
// If this typedef is not in block scope, determine whether we've
// seen a typedef with the same name (that we can merge with) or any
// other entity by that name (which name lookup could conflict with).
+ // Note: Repeated typedefs are not valid in C99:
+ // 'typedef int T; typedef int T;' is invalid
+ // We do not care about this now.
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
@@ -2289,6 +2415,9 @@ ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
if (!FoundDecl->isInIdentifierNamespace(IDNS))
continue;
if (auto *FoundTypedef = dyn_cast<TypedefNameDecl>(FoundDecl)) {
+ if (!hasSameVisibilityContext(FoundTypedef, D))
+ continue;
+
QualType FromUT = D->getUnderlyingType();
QualType FoundUT = FoundTypedef->getUnderlyingType();
if (Importer.IsStructurallyEquivalent(FromUT, FoundUT)) {
@@ -2296,21 +2425,21 @@ ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
// already have a complete underlying type then return with that.
if (!FromUT->isIncompleteType() && !FoundUT->isIncompleteType())
return Importer.MapImported(D, FoundTypedef);
+ // FIXME Handle redecl chain. When you do that make consistent changes
+ // in ASTImporterLookupTable too.
+ } else {
+ ConflictingDecls.push_back(FoundDecl);
}
- // FIXME Handle redecl chain. When you do that make consistent changes
- // in ASTImporterLookupTable too.
- break;
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -2383,11 +2512,12 @@ ASTNodeImporter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -2491,26 +2621,28 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
continue;
if (IsStructuralMatch(D, FoundEnum))
return Importer.MapImported(D, FoundEnum);
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(SearchName, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ SearchName, DC, IDNS, ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
SourceLocation ToBeginLoc;
NestedNameSpecifierLoc ToQualifierLoc;
QualType ToIntegerType;
- if (auto Imp = importSeq(
- D->getBeginLoc(), D->getQualifierLoc(), D->getIntegerType()))
- std::tie(ToBeginLoc, ToQualifierLoc, ToIntegerType) = *Imp;
+ SourceRange ToBraceRange;
+ if (auto Imp = importSeq(D->getBeginLoc(), D->getQualifierLoc(),
+ D->getIntegerType(), D->getBraceRange()))
+ std::tie(ToBeginLoc, ToQualifierLoc, ToIntegerType, ToBraceRange) = *Imp;
else
return Imp.takeError();
@@ -2524,6 +2656,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
D2->setQualifierInfo(ToQualifierLoc);
D2->setIntegerType(ToIntegerType);
+ D2->setBraceRange(ToBraceRange);
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(D2);
@@ -2546,10 +2679,10 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
}
// Import the major distinguishing characteristics of this record.
- DeclContext *DC, *LexicalDC;
+ DeclContext *DC = nullptr, *LexicalDC = nullptr;
DeclarationName Name;
SourceLocation Loc;
- NamedDecl *ToD;
+ NamedDecl *ToD = nullptr;
if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc))
return std::move(Err);
if (ToD)
@@ -2568,7 +2701,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
// We may already have a record of the same name; try to find and match it.
RecordDecl *PrevDecl = nullptr;
- if (!DC->isFunctionOrMethod()) {
+ if (!DC->isFunctionOrMethod() && !D->isLambda()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
auto FoundDecls =
Importer.findDeclsInToCtx(DC, SearchName);
@@ -2626,17 +2759,18 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
PrevDecl = FoundRecord->getMostRecentDecl();
break;
}
- }
-
- ConflictingDecls.push_back(FoundDecl);
+ ConflictingDecls.push_back(FoundDecl);
+ } // kind is RecordDecl
} // for
if (!ConflictingDecls.empty() && SearchName) {
- Name = Importer.HandleNameConflict(SearchName, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ SearchName, DC, IDNS, ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -2660,7 +2794,8 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
ExpectedDecl CDeclOrErr = import(DCXX->getLambdaContextDecl());
if (!CDeclOrErr)
return CDeclOrErr.takeError();
- D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), *CDeclOrErr);
+ D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), *CDeclOrErr,
+ DCXX->hasKnownLambdaInternalLinkage());
} else if (DCXX->isInjectedClassName()) {
// We have to be careful to do a similar dance to the one in
// Sema::ActOnStartCXXMemberDeclarations
@@ -2683,11 +2818,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
D2 = D2CXX;
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
- if (!DCXX->getDescribedClassTemplate() || DCXX->isImplicit())
- LexicalDC->addDeclInternal(D2);
-
- if (LexicalDC != DC && D->isInIdentifierNamespace(Decl::IDNS_TagFriend))
- DC->makeDeclVisibleInContext(D2);
+ addDeclToContexts(D, D2);
if (ClassTemplateDecl *FromDescribed =
DCXX->getDescribedClassTemplate()) {
@@ -2753,9 +2884,13 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
Name.getAsIdentifierInfo(), PrevDecl))
return D2;
D2->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDeclInternal(D2);
+ addDeclToContexts(D, D2);
}
+ if (auto BraceRangeOrErr = import(D->getBraceRange()))
+ D2->setBraceRange(*BraceRangeOrErr);
+ else
+ return BraceRangeOrErr.takeError();
if (auto QualifierLocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*QualifierLocOrErr);
else
@@ -2795,17 +2930,17 @@ ExpectedDecl ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
if (auto *FoundEnumConstant = dyn_cast<EnumConstantDecl>(FoundDecl)) {
if (IsStructuralMatch(D, FoundEnumConstant))
return Importer.MapImported(D, FoundEnumConstant);
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -2956,17 +3091,44 @@ Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD,
return Error::success();
}
-template <typename T>
-bool ASTNodeImporter::hasSameVisibilityContext(T *Found, T *From) {
- if (From->hasExternalFormalLinkage())
- return Found->hasExternalFormalLinkage();
- if (Importer.GetFromTU(Found) != From->getTranslationUnitDecl())
- return false;
- if (From->isInAnonymousNamespace())
- return Found->isInAnonymousNamespace();
- else
- return !Found->isInAnonymousNamespace() &&
- !Found->hasExternalFormalLinkage();
+// Returns true if the given D has a DeclContext up to the TranslationUnitDecl
+// which is equal to the given DC.
+static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
+ const DeclContext *DCi = D->getDeclContext();
+ while (DCi != D->getTranslationUnitDecl()) {
+ if (DCi == DC)
+ return true;
+ DCi = DCi->getParent();
+ }
+ return false;
+}
+
+bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
+ QualType FromTy = D->getType();
+ const FunctionProtoType *FromFPT = FromTy->getAs<FunctionProtoType>();
+ assert(FromFPT && "Must be called on FunctionProtoType");
+ if (AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) {
+ QualType DeducedT = AutoT->getDeducedType();
+ if (const RecordType *RecordT =
+ DeducedT.isNull() ? nullptr : dyn_cast<RecordType>(DeducedT)) {
+ RecordDecl *RD = RecordT->getDecl();
+ assert(RD);
+ if (isAncestorDeclContextOf(D, RD)) {
+ assert(RD->getLexicalDeclContext() == RD->getDeclContext());
+ return true;
+ }
+ }
+ }
+ if (const TypedefType *TypedefT =
+ dyn_cast<TypedefType>(FromFPT->getReturnType())) {
+ TypedefNameDecl *TD = TypedefT->getDecl();
+ assert(TD);
+ if (isAncestorDeclContextOf(D, TD)) {
+ assert(TD->getLexicalDeclContext() == TD->getDeclContext());
+ return true;
+ }
+ }
+ return false;
}
ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
@@ -3043,17 +3205,17 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
<< Name << D->getType() << FoundFunction->getType();
Importer.ToDiag(FoundFunction->getLocation(), diag::note_odr_value_here)
<< FoundFunction->getType();
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -3066,9 +3228,19 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (FoundByLookup) {
if (isa<CXXMethodDecl>(FoundByLookup)) {
if (D->getLexicalDeclContext() == D->getDeclContext()) {
- if (!D->doesThisDeclarationHaveABody())
+ if (!D->doesThisDeclarationHaveABody()) {
+ if (FunctionTemplateDecl *DescribedD =
+ D->getDescribedFunctionTemplate()) {
+ // Handle a "templated" function together with its described
+ // template. This avoids need for a similar check at import of the
+ // described template.
+ assert(FoundByLookup->getDescribedFunctionTemplate() &&
+ "Templated function mapped to non-templated?");
+ Importer.MapImported(DescribedD,
+ FoundByLookup->getDescribedFunctionTemplate());
+ }
return Importer.MapImported(D, FoundByLookup);
- else {
+ } else {
// Let's continue and build up the redecl chain in this case.
// FIXME Merge the functions into one decl.
}
@@ -3082,32 +3254,49 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
return std::move(Err);
QualType FromTy = D->getType();
- bool usedDifferentExceptionSpec = false;
-
- if (const auto *FromFPT = D->getType()->getAs<FunctionProtoType>()) {
+ // Set to true if we do not import the type of the function as is. There are
+ // cases when the original type would result in an infinite recursion during
+ // the import. To avoid an infinite recursion when importing, we create the
+ // FunctionDecl with a simplified function type and update it only after the
+ // relevant AST nodes are already imported.
+ bool UsedDifferentProtoType = false;
+ if (const auto *FromFPT = FromTy->getAs<FunctionProtoType>()) {
+ QualType FromReturnTy = FromFPT->getReturnType();
+ // Functions with auto return type may define a struct inside their body
+ // and the return type could refer to that struct.
+ // E.g.: auto foo() { struct X{}; return X(); }
+ // To avoid an infinite recursion when importing, create the FunctionDecl
+ // with a simplified return type.
+ if (hasAutoReturnTypeDeclaredInside(D)) {
+ FromReturnTy = Importer.getFromContext().VoidTy;
+ UsedDifferentProtoType = true;
+ }
FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo();
// FunctionProtoType::ExtProtoInfo's ExceptionSpecDecl can point to the
// FunctionDecl that we are importing the FunctionProtoType for.
// To avoid an infinite recursion when importing, create the FunctionDecl
- // with a simplified function type and update it afterwards.
+ // with a simplified function type.
if (FromEPI.ExceptionSpec.SourceDecl ||
FromEPI.ExceptionSpec.SourceTemplate ||
FromEPI.ExceptionSpec.NoexceptExpr) {
FunctionProtoType::ExtProtoInfo DefaultEPI;
- FromTy = Importer.getFromContext().getFunctionType(
- FromFPT->getReturnType(), FromFPT->getParamTypes(), DefaultEPI);
- usedDifferentExceptionSpec = true;
+ FromEPI = DefaultEPI;
+ UsedDifferentProtoType = true;
}
+ FromTy = Importer.getFromContext().getFunctionType(
+ FromReturnTy, FromFPT->getParamTypes(), FromEPI);
}
QualType T;
TypeSourceInfo *TInfo;
SourceLocation ToInnerLocStart, ToEndLoc;
NestedNameSpecifierLoc ToQualifierLoc;
+ Expr *TrailingRequiresClause;
if (auto Imp = importSeq(
FromTy, D->getTypeSourceInfo(), D->getInnerLocStart(),
- D->getQualifierLoc(), D->getEndLoc()))
- std::tie(T, TInfo, ToInnerLocStart, ToQualifierLoc, ToEndLoc) = *Imp;
+ D->getQualifierLoc(), D->getEndLoc(), D->getTrailingRequiresClause()))
+ std::tie(T, TInfo, ToInnerLocStart, ToQualifierLoc, ToEndLoc,
+ TrailingRequiresClause) = *Imp;
else
return Imp.takeError();
@@ -3136,7 +3325,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ExplicitSpecifier(
ExplicitExpr,
FromConstructor->getExplicitSpecifier().getKind()),
- D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind()))
+ D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind(),
+ InheritedConstructor(), // FIXME: Properly import inherited
+ // constructor info
+ TrailingRequiresClause))
return ToFunction;
} else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {
@@ -3154,7 +3346,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (GetImportedOrCreateDecl<CXXDestructorDecl>(
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
- D->isImplicit()))
+ D->isImplicit(), D->getConstexprKind(), TrailingRequiresClause))
return ToFunction;
CXXDestructorDecl *ToDtor = cast<CXXDestructorDecl>(ToFunction);
@@ -3174,20 +3366,21 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
ExplicitSpecifier(ExplicitExpr,
FromConversion->getExplicitSpecifier().getKind()),
- D->getConstexprKind(), SourceLocation()))
+ D->getConstexprKind(), SourceLocation(), TrailingRequiresClause))
return ToFunction;
} else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) {
if (GetImportedOrCreateDecl<CXXMethodDecl>(
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
ToInnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(),
Method->isInlineSpecified(), D->getConstexprKind(),
- SourceLocation()))
+ SourceLocation(), TrailingRequiresClause))
return ToFunction;
} else {
if (GetImportedOrCreateDecl(
ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart,
NameInfo, T, TInfo, D->getStorageClass(), D->isInlineSpecified(),
- D->hasWrittenPrototype(), D->getConstexprKind()))
+ D->hasWrittenPrototype(), D->getConstexprKind(),
+ TrailingRequiresClause))
return ToFunction;
}
@@ -3203,29 +3396,15 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// decl and its redeclarations may be required.
}
- // Import Ctor initializers.
- if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
- if (unsigned NumInitializers = FromConstructor->getNumCtorInitializers()) {
- SmallVector<CXXCtorInitializer *, 4> CtorInitializers(NumInitializers);
- // Import first, then allocate memory and copy if there was no error.
- if (Error Err = ImportContainerChecked(
- FromConstructor->inits(), CtorInitializers))
- return std::move(Err);
- auto **Memory =
- new (Importer.getToContext()) CXXCtorInitializer *[NumInitializers];
- std::copy(CtorInitializers.begin(), CtorInitializers.end(), Memory);
- auto *ToCtor = cast<CXXConstructorDecl>(ToFunction);
- ToCtor->setCtorInitializers(Memory);
- ToCtor->setNumCtorInitializers(NumInitializers);
- }
- }
-
ToFunction->setQualifierInfo(ToQualifierLoc);
ToFunction->setAccess(D->getAccess());
ToFunction->setLexicalDeclContext(LexicalDC);
ToFunction->setVirtualAsWritten(D->isVirtualAsWritten());
ToFunction->setTrivial(D->isTrivial());
ToFunction->setPure(D->isPure());
+ ToFunction->setDefaulted(D->isDefaulted());
+ ToFunction->setExplicitlyDefaulted(D->isExplicitlyDefaulted());
+ ToFunction->setDeletedAsWritten(D->isDeletedAsWritten());
ToFunction->setRangeEnd(ToEndLoc);
// Set the parameters.
@@ -3245,14 +3424,6 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
}
- if (usedDifferentExceptionSpec) {
- // Update FunctionProtoType::ExtProtoInfo.
- if (ExpectedType TyOrErr = import(D->getType()))
- ToFunction->setType(*TyOrErr);
- else
- return TyOrErr.takeError();
- }
-
// Import the describing template function, if any.
if (FromFT) {
auto ToFTOrErr = import(FromFT);
@@ -3260,6 +3431,23 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
return ToFTOrErr.takeError();
}
+ // Import Ctor initializers.
+ if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
+ if (unsigned NumInitializers = FromConstructor->getNumCtorInitializers()) {
+ SmallVector<CXXCtorInitializer *, 4> CtorInitializers(NumInitializers);
+ // Import first, then allocate memory and copy if there was no error.
+ if (Error Err = ImportContainerChecked(
+ FromConstructor->inits(), CtorInitializers))
+ return std::move(Err);
+ auto **Memory =
+ new (Importer.getToContext()) CXXCtorInitializer *[NumInitializers];
+ std::copy(CtorInitializers.begin(), CtorInitializers.end(), Memory);
+ auto *ToCtor = cast<CXXConstructorDecl>(ToFunction);
+ ToCtor->setCtorInitializers(Memory);
+ ToCtor->setNumCtorInitializers(NumInitializers);
+ }
+ }
+
if (D->doesThisDeclarationHaveABody()) {
Error Err = ImportFunctionDeclBody(D, ToFunction);
@@ -3267,32 +3455,26 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
return std::move(Err);
}
+ // Import and set the original type in case we used another type.
+ if (UsedDifferentProtoType) {
+ if (ExpectedType TyOrErr = import(D->getType()))
+ ToFunction->setType(*TyOrErr);
+ else
+ return TyOrErr.takeError();
+ }
+
// FIXME: Other bits to merge?
// If it is a template, import all related things.
if (Error Err = ImportTemplateInformation(D, ToFunction))
return std::move(Err);
- bool IsFriend = D->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend);
-
- // TODO Can we generalize this approach to other AST nodes as well?
- if (D->getDeclContext()->containsDeclAndLoad(D))
- DC->addDeclInternal(ToFunction);
- if (DC != LexicalDC && D->getLexicalDeclContext()->containsDeclAndLoad(D))
- LexicalDC->addDeclInternal(ToFunction);
-
- // Friend declaration's lexical context is the befriending class, but the
- // semantic context is the enclosing scope of the befriending class.
- // We want the friend functions to be found in the semantic context by lookup.
- // FIXME should we handle this generically in VisitFriendDecl?
- // In Other cases when LexicalDC != DC we don't want it to be added,
- // e.g out-of-class definitions like void B::f() {} .
- if (LexicalDC != DC && IsFriend) {
- DC->makeDeclVisibleInContext(ToFunction);
- }
+ addDeclToContexts(D, ToFunction);
if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
- ImportOverrides(cast<CXXMethodDecl>(ToFunction), FromCXXMethod);
+ if (Error Err = ImportOverriddenMethods(cast<CXXMethodDecl>(ToFunction),
+ FromCXXMethod))
+ return std::move(Err);
// Import the rest of the chain. I.e. import all subsequent declarations.
for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) {
@@ -3686,17 +3868,17 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) {
<< Name << D->getType() << FoundVar->getType();
Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here)
<< FoundVar->getType();
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -3735,10 +3917,7 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) {
if (D->isConstexpr())
ToVar->setConstexpr(true);
- if (D->getDeclContext()->containsDeclAndLoad(D))
- DC->addDeclInternal(ToVar);
- if (DC != LexicalDC && D->getLexicalDeclContext()->containsDeclAndLoad(D))
- LexicalDC->addDeclInternal(ToVar);
+ addDeclToContexts(D, ToVar);
// Import the rest of the chain. I.e. import all subsequent declarations.
for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) {
@@ -3772,6 +3951,28 @@ ExpectedDecl ASTNodeImporter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
return ToParm;
}
+Error ASTNodeImporter::ImportDefaultArgOfParmVarDecl(
+ const ParmVarDecl *FromParam, ParmVarDecl *ToParam) {
+ ToParam->setHasInheritedDefaultArg(FromParam->hasInheritedDefaultArg());
+ ToParam->setKNRPromoted(FromParam->isKNRPromoted());
+
+ if (FromParam->hasUninstantiatedDefaultArg()) {
+ if (auto ToDefArgOrErr = import(FromParam->getUninstantiatedDefaultArg()))
+ ToParam->setUninstantiatedDefaultArg(*ToDefArgOrErr);
+ else
+ return ToDefArgOrErr.takeError();
+ } else if (FromParam->hasUnparsedDefaultArg()) {
+ ToParam->setUnparsedDefaultArg();
+ } else if (FromParam->hasDefaultArg()) {
+ if (auto ToDefArgOrErr = import(FromParam->getDefaultArg()))
+ ToParam->setDefaultArg(*ToDefArgOrErr);
+ else
+ return ToDefArgOrErr.takeError();
+ }
+
+ return Error::success();
+}
+
ExpectedDecl ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
// Parameters are created in the translation unit's context, then moved
// into the function declaration's context afterward.
@@ -3798,23 +3999,11 @@ ExpectedDecl ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
/*DefaultArg*/ nullptr))
return ToParm;
- // Set the default argument.
- ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg());
- ToParm->setKNRPromoted(D->isKNRPromoted());
-
- if (D->hasUninstantiatedDefaultArg()) {
- if (auto ToDefArgOrErr = import(D->getUninstantiatedDefaultArg()))
- ToParm->setUninstantiatedDefaultArg(*ToDefArgOrErr);
- else
- return ToDefArgOrErr.takeError();
- } else if (D->hasUnparsedDefaultArg()) {
- ToParm->setUnparsedDefaultArg();
- } else if (D->hasDefaultArg()) {
- if (auto ToDefArgOrErr = import(D->getDefaultArg()))
- ToParm->setDefaultArg(*ToDefArgOrErr);
- else
- return ToDefArgOrErr.takeError();
- }
+ // Set the default argument. It should be no problem if it was already done.
+ // Do not import the default expression before GetImportedOrCreateDecl call
+ // to avoid possible infinite import loop because circular dependency.
+ if (Error Err = ImportDefaultArgOfParmVarDecl(D, ToParm))
+ return std::move(Err);
if (D->isObjCMethodParameter()) {
ToParm->setObjCMethodScopeInfo(D->getFunctionScopeIndex());
@@ -3914,10 +4103,10 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
ObjCMethodDecl *ToMethod;
if (GetImportedOrCreateDecl(
- ToMethod, D, Importer.getToContext(), Loc,
- ToEndLoc, Name.getObjCSelector(), ToReturnType,
- ToReturnTypeSourceInfo, DC, D->isInstanceMethod(), D->isVariadic(),
- D->isPropertyAccessor(), D->isImplicit(), D->isDefined(),
+ ToMethod, D, Importer.getToContext(), Loc, ToEndLoc,
+ Name.getObjCSelector(), ToReturnType, ToReturnTypeSourceInfo, DC,
+ D->isInstanceMethod(), D->isVariadic(), D->isPropertyAccessor(),
+ D->isSynthesizedAccessorStub(), D->isImplicit(), D->isDefined(),
D->getImplementationControl(), D->hasRelatedResultType()))
return ToMethod;
@@ -3949,6 +4138,14 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
ToMethod->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToMethod);
+
+ // Implicit params are declared when Sema encounters the definition but this
+ // never happens when the method is imported. Manually declare the implicit
+ // params now that the MethodDecl knows its class interface.
+ if (D->getSelfDecl())
+ ToMethod->createImplicitParams(Importer.getToContext(),
+ ToMethod->getClassInterface());
+
return ToMethod;
}
@@ -4417,6 +4614,20 @@ ExpectedDecl ASTNodeImporter::VisitUnresolvedUsingTypenameDecl(
return ToUsing;
}
+ExpectedDecl ASTNodeImporter::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) {
+ Decl* ToD = nullptr;
+ switch (D->getBuiltinTemplateKind()) {
+ case BuiltinTemplateKind::BTK__make_integer_seq:
+ ToD = Importer.getToContext().getMakeIntegerSeqDecl();
+ break;
+ case BuiltinTemplateKind::BTK__type_pack_element:
+ ToD = Importer.getToContext().getTypePackElementDecl();
+ break;
+ }
+ assert(ToD && "BuiltinTemplateDecl of unsupported kind!");
+ Importer.MapImported(D, ToD);
+ return ToD;
+}
Error ASTNodeImporter::ImportDefinition(
ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, ImportDefinitionKind Kind) {
@@ -4898,7 +5109,7 @@ ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
// context. This context will be fixed when the actual template declaration
// is created.
- // FIXME: Import default argument.
+ // FIXME: Import default argument and constraint expression.
ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc());
if (!BeginLocOrErr)
@@ -4909,12 +5120,47 @@ ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
return LocationOrErr.takeError();
TemplateTypeParmDecl *ToD = nullptr;
- (void)GetImportedOrCreateDecl(
+ if (GetImportedOrCreateDecl(
ToD, D, Importer.getToContext(),
Importer.getToContext().getTranslationUnitDecl(),
*BeginLocOrErr, *LocationOrErr,
D->getDepth(), D->getIndex(), Importer.Import(D->getIdentifier()),
- D->wasDeclaredWithTypename(), D->isParameterPack());
+ D->wasDeclaredWithTypename(), D->isParameterPack(),
+ D->hasTypeConstraint()))
+ return ToD;
+
+ // Import the type-constraint
+ if (const TypeConstraint *TC = D->getTypeConstraint()) {
+ NestedNameSpecifierLoc ToNNS;
+ DeclarationName ToName;
+ SourceLocation ToNameLoc;
+ NamedDecl *ToFoundDecl;
+ ConceptDecl *ToNamedConcept;
+ Expr *ToIDC;
+ if (auto Imp = importSeq(TC->getNestedNameSpecifierLoc(),
+ TC->getConceptNameInfo().getName(), TC->getConceptNameInfo().getLoc(),
+ TC->getFoundDecl(), TC->getNamedConcept(),
+ TC->getImmediatelyDeclaredConstraint()))
+ std::tie(ToNNS, ToName, ToNameLoc, ToFoundDecl, ToNamedConcept,
+ ToIDC) = *Imp;
+ else
+ return Imp.takeError();
+
+ TemplateArgumentListInfo ToTAInfo;
+ const auto *ASTTemplateArgs = TC->getTemplateArgsAsWritten();
+ if (ASTTemplateArgs)
+ if (Error Err = ImportTemplateArgumentListInfo(*ASTTemplateArgs,
+ ToTAInfo))
+ return std::move(Err);
+
+ ToD->setTypeConstraint(ToNNS, DeclarationNameInfo(ToName, ToNameLoc),
+ ToFoundDecl, ToNamedConcept,
+ ASTTemplateArgs ?
+ ASTTemplateArgumentListInfo::Create(Importer.getToContext(),
+ ToTAInfo) : nullptr,
+ ToIDC);
+ }
+
return ToD;
}
@@ -4986,7 +5232,6 @@ template <typename T> static auto getTemplateDefinition(T *D) -> T * {
}
ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
- bool IsFriend = D->getFriendObjectKind() != Decl::FOK_None;
// Import the major distinguishing characteristics of this class template.
DeclContext *DC, *LexicalDC;
@@ -5012,29 +5257,33 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Decl *Found = FoundDecl;
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found);
if (FoundTemplate) {
+ if (!hasSameVisibilityContext(FoundTemplate, D))
+ continue;
if (IsStructuralMatch(D, FoundTemplate)) {
ClassTemplateDecl *TemplateWithDef =
getTemplateDefinition(FoundTemplate);
- if (D->isThisDeclarationADefinition() && TemplateWithDef) {
+ if (D->isThisDeclarationADefinition() && TemplateWithDef)
return Importer.MapImported(D, TemplateWithDef);
- }
- FoundByLookup = FoundTemplate;
- break;
+ if (!FoundByLookup)
+ FoundByLookup = FoundTemplate;
+ // Search in all matches because there may be multiple decl chains,
+ // see ASTTests test ImportExistingFriendClassTemplateDef.
+ continue;
}
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
- ConflictingDecls.data(),
- ConflictingDecls.size());
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, Decl::IDNS_Ordinary, ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
-
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
}
CXXRecordDecl *FromTemplated = D->getTemplatedDecl();
@@ -5059,10 +5308,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
- if (D->getDeclContext()->containsDeclAndLoad(D))
- DC->addDeclInternal(D2);
- if (DC != LexicalDC && D->getLexicalDeclContext()->containsDeclAndLoad(D))
- LexicalDC->addDeclInternal(D2);
+ addDeclToContexts(D, D2);
if (FoundByLookup) {
auto *Recent =
@@ -5088,9 +5334,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
D2->setPreviousDecl(Recent);
}
- if (LexicalDC != DC && IsFriend)
- DC->makeDeclVisibleInContext(D2);
-
if (FromTemplated->isCompleteDefinition() &&
!ToTemplated->isCompleteDefinition()) {
// FIXME: Import definition!
@@ -5115,16 +5358,25 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (Error Err = ImportTemplateArguments(
D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs))
return std::move(Err);
-
- // Try to find an existing specialization with these template arguments.
+ // Try to find an existing specialization with these template arguments and
+ // template parameter list.
void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl = nullptr;
ClassTemplatePartialSpecializationDecl *PartialSpec =
dyn_cast<ClassTemplatePartialSpecializationDecl>(D);
- if (PartialSpec)
- PrevDecl =
- ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos);
- else
+
+ // Import template parameters.
+ TemplateParameterList *ToTPList = nullptr;
+
+ if (PartialSpec) {
+ auto ToTPListOrErr = import(PartialSpec->getTemplateParameters());
+ if (!ToTPListOrErr)
+ return ToTPListOrErr.takeError();
+ ToTPList = *ToTPListOrErr;
+ PrevDecl = ClassTemplate->findPartialSpecialization(TemplateArgs,
+ *ToTPListOrErr,
+ InsertPos);
+ } else
PrevDecl = ClassTemplate->findSpecialization(TemplateArgs, InsertPos);
if (PrevDecl) {
@@ -5183,13 +5435,9 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
return std::move(Err);
CanonInjType = CanonInjType.getCanonicalType();
- auto ToTPListOrErr = import(PartialSpec->getTemplateParameters());
- if (!ToTPListOrErr)
- return ToTPListOrErr.takeError();
-
if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
D2, D, Importer.getToContext(), D->getTagKind(), DC,
- *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, ClassTemplate,
+ *BeginLocOrErr, *IdLocOrErr, ToTPList, ClassTemplate,
llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()),
ToTAInfo, CanonInjType,
cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
@@ -5197,10 +5445,11 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
// Update InsertPos, because preceding import calls may have invalidated
// it by adding new specializations.
- if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos))
+ auto *PartSpec2 = cast<ClassTemplatePartialSpecializationDecl>(D2);
+ if (!ClassTemplate->findPartialSpecialization(TemplateArgs, ToTPList,
+ InsertPos))
// Add this partial specialization to the class template.
- ClassTemplate->AddPartialSpecialization(
- cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos);
+ ClassTemplate->AddPartialSpecialization(PartSpec2, InsertPos);
} else { // Not a partial specialization.
if (GetImportedOrCreateDecl(
@@ -5226,6 +5475,11 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
LexicalDC->addDeclInternal(D2);
}
+ if (auto BraceRangeOrErr = import(D->getBraceRange()))
+ D2->setBraceRange(*BraceRangeOrErr);
+ else
+ return BraceRangeOrErr.takeError();
+
// Import the qualifier, if any.
if (auto LocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*LocOrErr);
@@ -5307,22 +5561,20 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
FoundTemplate->getTemplatedDecl());
return Importer.MapImported(D, FoundTemplate);
}
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
- ConflictingDecls.data(),
- ConflictingDecls.size());
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, Decl::IDNS_Ordinary, ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
- if (!Name)
- // FIXME: Is it possible to get other error than name conflict?
- // (Put this `if` into the previous `if`?)
- return make_error<ImportError>(ImportError::NameConflict);
-
VarDecl *DTemplated = D->getTemplatedDecl();
// Import the type.
@@ -5533,17 +5785,16 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
continue;
if (auto *FoundTemplate = dyn_cast<FunctionTemplateDecl>(FoundDecl)) {
- if (FoundTemplate->hasExternalFormalLinkage() &&
- D->hasExternalFormalLinkage()) {
- if (IsStructuralMatch(D, FoundTemplate)) {
- FunctionTemplateDecl *TemplateWithDef =
- getTemplateDefinition(FoundTemplate);
- if (D->isThisDeclarationADefinition() && TemplateWithDef) {
- return Importer.MapImported(D, TemplateWithDef);
- }
- FoundByLookup = FoundTemplate;
- break;
- }
+ if (!hasSameVisibilityContext(FoundTemplate, D))
+ continue;
+ if (IsStructuralMatch(D, FoundTemplate)) {
+ FunctionTemplateDecl *TemplateWithDef =
+ getTemplateDefinition(FoundTemplate);
+ if (D->isThisDeclarationADefinition() && TemplateWithDef)
+ return Importer.MapImported(D, TemplateWithDef);
+
+ FoundByLookup = FoundTemplate;
+ break;
// TODO: handle conflicting names
}
}
@@ -6227,7 +6478,8 @@ ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
TemplateArgumentListInfo *ToResInfo = nullptr;
if (E->hasExplicitTemplateArgs()) {
if (Error Err =
- ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo))
+ ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(),
+ E->template_arguments(), ToTAInfo))
return std::move(Err);
ToResInfo = &ToTAInfo;
}
@@ -6868,8 +7120,23 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
if (!UsedContextOrErr)
return UsedContextOrErr.takeError();
- return CXXDefaultArgExpr::Create(
- Importer.getToContext(), *ToUsedLocOrErr, *ToParamOrErr, *UsedContextOrErr);
+ // Import the default arg if it was not imported yet.
+ // This is needed because it can happen that during the import of the
+ // default expression (from VisitParmVarDecl) the same ParmVarDecl is
+ // encountered here. The default argument for a ParmVarDecl is set in the
+ // ParmVarDecl only after it is imported (set in VisitParmVarDecl if not here,
+ // see VisitParmVarDecl).
+ ParmVarDecl *ToParam = *ToParamOrErr;
+ if (!ToParam->getDefaultArg()) {
+ Optional<ParmVarDecl *> FromParam = Importer.getImportedFromDecl(ToParam);
+ assert(FromParam && "ParmVarDecl was not imported?");
+
+ if (Error Err = ImportDefaultArgOfParmVarDecl(*FromParam, ToParam))
+ return std::move(Err);
+ }
+
+ return CXXDefaultArgExpr::Create(Importer.getToContext(), *ToUsedLocOrErr,
+ *ToParamOrErr, *UsedContextOrErr);
}
ExpectedStmt
@@ -6928,23 +7195,52 @@ ASTNodeImporter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
E->requiresZeroInitialization());
}
+ExpectedDecl ASTNodeImporter::VisitLifetimeExtendedTemporaryDecl(
+ LifetimeExtendedTemporaryDecl *D) {
+ DeclContext *DC, *LexicalDC;
+ if (Error Err = ImportDeclContext(D, DC, LexicalDC))
+ return std::move(Err);
+
+ auto Imp = importSeq(D->getTemporaryExpr(), D->getExtendingDecl());
+ // FIXME: the APValue should be imported as well if present.
+ if (!Imp)
+ return Imp.takeError();
+
+ Expr *Temporary;
+ ValueDecl *ExtendingDecl;
+ std::tie(Temporary, ExtendingDecl) = *Imp;
+ // FIXME: Should ManglingNumber get numbers associated with 'to' context?
+
+ LifetimeExtendedTemporaryDecl *To;
+ if (GetImportedOrCreateDecl(To, D, Temporary, ExtendingDecl,
+ D->getManglingNumber()))
+ return To;
+
+ To->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(To);
+ return To;
+}
+
ExpectedStmt
ASTNodeImporter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
- auto Imp = importSeq(
- E->getType(), E->GetTemporaryExpr(), E->getExtendingDecl());
+ auto Imp = importSeq(E->getType(),
+ E->getLifetimeExtendedTemporaryDecl() ? nullptr
+ : E->getSubExpr(),
+ E->getLifetimeExtendedTemporaryDecl());
if (!Imp)
return Imp.takeError();
QualType ToType;
Expr *ToTemporaryExpr;
- const ValueDecl *ToExtendingDecl;
- std::tie(ToType, ToTemporaryExpr, ToExtendingDecl) = *Imp;
+ LifetimeExtendedTemporaryDecl *ToMaterializedDecl;
+ std::tie(ToType, ToTemporaryExpr, ToMaterializedDecl) = *Imp;
+ if (!ToTemporaryExpr)
+ ToTemporaryExpr = cast<Expr>(ToMaterializedDecl->getTemporaryExpr());
- auto *ToMTE = new (Importer.getToContext()) MaterializeTemporaryExpr(
- ToType, ToTemporaryExpr, E->isBoundToLvalueReference());
+ auto *ToMTE = new (Importer.getToContext()) MaterializeTemporaryExpr(
+ ToType, ToTemporaryExpr, E->isBoundToLvalueReference(),
+ ToMaterializedDecl);
- // FIXME: Should ManglingNumber get numbers associated with 'to' context?
- ToMTE->setExtendingDecl(ToExtendingDecl, E->getManglingNumber());
return ToMTE;
}
@@ -7259,20 +7555,19 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr(
ExpectedStmt
ASTNodeImporter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
- auto Imp = importSeq(
- E->getQualifierLoc(), E->getTemplateKeywordLoc(), E->getDeclName(),
- E->getExprLoc(), E->getLAngleLoc(), E->getRAngleLoc());
+ auto Imp = importSeq(E->getQualifierLoc(), E->getTemplateKeywordLoc(),
+ E->getDeclName(), E->getNameInfo().getLoc(),
+ E->getLAngleLoc(), E->getRAngleLoc());
if (!Imp)
return Imp.takeError();
NestedNameSpecifierLoc ToQualifierLoc;
- SourceLocation ToTemplateKeywordLoc, ToExprLoc, ToLAngleLoc, ToRAngleLoc;
+ SourceLocation ToTemplateKeywordLoc, ToNameLoc, ToLAngleLoc, ToRAngleLoc;
DeclarationName ToDeclName;
- std::tie(
- ToQualifierLoc, ToTemplateKeywordLoc, ToDeclName, ToExprLoc,
- ToLAngleLoc, ToRAngleLoc) = *Imp;
+ std::tie(ToQualifierLoc, ToTemplateKeywordLoc, ToDeclName, ToNameLoc,
+ ToLAngleLoc, ToRAngleLoc) = *Imp;
- DeclarationNameInfo ToNameInfo(ToDeclName, ToExprLoc);
+ DeclarationNameInfo ToNameInfo(ToDeclName, ToNameLoc);
if (Error Err = ImportDeclarationNameLoc(E->getNameInfo(), ToNameInfo))
return std::move(Err);
@@ -7337,7 +7632,7 @@ ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
else
return ToDOrErr.takeError();
- if (E->hasExplicitTemplateArgs() && E->getTemplateKeywordLoc().isValid()) {
+ if (E->hasExplicitTemplateArgs()) {
TemplateArgumentListInfo ToTAInfo;
if (Error Err = ImportTemplateArgumentListInfo(
E->getLAngleLoc(), E->getRAngleLoc(), E->template_arguments(),
@@ -7391,8 +7686,9 @@ ASTNodeImporter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
TemplateArgumentListInfo ToTAInfo;
TemplateArgumentListInfo *ResInfo = nullptr;
if (E->hasExplicitTemplateArgs()) {
- if (Error Err =
- ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo))
+ TemplateArgumentListInfo FromTAInfo;
+ E->copyTemplateArgumentsInto(FromTAInfo);
+ if (Error Err = ImportTemplateArgumentListInfo(FromTAInfo, ToTAInfo))
return std::move(Err);
ResInfo = &ToTAInfo;
}
@@ -7701,15 +7997,18 @@ ExpectedStmt ASTNodeImporter::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
*ToTypeOrErr, *ToExprOperandOrErr, *ToSourceRangeOrErr);
}
-void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod,
- CXXMethodDecl *FromMethod) {
+Error ASTNodeImporter::ImportOverriddenMethods(CXXMethodDecl *ToMethod,
+ CXXMethodDecl *FromMethod) {
+ Error ImportErrors = Error::success();
for (auto *FromOverriddenMethod : FromMethod->overridden_methods()) {
if (auto ImportedOrErr = import(FromOverriddenMethod))
ToMethod->getCanonicalDecl()->addOverriddenMethod(cast<CXXMethodDecl>(
(*ImportedOrErr)->getCanonicalDecl()));
else
- consumeError(ImportedOrErr.takeError());
+ ImportErrors =
+ joinErrors(std::move(ImportErrors), ImportedOrErr.takeError());
}
+ return ImportErrors;
}
ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
@@ -7718,7 +8017,7 @@ ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
std::shared_ptr<ASTImporterSharedState> SharedState)
: SharedState(SharedState), ToContext(ToContext), FromContext(FromContext),
ToFileManager(ToFileManager), FromFileManager(FromFileManager),
- Minimal(MinimalImport) {
+ Minimal(MinimalImport), ODRHandling(ODRHandlingType::Conservative) {
// Create a default state without the lookup table: LLDB case.
if (!SharedState) {
@@ -8202,8 +8501,14 @@ ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
return std::move(Err);
TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo(
QualType(Spec->getAsType(), 0), ToTLoc);
- Builder.Extend(getToContext(), ToLocalBeginLoc, TSI->getTypeLoc(),
- ToLocalEndLoc);
+ if (Kind == NestedNameSpecifier::TypeSpecWithTemplate)
+ // ToLocalBeginLoc is here the location of the 'template' keyword.
+ Builder.Extend(getToContext(), ToLocalBeginLoc, TSI->getTypeLoc(),
+ ToLocalEndLoc);
+ else
+ // No location for 'template' keyword here.
+ Builder.Extend(getToContext(), SourceLocation{}, TSI->getTypeLoc(),
+ ToLocalEndLoc);
break;
}
@@ -8390,13 +8695,13 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
// disk again
// FIXME: We definitely want to re-use the existing MemoryBuffer, rather
// than mmap the files several times.
- const FileEntry *Entry =
+ auto Entry =
ToFileManager.getFile(Cache->OrigEntry->getName());
// FIXME: The filename may be a virtual name that does probably not
// point to a valid file and we get no Entry here. In this case try with
// the memory buffer below.
if (Entry)
- ToID = ToSM.createFileID(Entry, *ToIncludeLoc,
+ ToID = ToSM.createFileID(*Entry, *ToIncludeLoc,
FromSLoc.getFile().getFileCharacteristic());
}
}
@@ -8404,8 +8709,9 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
if (ToID.isInvalid() || IsBuiltin) {
// FIXME: We want to re-use the existing MemoryBuffer!
bool Invalid = true;
- const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(
- FromContext.getDiagnostics(), FromSM, SourceLocation{}, &Invalid);
+ const llvm::MemoryBuffer *FromBuf =
+ Cache->getBuffer(FromContext.getDiagnostics(),
+ FromSM.getFileManager(), SourceLocation{}, &Invalid);
if (!FromBuf || Invalid)
// FIXME: Use a new error kind?
return llvm::make_error<ImportError>(ImportError::Unknown);
@@ -8421,6 +8727,10 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
assert(ToID.isValid() && "Unexpected invalid fileID was created.");
ImportedFileIDs[FromID] = ToID;
+
+ if (FileIDImportHandler)
+ FileIDImportHandler(ToID, FromID);
+
return ToID;
}
@@ -8640,12 +8950,17 @@ Expected<Selector> ASTImporter::Import(Selector FromSel) {
return ToContext.Selectors.getSelector(FromSel.getNumArgs(), Idents.data());
}
-DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name,
- DeclContext *DC,
- unsigned IDNS,
- NamedDecl **Decls,
- unsigned NumDecls) {
- return Name;
+Expected<DeclarationName> ASTImporter::HandleNameConflict(DeclarationName Name,
+ DeclContext *DC,
+ unsigned IDNS,
+ NamedDecl **Decls,
+ unsigned NumDecls) {
+ if (ODRHandling == ODRHandlingType::Conservative)
+ // Report error at any name conflict.
+ return make_error<ImportError>(ImportError::NameConflict);
+ else
+ // Allow to create the new Decl with the same name.
+ return Name;
}
DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) {
diff --git a/contrib/llvm-project/clang/lib/AST/ASTStructuralEquivalence.cpp b/contrib/llvm-project/clang/lib/AST/ASTStructuralEquivalence.cpp
index 912db3c130c5..91a2f3a8391b 100644
--- a/contrib/llvm-project/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -235,12 +235,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const TemplateName &N1,
const TemplateName &N2) {
- if (N1.getKind() != N2.getKind())
+ TemplateDecl *TemplateDeclN1 = N1.getAsTemplateDecl();
+ TemplateDecl *TemplateDeclN2 = N2.getAsTemplateDecl();
+ if (TemplateDeclN1 && TemplateDeclN2) {
+ if (!IsStructurallyEquivalent(Context, TemplateDeclN1, TemplateDeclN2))
+ return false;
+ // If the kind is different we compare only the template decl.
+ if (N1.getKind() != N2.getKind())
+ return true;
+ } else if (TemplateDeclN1 || TemplateDeclN2)
+ return false;
+ else if (N1.getKind() != N2.getKind())
return false;
+
+ // Check for special case incompatibilities.
switch (N1.getKind()) {
- case TemplateName::Template:
- return IsStructurallyEquivalent(Context, N1.getAsTemplateDecl(),
- N2.getAsTemplateDecl());
case TemplateName::OverloadedTemplate: {
OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(),
@@ -259,14 +268,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return TN1->getDeclName() == TN2->getDeclName();
}
- case TemplateName::QualifiedTemplate: {
- QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(),
- *QN2 = N2.getAsQualifiedTemplateName();
- return IsStructurallyEquivalent(Context, QN1->getDecl(), QN2->getDecl()) &&
- IsStructurallyEquivalent(Context, QN1->getQualifier(),
- QN2->getQualifier());
- }
-
case TemplateName::DependentTemplate: {
DependentTemplateName *DN1 = N1.getAsDependentTemplateName(),
*DN2 = N2.getAsDependentTemplateName();
@@ -281,15 +282,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
}
- case TemplateName::SubstTemplateTemplateParm: {
- SubstTemplateTemplateParmStorage *TS1 = N1.getAsSubstTemplateTemplateParm(),
- *TS2 = N2.getAsSubstTemplateTemplateParm();
- return IsStructurallyEquivalent(Context, TS1->getParameter(),
- TS2->getParameter()) &&
- IsStructurallyEquivalent(Context, TS1->getReplacement(),
- TS2->getReplacement());
- }
-
case TemplateName::SubstTemplateTemplateParmPack: {
SubstTemplateTemplateParmPackStorage
*P1 = N1.getAsSubstTemplateTemplateParmPack(),
@@ -299,8 +291,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
IsStructurallyEquivalent(Context, P1->getParameterPack(),
P2->getParameterPack());
}
+
+ case TemplateName::Template:
+ case TemplateName::QualifiedTemplate:
+ case TemplateName::SubstTemplateTemplateParm:
+ // It is sufficient to check value of getAsTemplateDecl.
+ break;
+
}
- return false;
+
+ return true;
}
/// Determine whether two template arguments are equivalent.
@@ -729,11 +729,31 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
- case Type::Auto:
- if (!IsStructurallyEquivalent(Context, cast<AutoType>(T1)->getDeducedType(),
- cast<AutoType>(T2)->getDeducedType()))
+ case Type::Auto: {
+ auto *Auto1 = cast<AutoType>(T1);
+ auto *Auto2 = cast<AutoType>(T2);
+ if (!IsStructurallyEquivalent(Context, Auto1->getDeducedType(),
+ Auto2->getDeducedType()))
+ return false;
+ if (Auto1->isConstrained() != Auto2->isConstrained())
return false;
+ if (Auto1->isConstrained()) {
+ if (Auto1->getTypeConstraintConcept() !=
+ Auto2->getTypeConstraintConcept())
+ return false;
+ ArrayRef<TemplateArgument> Auto1Args =
+ Auto1->getTypeConstraintArguments();
+ ArrayRef<TemplateArgument> Auto2Args =
+ Auto2->getTypeConstraintArguments();
+ if (Auto1Args.size() != Auto2Args.size())
+ return false;
+ for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I]))
+ return false;
+ }
+ }
break;
+ }
case Type::DeducedTemplateSpecialization: {
const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
@@ -1574,20 +1594,24 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Decl *D1, Decl *D2) {
// FIXME: Check for known structural equivalences via a callback of some sort.
+ D1 = D1->getCanonicalDecl();
+ D2 = D2->getCanonicalDecl();
+ std::pair<Decl *, Decl *> P{D1, D2};
+
// Check whether we already know that these two declarations are not
// structurally equivalent.
- if (Context.NonEquivalentDecls.count(
- std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl())))
+ if (Context.NonEquivalentDecls.count(P))
return false;
- // Determine whether we've already produced a tentative equivalence for D1.
- Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()];
- if (EquivToD1)
- return EquivToD1 == D2->getCanonicalDecl();
+ // Check if a check for these declarations is already pending.
+ // If yes D1 and D2 will be checked later (from DeclsToCheck),
+ // or these are already checked (and equivalent).
+ bool Inserted = Context.VisitedDecls.insert(P).second;
+ if (!Inserted)
+ return true;
+
+ Context.DeclsToCheck.push(P);
- // Produce a tentative equivalence D1 <-> D2, which will be checked later.
- EquivToD1 = D2->getCanonicalDecl();
- Context.DeclsToCheck.push_back(D1->getCanonicalDecl());
return true;
}
@@ -1703,11 +1727,13 @@ bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {
// Ensure that the implementation functions (all static functions in this TU)
// never call the public ASTStructuralEquivalence::IsEquivalent() functions,
// because that will wreak havoc the internal state (DeclsToCheck and
- // TentativeEquivalences members) and can cause faulty behaviour. For
- // instance, some leaf declarations can be stated and cached as inequivalent
- // as a side effect of one inequivalent element in the DeclsToCheck list.
+ // VisitedDecls members) and can cause faulty behaviour.
+ // In other words: Do not start a graph search from a new node with the
+ // internal data of another search in progress.
+ // FIXME: Better encapsulation and separation of internal and public
+ // functionality.
assert(DeclsToCheck.empty());
- assert(TentativeEquivalences.empty());
+ assert(VisitedDecls.empty());
if (!::IsStructurallyEquivalent(*this, D1, D2))
return false;
@@ -1717,7 +1743,7 @@ bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {
bool StructuralEquivalenceContext::IsEquivalent(QualType T1, QualType T2) {
assert(DeclsToCheck.empty());
- assert(TentativeEquivalences.empty());
+ assert(VisitedDecls.empty());
if (!::IsStructurallyEquivalent(*this, T1, T2))
return false;
@@ -1876,11 +1902,11 @@ bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
bool StructuralEquivalenceContext::Finish() {
while (!DeclsToCheck.empty()) {
// Check the next declaration.
- Decl *D1 = DeclsToCheck.front();
- DeclsToCheck.pop_front();
+ std::pair<Decl *, Decl *> P = DeclsToCheck.front();
+ DeclsToCheck.pop();
- Decl *D2 = TentativeEquivalences[D1];
- assert(D2 && "Unrecorded tentative equivalence?");
+ Decl *D1 = P.first;
+ Decl *D2 = P.second;
bool Equivalent =
CheckCommonEquivalence(D1, D2) && CheckKindSpecificEquivalence(D1, D2);
@@ -1888,8 +1914,8 @@ bool StructuralEquivalenceContext::Finish() {
if (!Equivalent) {
// Note that these two declarations are not equivalent (and we already
// know about it).
- NonEquivalentDecls.insert(
- std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl()));
+ NonEquivalentDecls.insert(P);
+
return true;
}
}
diff --git a/contrib/llvm-project/clang/lib/AST/ASTTypeTraits.cpp b/contrib/llvm-project/clang/lib/AST/ASTTypeTraits.cpp
index ba1581bd3f6b..a5570c329ae8 100644
--- a/contrib/llvm-project/clang/lib/AST/ASTTypeTraits.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ASTTypeTraits.cpp
@@ -15,6 +15,8 @@
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/OpenMPClause.h"
namespace clang {
namespace ast_type_traits {
@@ -36,7 +38,7 @@ const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
#include "clang/AST/StmtNodes.inc"
{ NKI_None, "Type" },
#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" },
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
{ NKI_None, "OMPClause" },
#define OPENMP_CLAUSE(TextualSpelling, Class) {NKI_OMPClause, #Class},
#include "clang/Basic/OpenMPKinds.def"
@@ -103,7 +105,7 @@ ASTNodeKind ASTNodeKind::getFromNode(const Type &T) {
#define TYPE(Class, Base) \
case Type::Class: return ASTNodeKind(NKI_##Class##Type);
#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
llvm_unreachable("invalid type kind");
}
@@ -115,6 +117,8 @@ ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) {
#include "clang/Basic/OpenMPKinds.def"
case OMPC_threadprivate:
case OMPC_uniform:
+ case OMPC_device_type:
+ case OMPC_match:
case OMPC_unknown:
llvm_unreachable("unexpected OpenMP clause kind");
}
@@ -129,9 +133,12 @@ void DynTypedNode::print(llvm::raw_ostream &OS,
TN->print(OS, PP);
else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>())
NNS->print(OS, PP);
- else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
- NNSL->getNestedNameSpecifier()->print(OS, PP);
- else if (const QualType *QT = get<QualType>())
+ else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) {
+ if (const NestedNameSpecifier *NNS = NNSL->getNestedNameSpecifier())
+ NNS->print(OS, PP);
+ else
+ OS << "(empty NestedNameSpecifierLoc)";
+ } else if (const QualType *QT = get<QualType>())
QT->print(OS, PP);
else if (const TypeLoc *TL = get<TypeLoc>())
TL->getType().print(OS, PP);
diff --git a/contrib/llvm-project/clang/lib/AST/CXXInheritance.cpp b/contrib/llvm-project/clang/lib/AST/CXXInheritance.cpp
index ecf451b175af..0377bd324cb6 100644
--- a/contrib/llvm-project/clang/lib/AST/CXXInheritance.cpp
+++ b/contrib/llvm-project/clang/lib/AST/CXXInheritance.cpp
@@ -44,7 +44,7 @@ void CXXBasePaths::ComputeDeclsFound() {
Decls.insert(Path->Decls.front());
NumDeclsFound = Decls.size();
- DeclsFound = llvm::make_unique<NamedDecl *[]>(NumDeclsFound);
+ DeclsFound = std::make_unique<NamedDecl *[]>(NumDeclsFound);
std::copy(Decls.begin(), Decls.end(), DeclsFound.get());
}
@@ -758,6 +758,8 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
return false;
};
+ // FIXME: IsHidden reads from Overriding from the middle of a remove_if
+ // over the same sequence! Is this guaranteed to work?
Overriding.erase(
std::remove_if(Overriding.begin(), Overriding.end(), IsHidden),
Overriding.end());
diff --git a/contrib/llvm-project/clang/lib/AST/Comment.cpp b/contrib/llvm-project/clang/lib/AST/Comment.cpp
index 25339c7901e3..a02cc9d119fe 100644
--- a/contrib/llvm-project/clang/lib/AST/Comment.cpp
+++ b/contrib/llvm-project/clang/lib/AST/Comment.cpp
@@ -13,10 +13,25 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/CharInfo.h"
#include "llvm/Support/ErrorHandling.h"
+#include <type_traits>
namespace clang {
namespace comments {
+// Check that no comment class has a non-trival destructor. They are allocated
+// with a BumpPtrAllocator and therefore their destructor is not executed.
+#define ABSTRACT_COMMENT(COMMENT)
+#define COMMENT(CLASS, PARENT) \
+ static_assert(std::is_trivially_destructible<CLASS>::value, \
+ #CLASS " should be trivially destructible!");
+#include "clang/AST/CommentNodes.inc"
+#undef COMMENT
+#undef ABSTRACT_COMMENT
+
+// DeclInfo is also allocated with a BumpPtrAllocator.
+static_assert(std::is_trivially_destructible<DeclInfo>::value,
+ "DeclInfo should be trivially destructible!");
+
const char *Comment::getCommentKindName() const {
switch (getCommentKind()) {
case NoCommentKind: return "NoCommentKind";
@@ -364,11 +379,11 @@ StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
assert(isPositionValid());
const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
for (unsigned i = 0, e = getDepth(); i != e; ++i) {
- if (i == e-1)
+ assert(TPL && "Unknown TemplateParameterList");
+ if (i == e - 1)
return TPL->getParam(getIndex(i))->getName();
const NamedDecl *Param = TPL->getParam(getIndex(i));
- if (const TemplateTemplateParmDecl *TTP =
- dyn_cast<TemplateTemplateParmDecl>(Param))
+ if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param))
TPL = TTP->getTemplateParameters();
}
return "";
diff --git a/contrib/llvm-project/clang/lib/AST/CommentLexer.cpp b/contrib/llvm-project/clang/lib/AST/CommentLexer.cpp
index 19485f6018c0..c1ea3eab075e 100644
--- a/contrib/llvm-project/clang/lib/AST/CommentLexer.cpp
+++ b/contrib/llvm-project/clang/lib/AST/CommentLexer.cpp
@@ -850,17 +850,14 @@ again:
}
StringRef Lexer::getSpelling(const Token &Tok,
- const SourceManager &SourceMgr,
- bool *Invalid) const {
+ const SourceManager &SourceMgr) const {
SourceLocation Loc = Tok.getLocation();
std::pair<FileID, unsigned> LocInfo = SourceMgr.getDecomposedLoc(Loc);
bool InvalidTemp = false;
StringRef File = SourceMgr.getBufferData(LocInfo.first, &InvalidTemp);
- if (InvalidTemp) {
- *Invalid = true;
+ if (InvalidTemp)
return StringRef();
- }
const char *Begin = File.data() + LocInfo.second;
return StringRef(Begin, Tok.getLength());
diff --git a/contrib/llvm-project/clang/lib/AST/CommentParser.cpp b/contrib/llvm-project/clang/lib/AST/CommentParser.cpp
index c7f8aa7e16a0..29983b0a16c3 100644
--- a/contrib/llvm-project/clang/lib/AST/CommentParser.cpp
+++ b/contrib/llvm-project/clang/lib/AST/CommentParser.cpp
@@ -422,6 +422,12 @@ InlineCommandComment *Parser::parseInlineCommand() {
IC = S.actOnInlineCommand(CommandTok.getLocation(),
CommandTok.getEndLocation(),
CommandTok.getCommandID());
+
+ Diag(CommandTok.getEndLocation().getLocWithOffset(1),
+ diag::warn_doc_inline_contents_no_argument)
+ << CommandTok.is(tok::at_command)
+ << Traits.getCommandInfo(CommandTok.getCommandID())->Name
+ << SourceRange(CommandTok.getLocation(), CommandTok.getEndLocation());
}
Retokenizer.putBackLeftoverTokens();
diff --git a/contrib/llvm-project/clang/lib/AST/CommentSema.cpp b/contrib/llvm-project/clang/lib/AST/CommentSema.cpp
index 067b3ae4222e..53c1832d1dd2 100644
--- a/contrib/llvm-project/clang/lib/AST/CommentSema.cpp
+++ b/contrib/llvm-project/clang/lib/AST/CommentSema.cpp
@@ -588,6 +588,8 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
if (isObjCPropertyDecl())
return;
if (isFunctionDecl() || isFunctionOrBlockPointerVarLikeDecl()) {
+ assert(!ThisDeclInfo->ReturnType.isNull() &&
+ "should have a valid return type");
if (ThisDeclInfo->ReturnType->isVoidType()) {
unsigned DiagKind;
switch (ThisDeclInfo->CommentDecl->getKind()) {
@@ -674,9 +676,8 @@ void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
D->hasAttr<UnavailableAttr>())
return;
- Diag(Command->getLocation(),
- diag::warn_doc_deprecated_not_sync)
- << Command->getSourceRange();
+ Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync)
+ << Command->getSourceRange() << Command->getCommandMarker();
// Try to emit a fixit with a deprecation attribute.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
@@ -687,24 +688,41 @@ void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
FD->doesThisDeclarationHaveABody())
return;
- StringRef AttributeSpelling = "__attribute__((deprecated))";
+ const LangOptions &LO = FD->getASTContext().getLangOpts();
+ const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C2x;
+ StringRef AttributeSpelling =
+ DoubleSquareBracket ? "[[deprecated]]" : "__attribute__((deprecated))";
if (PP) {
- TokenValue Tokens[] = {
- tok::kw___attribute, tok::l_paren, tok::l_paren,
- PP->getIdentifierInfo("deprecated"),
- tok::r_paren, tok::r_paren
- };
- StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
- Tokens);
- if (!MacroName.empty())
- AttributeSpelling = MacroName;
+ // Try to find a replacement macro:
+ // - In C2x/C++14 we prefer [[deprecated]].
+ // - If not found or an older C/C++ look for __attribute__((deprecated)).
+ StringRef MacroName;
+ if (DoubleSquareBracket) {
+ TokenValue Tokens[] = {tok::l_square, tok::l_square,
+ PP->getIdentifierInfo("deprecated"),
+ tok::r_square, tok::r_square};
+ MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
+ if (!MacroName.empty())
+ AttributeSpelling = MacroName;
+ }
+
+ if (MacroName.empty()) {
+ TokenValue Tokens[] = {
+ tok::kw___attribute, tok::l_paren,
+ tok::l_paren, PP->getIdentifierInfo("deprecated"),
+ tok::r_paren, tok::r_paren};
+ StringRef MacroName =
+ PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
+ if (!MacroName.empty())
+ AttributeSpelling = MacroName;
+ }
}
- SmallString<64> TextToInsert(" ");
- TextToInsert += AttributeSpelling;
- Diag(FD->getEndLoc(), diag::note_add_deprecation_attr)
- << FixItHint::CreateInsertion(FD->getEndLoc().getLocWithOffset(1),
- TextToInsert);
+ SmallString<64> TextToInsert = AttributeSpelling;
+ TextToInsert += " ";
+ SourceLocation Loc = FD->getSourceRange().getBegin();
+ Diag(Loc, diag::note_add_deprecation_attr)
+ << FixItHint::CreateInsertion(Loc, TextToInsert);
}
}
@@ -873,6 +891,12 @@ bool Sema::isFunctionOrBlockPointerVarLikeDecl() {
// can be ignored.
if (QT->getAs<TypedefType>())
return false;
+ if (const auto *P = QT->getAs<PointerType>())
+ if (P->getPointeeType()->getAs<TypedefType>())
+ return false;
+ if (const auto *P = QT->getAs<BlockPointerType>())
+ if (P->getPointeeType()->getAs<TypedefType>())
+ return false;
return QT->isFunctionPointerType() || QT->isBlockPointerType();
}
@@ -1119,6 +1143,7 @@ Sema::getInlineCommandRenderKind(StringRef Name) const {
.Case("b", InlineCommandComment::RenderBold)
.Cases("c", "p", InlineCommandComment::RenderMonospaced)
.Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
+ .Case("anchor", InlineCommandComment::RenderAnchor)
.Default(InlineCommandComment::RenderNormal);
}
diff --git a/contrib/llvm-project/clang/lib/AST/ComparisonCategories.cpp b/contrib/llvm-project/clang/lib/AST/ComparisonCategories.cpp
index ee4c1b0443a3..07673230357f 100644
--- a/contrib/llvm-project/clang/lib/AST/ComparisonCategories.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ComparisonCategories.cpp
@@ -19,6 +19,26 @@
using namespace clang;
+Optional<ComparisonCategoryType>
+clang::getComparisonCategoryForBuiltinCmp(QualType T) {
+ using CCT = ComparisonCategoryType;
+
+ if (T->isIntegralOrEnumerationType())
+ return CCT::StrongOrdering;
+
+ if (T->isRealFloatingType())
+ return CCT::PartialOrdering;
+
+ // C++2a [expr.spaceship]p8: If the composite pointer type is an object
+ // pointer type, p <=> q is of type std::strong_ordering.
+ // Note: this assumes neither operand is a null pointer constant.
+ if (T->isObjectPointerType())
+ return CCT::StrongOrdering;
+
+ // TODO: Extend support for operator<=> to ObjC types.
+ return llvm::None;
+}
+
bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
assert(VD && "must have var decl");
if (!VD->checkInitIsICE())
@@ -59,7 +79,7 @@ ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
// a new entry representing it.
DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup(
&Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
- if (Lookup.size() != 1 || !isa<VarDecl>(Lookup.front()))
+ if (Lookup.empty() || !isa<VarDecl>(Lookup.front()))
return nullptr;
Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
return &Objects.back();
@@ -70,7 +90,7 @@ static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
if (!StdNS) {
DeclContextLookupResult Lookup =
Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
- if (Lookup.size() == 1)
+ if (!Lookup.empty())
StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
}
return StdNS;
@@ -81,7 +101,7 @@ static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
ComparisonCategoryType Kind) {
StringRef Name = ComparisonCategories::getCategoryString(Kind);
DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
- if (Lookup.size() == 1)
+ if (!Lookup.empty())
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
return RD;
return nullptr;
@@ -150,10 +170,6 @@ QualType ComparisonCategoryInfo::getType() const {
StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) {
using CCKT = ComparisonCategoryType;
switch (Kind) {
- case CCKT::WeakEquality:
- return "weak_equality";
- case CCKT::StrongEquality:
- return "strong_equality";
case CCKT::PartialOrdering:
return "partial_ordering";
case CCKT::WeakOrdering:
@@ -169,12 +185,8 @@ StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) {
switch (Kind) {
case CCVT::Equal:
return "equal";
- case CCVT::Nonequal:
- return "nonequal";
case CCVT::Equivalent:
return "equivalent";
- case CCVT::Nonequivalent:
- return "nonequivalent";
case CCVT::Less:
return "less";
case CCVT::Greater:
@@ -190,20 +202,11 @@ ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) {
using CCT = ComparisonCategoryType;
using CCR = ComparisonCategoryResult;
std::vector<CCR> Values;
- Values.reserve(6);
- Values.push_back(CCR::Equivalent);
- bool IsStrong = (Type == CCT::StrongEquality || Type == CCT::StrongOrdering);
- if (IsStrong)
- Values.push_back(CCR::Equal);
- if (Type == CCT::StrongOrdering || Type == CCT::WeakOrdering ||
- Type == CCT::PartialOrdering) {
- Values.push_back(CCR::Less);
- Values.push_back(CCR::Greater);
- } else {
- Values.push_back(CCR::Nonequivalent);
- if (IsStrong)
- Values.push_back(CCR::Nonequal);
- }
+ Values.reserve(4);
+ bool IsStrong = Type == CCT::StrongOrdering;
+ Values.push_back(IsStrong ? CCR::Equal : CCR::Equivalent);
+ Values.push_back(CCR::Less);
+ Values.push_back(CCR::Greater);
if (Type == CCT::PartialOrdering)
Values.push_back(CCR::Unordered);
return Values;
diff --git a/contrib/llvm-project/clang/lib/AST/Decl.cpp b/contrib/llvm-project/clang/lib/AST/Decl.cpp
index aa74da006174..0d30f64b992e 100644
--- a/contrib/llvm-project/clang/lib/AST/Decl.cpp
+++ b/contrib/llvm-project/clang/lib/AST/Decl.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CanonicalType.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
@@ -55,8 +56,8 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
@@ -901,6 +902,10 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
if (!isExternallyVisible(LV.getLinkage()))
return LinkageInfo(LV.getLinkage(), DefaultVisibility, false);
+ // Mark the symbols as hidden when compiling for the device.
+ if (Context.getLangOpts().OpenMP && Context.getLangOpts().OpenMPIsDevice)
+ LV.mergeVisibility(HiddenVisibility, /*newExplicit=*/false);
+
return LV;
}
@@ -1385,7 +1390,8 @@ LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D,
case Decl::CXXRecord: {
const auto *Record = cast<CXXRecordDecl>(D);
if (Record->isLambda()) {
- if (!Record->getLambdaManglingNumber()) {
+ if (Record->hasKnownLambdaInternalLinkage() ||
+ !Record->getLambdaManglingNumber()) {
// This lambda has no mangling number, so it's internal.
return getInternalLinkageFor(D);
}
@@ -1402,7 +1408,8 @@ LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D,
// };
const CXXRecordDecl *OuterMostLambda =
getOutermostEnclosingLambda(Record);
- if (!OuterMostLambda->getLambdaManglingNumber())
+ if (OuterMostLambda->hasKnownLambdaInternalLinkage() ||
+ !OuterMostLambda->getLambdaManglingNumber())
return getInternalLinkageFor(D);
return getLVForClosure(
@@ -1558,6 +1565,24 @@ void NamedDecl::printQualifiedName(raw_ostream &OS) const {
void NamedDecl::printQualifiedName(raw_ostream &OS,
const PrintingPolicy &P) const {
+ if (getDeclContext()->isFunctionOrMethod()) {
+ // We do not print '(anonymous)' for function parameters without name.
+ printName(OS);
+ return;
+ }
+ printNestedNameSpecifier(OS, P);
+ if (getDeclName() || isa<DecompositionDecl>(this))
+ OS << *this;
+ else
+ OS << "(anonymous)";
+}
+
+void NamedDecl::printNestedNameSpecifier(raw_ostream &OS) const {
+ printNestedNameSpecifier(OS, getASTContext().getPrintingPolicy());
+}
+
+void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
+ const PrintingPolicy &P) const {
const DeclContext *Ctx = getDeclContext();
// For ObjC methods and properties, look through categories and use the
@@ -1571,10 +1596,8 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
Ctx = ID;
}
- if (Ctx->isFunctionOrMethod()) {
- printName(OS);
+ if (Ctx->isFunctionOrMethod())
return;
- }
using ContextsTy = SmallVector<const DeclContext *, 8>;
ContextsTy Contexts;
@@ -1644,11 +1667,6 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
}
OS << "::";
}
-
- if (getDeclName() || isa<DecompositionDecl>(this))
- OS << *this;
- else
- OS << "(anonymous)";
}
void NamedDecl::getNameForDiagnostic(raw_ostream &OS,
@@ -1802,6 +1820,12 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
return SourceLocation();
}
+SourceLocation DeclaratorDecl::getTypeSpecEndLoc() const {
+ TypeSourceInfo *TSI = getTypeSourceInfo();
+ if (TSI) return TSI->getTypeLoc().getEndLoc();
+ return SourceLocation();
+}
+
void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
if (QualifierLoc) {
// Make sure the extended decl info is allocated.
@@ -1815,23 +1839,27 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
}
// Set qualifier info.
getExtInfo()->QualifierLoc = QualifierLoc;
- } else {
+ } else if (hasExtInfo()) {
// Here Qualifier == 0, i.e., we are removing the qualifier (if any).
- if (hasExtInfo()) {
- if (getExtInfo()->NumTemplParamLists == 0) {
- // Save type source info pointer.
- TypeSourceInfo *savedTInfo = getExtInfo()->TInfo;
- // Deallocate the extended decl info.
- getASTContext().Deallocate(getExtInfo());
- // Restore savedTInfo into (non-extended) decl info.
- DeclInfo = savedTInfo;
- }
- else
- getExtInfo()->QualifierLoc = QualifierLoc;
- }
+ getExtInfo()->QualifierLoc = QualifierLoc;
}
}
+void DeclaratorDecl::setTrailingRequiresClause(Expr *TrailingRequiresClause) {
+ assert(TrailingRequiresClause);
+ // Make sure the extended decl info is allocated.
+ if (!hasExtInfo()) {
+ // Save (non-extended) type source info pointer.
+ auto *savedTInfo = DeclInfo.get<TypeSourceInfo*>();
+ // Allocate external info struct.
+ DeclInfo = new (getASTContext()) ExtInfo;
+ // Restore savedTInfo into (extended) decl info.
+ getExtInfo()->TInfo = savedTInfo;
+ }
+ // Set requires clause info.
+ getExtInfo()->TrailingRequiresClause = TrailingRequiresClause;
+}
+
void DeclaratorDecl::setTemplateParameterListsInfo(
ASTContext &Context, ArrayRef<TemplateParameterList *> TPLists) {
assert(!TPLists.empty());
@@ -2220,6 +2248,22 @@ Stmt **VarDecl::getInitAddress() {
return Init.getAddrOfPtr1();
}
+VarDecl *VarDecl::getInitializingDeclaration() {
+ VarDecl *Def = nullptr;
+ for (auto I : redecls()) {
+ if (I->hasInit())
+ return I;
+
+ if (I->isThisDeclarationADefinition()) {
+ if (isStaticDataMember())
+ return I;
+ else
+ Def = I;
+ }
+ }
+ return Def;
+}
+
bool VarDecl::isOutOfLine() const {
if (Decl::isOutOfLine())
return true;
@@ -2565,6 +2609,18 @@ bool VarDecl::isNoDestroy(const ASTContext &Ctx) const {
!hasAttr<AlwaysDestroyAttr>()));
}
+QualType::DestructionKind
+VarDecl::needsDestruction(const ASTContext &Ctx) const {
+ if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
+ if (Eval->HasConstantDestruction)
+ return QualType::DK_none;
+
+ if (isNoDestroy(Ctx))
+ return QualType::DK_none;
+
+ return getType().isDestructedType();
+}
+
MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
if (isStaticDataMember())
// FIXME: Remove ?
@@ -2725,10 +2781,11 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, StorageClass S,
bool isInlineSpecified,
- ConstexprSpecKind ConstexprKind)
+ ConstexprSpecKind ConstexprKind,
+ Expr *TrailingRequiresClause)
: DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
StartLoc),
- DeclContext(DK), redeclarable_base(C), ODRHash(0),
+ DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0),
EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {
assert(T.isNull() || T->isFunctionType());
FunctionDeclBits.SClass = S;
@@ -2743,16 +2800,20 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
FunctionDeclBits.IsTrivialForCall = false;
FunctionDeclBits.IsDefaulted = false;
FunctionDeclBits.IsExplicitlyDefaulted = false;
+ FunctionDeclBits.HasDefaultedFunctionInfo = false;
FunctionDeclBits.HasImplicitReturnZero = false;
FunctionDeclBits.IsLateTemplateParsed = false;
FunctionDeclBits.ConstexprKind = ConstexprKind;
FunctionDeclBits.InstantiationIsPending = false;
FunctionDeclBits.UsesSEHTry = false;
+ FunctionDeclBits.UsesFPIntrin = false;
FunctionDeclBits.HasSkippedBody = false;
FunctionDeclBits.WillHaveBody = false;
FunctionDeclBits.IsMultiVersion = false;
FunctionDeclBits.IsCopyDeductionCandidate = false;
FunctionDeclBits.HasODRHash = false;
+ if (TrailingRequiresClause)
+ setTrailingRequiresClause(TrailingRequiresClause);
}
void FunctionDecl::getNameForDiagnostic(
@@ -2769,6 +2830,32 @@ bool FunctionDecl::isVariadic() const {
return false;
}
+FunctionDecl::DefaultedFunctionInfo *
+FunctionDecl::DefaultedFunctionInfo::Create(ASTContext &Context,
+ ArrayRef<DeclAccessPair> Lookups) {
+ DefaultedFunctionInfo *Info = new (Context.Allocate(
+ totalSizeToAlloc<DeclAccessPair>(Lookups.size()),
+ std::max(alignof(DefaultedFunctionInfo), alignof(DeclAccessPair))))
+ DefaultedFunctionInfo;
+ Info->NumLookups = Lookups.size();
+ std::uninitialized_copy(Lookups.begin(), Lookups.end(),
+ Info->getTrailingObjects<DeclAccessPair>());
+ return Info;
+}
+
+void FunctionDecl::setDefaultedFunctionInfo(DefaultedFunctionInfo *Info) {
+ assert(!FunctionDeclBits.HasDefaultedFunctionInfo && "already have this");
+ assert(!Body && "can't replace function body with defaulted function info");
+
+ FunctionDeclBits.HasDefaultedFunctionInfo = true;
+ DefaultedInfo = Info;
+}
+
+FunctionDecl::DefaultedFunctionInfo *
+FunctionDecl::getDefaultedFunctionInfo() const {
+ return FunctionDeclBits.HasDefaultedFunctionInfo ? DefaultedInfo : nullptr;
+}
+
bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
for (auto I : redecls()) {
if (I->doesThisDeclarationHaveABody()) {
@@ -2780,8 +2867,7 @@ bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
return false;
}
-bool FunctionDecl::hasTrivialBody() const
-{
+bool FunctionDecl::hasTrivialBody() const {
Stmt *S = getBody();
if (!S) {
// Since we don't have a body for this function, we don't know if it's
@@ -2809,6 +2895,8 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
if (!hasBody(Definition))
return nullptr;
+ assert(!Definition->FunctionDeclBits.HasDefaultedFunctionInfo &&
+ "definition should not have a body");
if (Definition->Body)
return Definition->Body.get(getASTContext().getExternalSource());
@@ -2816,7 +2904,8 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
}
void FunctionDecl::setBody(Stmt *B) {
- Body = B;
+ FunctionDeclBits.HasDefaultedFunctionInfo = false;
+ Body = LazyDeclStmtPtr(B);
if (B)
EndRangeLoc = B->getEndLoc();
}
@@ -2950,14 +3039,21 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const
Ty = Ty->getPointeeType();
if (Ty.getCVRQualifiers() != Qualifiers::Const)
return false;
- const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- if (RD && isNamed(RD, "nothrow_t") && RD->isInStdNamespace())
+ if (Ty->isNothrowT())
Consume();
}
return Params == FPT->getNumParams();
}
+bool FunctionDecl::isInlineBuiltinDeclaration() const {
+ if (!getBuiltinID())
+ return false;
+
+ const FunctionDecl *Definition;
+ return hasBody(Definition) && Definition->isInlineSpecified();
+}
+
bool FunctionDecl::isDestroyingOperatorDelete() const {
// C++ P0722:
// Within a class C, a single object deallocation function with signature
@@ -3075,10 +3171,17 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); }
/// functions as their wrapped builtins. This shouldn't be done in general, but
/// it's useful in Sema to diagnose calls to wrappers based on their semantics.
unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
- if (!getIdentifier())
- return 0;
+ unsigned BuiltinID;
+
+ if (const auto *AMAA = getAttr<ArmMveAliasAttr>()) {
+ BuiltinID = AMAA->getBuiltinName()->getBuiltinID();
+ } else {
+ if (!getIdentifier())
+ return 0;
+
+ BuiltinID = getIdentifier()->getBuiltinID();
+ }
- unsigned BuiltinID = getIdentifier()->getBuiltinID();
if (!BuiltinID)
return 0;
@@ -3102,7 +3205,8 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
// If the function is marked "overloadable", it has a different mangled name
// and is not the C library function.
- if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>())
+ if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>() &&
+ !hasAttr<ArmMveAliasAttr>())
return 0;
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
@@ -3235,6 +3339,9 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
return true;
}
+ if (Context.getLangOpts().CPlusPlus)
+ return false;
+
if (Context.getLangOpts().GNUInline || hasAttr<GNUInlineAttr>()) {
// With GNU inlining, a declaration with 'inline' but not 'extern', forces
// an externally visible definition.
@@ -3247,9 +3354,9 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
const FunctionDecl *Prev = this;
bool FoundBody = false;
while ((Prev = Prev->getPreviousDecl())) {
- FoundBody |= Prev->Body.isValid();
+ FoundBody |= Prev->doesThisDeclarationHaveABody();
- if (Prev->Body) {
+ if (Prev->doesThisDeclarationHaveABody()) {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then it is always externally visible.
if (!Prev->isInlineSpecified() ||
@@ -3263,9 +3370,6 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
return FoundBody;
}
- if (Context.getLangOpts().CPlusPlus)
- return false;
-
// C99 6.7.4p6:
// [...] If all of the file scope declarations for a function in a
// translation unit include the inline function specifier without extern,
@@ -3275,19 +3379,21 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
const FunctionDecl *Prev = this;
bool FoundBody = false;
while ((Prev = Prev->getPreviousDecl())) {
- FoundBody |= Prev->Body.isValid();
+ FoundBody |= Prev->doesThisDeclarationHaveABody();
if (RedeclForcesDefC99(Prev))
return false;
}
return FoundBody;
}
-SourceRange FunctionDecl::getReturnTypeSourceRange() const {
+FunctionTypeLoc FunctionDecl::getFunctionTypeLoc() const {
const TypeSourceInfo *TSI = getTypeSourceInfo();
- if (!TSI)
- return SourceRange();
- FunctionTypeLoc FTL =
- TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
+ return TSI ? TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>()
+ : FunctionTypeLoc();
+}
+
+SourceRange FunctionDecl::getReturnTypeSourceRange() const {
+ FunctionTypeLoc FTL = getFunctionTypeLoc();
if (!FTL)
return SourceRange();
@@ -3302,16 +3408,25 @@ SourceRange FunctionDecl::getReturnTypeSourceRange() const {
return RTRange;
}
-SourceRange FunctionDecl::getExceptionSpecSourceRange() const {
- const TypeSourceInfo *TSI = getTypeSourceInfo();
- if (!TSI)
- return SourceRange();
- FunctionTypeLoc FTL =
- TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
- if (!FTL)
+SourceRange FunctionDecl::getParametersSourceRange() const {
+ unsigned NP = getNumParams();
+ SourceLocation EllipsisLoc = getEllipsisLoc();
+
+ if (NP == 0 && EllipsisLoc.isInvalid())
return SourceRange();
- return FTL.getExceptionSpecRange();
+ SourceLocation Begin =
+ NP > 0 ? ParamInfo[0]->getSourceRange().getBegin() : EllipsisLoc;
+ SourceLocation End = EllipsisLoc.isValid()
+ ? EllipsisLoc
+ : ParamInfo[NP - 1]->getSourceRange().getEnd();
+
+ return SourceRange(Begin, End);
+}
+
+SourceRange FunctionDecl::getExceptionSpecSourceRange() const {
+ FunctionTypeLoc FTL = getFunctionTypeLoc();
+ return FTL ? FTL.getExceptionSpecRange() : SourceRange();
}
/// For an inline function definition in C, or for a gnu_inline function
@@ -3345,6 +3460,8 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then this inline definition is
// externally visible.
+ if (Context.getLangOpts().CPlusPlus)
+ return false;
if (!(isInlineSpecified() && getStorageClass() == SC_Extern))
return true;
@@ -3770,6 +3887,11 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
case Builtin::BImemcpy:
return Builtin::BImemcpy;
+ case Builtin::BI__builtin_mempcpy:
+ case Builtin::BI__builtin___mempcpy_chk:
+ case Builtin::BImempcpy:
+ return Builtin::BImempcpy;
+
case Builtin::BI__builtin_memmove:
case Builtin::BI__builtin___memmove_chk:
case Builtin::BImemmove:
@@ -3827,6 +3949,8 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
return Builtin::BImemset;
else if (FnInfo->isStr("memcpy"))
return Builtin::BImemcpy;
+ else if (FnInfo->isStr("mempcpy"))
+ return Builtin::BImempcpy;
else if (FnInfo->isStr("memmove"))
return Builtin::BImemmove;
else if (FnInfo->isStr("memcmp"))
@@ -4540,7 +4664,7 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
}
void LabelDecl::setMSAsmLabel(StringRef Name) {
- char *Buffer = new (getASTContext(), 1) char[Name.size() + 1];
+char *Buffer = new (getASTContext(), 1) char[Name.size() + 1];
memcpy(Buffer, Name.data(), Name.size());
Buffer[Name.size()] = '\0';
MSAsmName = Buffer;
@@ -4581,10 +4705,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
QualType T, TypeSourceInfo *TInfo,
StorageClass SC, bool isInlineSpecified,
bool hasWrittenPrototype,
- ConstexprSpecKind ConstexprKind) {
+ ConstexprSpecKind ConstexprKind,
+ Expr *TrailingRequiresClause) {
FunctionDecl *New =
new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo,
- SC, isInlineSpecified, ConstexprKind);
+ SC, isInlineSpecified, ConstexprKind,
+ TrailingRequiresClause);
New->setHasWrittenPrototype(hasWrittenPrototype);
return New;
}
@@ -4592,7 +4718,7 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) FunctionDecl(Function, C, nullptr, SourceLocation(),
DeclarationNameInfo(), QualType(), nullptr,
- SC_None, false, CSK_unspecified);
+ SC_None, false, CSK_unspecified, nullptr);
}
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
diff --git a/contrib/llvm-project/clang/lib/AST/DeclBase.cpp b/contrib/llvm-project/clang/lib/AST/DeclBase.cpp
index fd80e1532eb5..cb4d61cac2c7 100644
--- a/contrib/llvm-project/clang/lib/AST/DeclBase.cpp
+++ b/contrib/llvm-project/clang/lib/AST/DeclBase.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/DeclBase.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/Attr.h"
#include "clang/AST/AttrIterator.h"
@@ -99,7 +100,7 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
// Ensure required alignment of the resulting object by adding extra
// padding at the start if required.
size_t ExtraAlign =
- llvm::OffsetToAlignment(sizeof(Module *), alignof(Decl));
+ llvm::offsetToAlignment(sizeof(Module *), llvm::Align(alignof(Decl)));
auto *Buffer = reinterpret_cast<char *>(
::operator new(ExtraAlign + sizeof(Module *) + Size + Extra, Ctx));
Buffer += ExtraAlign;
@@ -802,6 +803,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case OMPRequires:
case OMPCapturedExpr:
case Empty:
+ case LifetimeExtendedTemporary:
+ case RequiresExprBody:
// Never looked up by name.
return 0;
}
@@ -958,11 +961,11 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const {
return nullptr;
if (Ty->isFunctionPointerType())
- Ty = Ty->getAs<PointerType>()->getPointeeType();
+ Ty = Ty->castAs<PointerType>()->getPointeeType();
else if (Ty->isFunctionReferenceType())
- Ty = Ty->getAs<ReferenceType>()->getPointeeType();
+ Ty = Ty->castAs<ReferenceType>()->getPointeeType();
else if (BlocksToo && Ty->isBlockPointerType())
- Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
+ Ty = Ty->castAs<BlockPointerType>()->getPointeeType();
return Ty->getAs<FunctionType>();
}
@@ -1043,6 +1046,12 @@ DeclContext *DeclContext::getLookupParent() {
getLexicalParent()->getRedeclContext()->isRecord())
return getLexicalParent();
+ // A lookup within the call operator of a lambda never looks in the lambda
+ // class; instead, skip to the context in which that closure type is
+ // declared.
+ if (isLambdaCallOperator(this))
+ return getParent()->getParent();
+
return getParent();
}
@@ -1169,6 +1178,7 @@ DeclContext *DeclContext::getPrimaryContext() {
case Decl::Captured:
case Decl::OMPDeclareReduction:
case Decl::OMPDeclareMapper:
+ case Decl::RequiresExprBody:
// There is only one DeclContext for these entities.
return this;
diff --git a/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp b/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp
index 59710a55498f..227fe80ccab4 100644
--- a/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp
+++ b/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/ASTUnresolvedSet.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclTemplate.h"
@@ -95,14 +96,16 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
HasDefaultedDefaultConstructor(false),
DefaultedDefaultConstructorIsConstexpr(true),
HasConstexprDefaultConstructor(false),
- HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
+ DefaultedDestructorIsConstexpr(true),
+ HasNonLiteralTypeFieldsOrBases(false),
UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0),
ImplicitCopyConstructorCanHaveConstParamForVBase(true),
ImplicitCopyConstructorCanHaveConstParamForNonVBase(true),
ImplicitCopyAssignmentHasConstParam(true),
HasDeclaredCopyConstructorWithConstParam(false),
HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false),
- IsParsingBaseSpecifiers(false), HasODRHash(false), Definition(D) {}
+ IsParsingBaseSpecifiers(false), ComputedVisibleConversions(false),
+ HasODRHash(false), Definition(D) {}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
return Bases.get(Definition->getASTContext().getExternalSource());
@@ -217,7 +220,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (BaseType->isDependentType())
continue;
auto *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(BaseType->castAs<RecordType>()->getDecl());
// C++2a [class]p7:
// A standard-layout class is a class that:
@@ -325,10 +328,12 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().IsStandardLayout = false;
data().IsCXX11StandardLayout = false;
- // C++11 [dcl.constexpr]p4:
- // In the definition of a constexpr constructor [...]
- // -- the class shall not have any virtual base classes
+ // C++20 [dcl.constexpr]p3:
+ // In the definition of a constexpr function [...]
+ // -- if the function is a constructor or destructor,
+ // its class shall not have any virtual base classes
data().DefaultedDefaultConstructorIsConstexpr = false;
+ data().DefaultedDestructorIsConstexpr = false;
// C++1z [class.copy]p8:
// The implicitly-declared copy constructor for a class X will have
@@ -409,7 +414,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().HasIrrelevantDestructor = false;
// C++11 [class.copy]p18:
- // The implicitly-declared copy assignment oeprator for a class X will
+ // The implicitly-declared copy assignment operator for a class X will
// have the form 'X& X::operator=(const X&)' if each direct base class B
// of X has a copy assignment operator whose parameter is of type 'const
// B&', 'const volatile B&', or 'B' [...]
@@ -520,6 +525,19 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
data().NeedOverloadResolutionForMoveConstructor = true;
data().NeedOverloadResolutionForDestructor = true;
}
+
+ // C++2a [dcl.constexpr]p4:
+ // The definition of a constexpr destructor [shall] satisfy the
+ // following requirement:
+ // -- for every subobject of class type or (possibly multi-dimensional)
+ // array thereof, that class type shall have a constexpr destructor
+ if (!Subobj->hasConstexprDestructor())
+ data().DefaultedDestructorIsConstexpr = false;
+}
+
+bool CXXRecordDecl::hasConstexprDestructor() const {
+ auto *Dtor = getDestructor();
+ return Dtor ? Dtor->isConstexpr() : defaultedDestructorIsConstexpr();
}
bool CXXRecordDecl::hasAnyDependentBases() const {
@@ -720,49 +738,55 @@ void CXXRecordDecl::addedMember(Decl *D) {
// Handle constructors.
if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- if (!Constructor->isImplicit()) {
- // Note that we have a user-declared constructor.
- data().UserDeclaredConstructor = true;
+ if (Constructor->isInheritingConstructor()) {
+ // Ignore constructor shadow declarations. They are lazily created and
+ // so shouldn't affect any properties of the class.
+ } else {
+ if (!Constructor->isImplicit()) {
+ // Note that we have a user-declared constructor.
+ data().UserDeclaredConstructor = true;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ // Since the POD bit is meant to be C++03 POD-ness, clear it even if
+ // the type is technically an aggregate in C++0x since it wouldn't be
+ // in 03.
+ data().PlainOldData = false;
+ }
- // C++ [class]p4:
- // A POD-struct is an aggregate class [...]
- // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
- // type is technically an aggregate in C++0x since it wouldn't be in 03.
- data().PlainOldData = false;
- }
+ if (Constructor->isDefaultConstructor()) {
+ SMKind |= SMF_DefaultConstructor;
- if (Constructor->isDefaultConstructor()) {
- SMKind |= SMF_DefaultConstructor;
+ if (Constructor->isUserProvided())
+ data().UserProvidedDefaultConstructor = true;
+ if (Constructor->isConstexpr())
+ data().HasConstexprDefaultConstructor = true;
+ if (Constructor->isDefaulted())
+ data().HasDefaultedDefaultConstructor = true;
+ }
- if (Constructor->isUserProvided())
- data().UserProvidedDefaultConstructor = true;
- if (Constructor->isConstexpr())
- data().HasConstexprDefaultConstructor = true;
- if (Constructor->isDefaulted())
- data().HasDefaultedDefaultConstructor = true;
- }
+ if (!FunTmpl) {
+ unsigned Quals;
+ if (Constructor->isCopyConstructor(Quals)) {
+ SMKind |= SMF_CopyConstructor;
- if (!FunTmpl) {
- unsigned Quals;
- if (Constructor->isCopyConstructor(Quals)) {
- SMKind |= SMF_CopyConstructor;
+ if (Quals & Qualifiers::Const)
+ data().HasDeclaredCopyConstructorWithConstParam = true;
+ } else if (Constructor->isMoveConstructor())
+ SMKind |= SMF_MoveConstructor;
+ }
- if (Quals & Qualifiers::Const)
- data().HasDeclaredCopyConstructorWithConstParam = true;
- } else if (Constructor->isMoveConstructor())
- SMKind |= SMF_MoveConstructor;
+ // C++11 [dcl.init.aggr]p1: DR1518
+ // An aggregate is an array or a class with no user-provided [or]
+ // explicit [...] constructors
+ // C++20 [dcl.init.aggr]p1:
+ // An aggregate is an array or a class with no user-declared [...]
+ // constructors
+ if (getASTContext().getLangOpts().CPlusPlus2a
+ ? !Constructor->isImplicit()
+ : (Constructor->isUserProvided() || Constructor->isExplicit()))
+ data().Aggregate = false;
}
-
- // C++11 [dcl.init.aggr]p1: DR1518
- // An aggregate is an array or a class with no user-provided [or]
- // explicit [...] constructors
- // C++20 [dcl.init.aggr]p1:
- // An aggregate is an array or a class with no user-declared [...]
- // constructors
- if (getASTContext().getLangOpts().CPlusPlus2a
- ? !Constructor->isImplicit()
- : (Constructor->isUserProvided() || Constructor->isExplicit()))
- data().Aggregate = false;
}
// Handle constructors, including those inherited from base classes.
@@ -1263,7 +1287,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
} else {
// Base element type of field is a non-class type.
if (!T->isLiteralType(Context) ||
- (!Field->hasInClassInitializer() && !isUnion()))
+ (!Field->hasInClassInitializer() && !isUnion() &&
+ !Context.getLangOpts().CPlusPlus2a))
data().DefaultedDefaultConstructorIsConstexpr = false;
// C++11 [class.copy]p23:
@@ -1382,17 +1407,29 @@ static bool allLookupResultsAreTheSame(const DeclContext::lookup_result &R) {
}
#endif
-CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
- if (!isLambda()) return nullptr;
+static NamedDecl* getLambdaCallOperatorHelper(const CXXRecordDecl &RD) {
+ if (!RD.isLambda()) return nullptr;
DeclarationName Name =
- getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
- DeclContext::lookup_result Calls = lookup(Name);
+ RD.getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclContext::lookup_result Calls = RD.lookup(Name);
assert(!Calls.empty() && "Missing lambda call operator!");
assert(allLookupResultsAreTheSame(Calls) &&
"More than one lambda call operator!");
+ return Calls.front();
+}
+
+FunctionTemplateDecl* CXXRecordDecl::getDependentLambdaCallOperator() const {
+ NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
+ return dyn_cast_or_null<FunctionTemplateDecl>(CallOp);
+}
+
+CXXMethodDecl *CXXRecordDecl::getLambdaCallOperator() const {
+ NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
+
+ if (CallOp == nullptr)
+ return nullptr;
- NamedDecl *CallOp = Calls.front();
if (const auto *CallOpTmpl = dyn_cast<FunctionTemplateDecl>(CallOp))
return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
@@ -1481,14 +1518,12 @@ static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
/// \param VOutput the set to which to add conversions from virtual bases
/// \param HiddenVBaseCs the set of conversions which were hidden in a
/// virtual base along some inheritance path
-static void CollectVisibleConversions(ASTContext &Context,
- CXXRecordDecl *Record,
- bool InVirtual,
- AccessSpecifier Access,
- const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
- ASTUnresolvedSet &Output,
- UnresolvedSetImpl &VOutput,
- llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) {
+static void CollectVisibleConversions(
+ ASTContext &Context, const CXXRecordDecl *Record, bool InVirtual,
+ AccessSpecifier Access,
+ const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
+ ASTUnresolvedSet &Output, UnresolvedSetImpl &VOutput,
+ llvm::SmallPtrSet<NamedDecl *, 8> &HiddenVBaseCs) {
// The set of types which have conversions in this class or its
// subclasses. As an optimization, we don't copy the derived set
// unless it might change.
@@ -1529,7 +1564,7 @@ static void CollectVisibleConversions(ASTContext &Context,
// Collect information recursively from any base classes.
for (const auto &I : Record->bases()) {
- const RecordType *RT = I.getType()->getAs<RecordType>();
+ const auto *RT = I.getType()->getAs<RecordType>();
if (!RT) continue;
AccessSpecifier BaseAccess
@@ -1547,7 +1582,7 @@ static void CollectVisibleConversions(ASTContext &Context,
/// This would be extremely straightforward if it weren't for virtual
/// bases. It might be worth special-casing that, really.
static void CollectVisibleConversions(ASTContext &Context,
- CXXRecordDecl *Record,
+ const CXXRecordDecl *Record,
ASTUnresolvedSet &Output) {
// The collection of all conversions in virtual bases that we've
// found. These will be added to the output as long as they don't
@@ -1571,7 +1606,7 @@ static void CollectVisibleConversions(ASTContext &Context,
// Recursively collect conversions from base classes.
for (const auto &I : Record->bases()) {
- const RecordType *RT = I.getType()->getAs<RecordType>();
+ const auto *RT = I.getType()->getAs<RecordType>();
if (!RT) continue;
CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()),
@@ -1590,7 +1625,7 @@ static void CollectVisibleConversions(ASTContext &Context,
/// getVisibleConversionFunctions - get all conversion functions visible
/// in current class; including conversion function templates.
llvm::iterator_range<CXXRecordDecl::conversion_iterator>
-CXXRecordDecl::getVisibleConversionFunctions() {
+CXXRecordDecl::getVisibleConversionFunctions() const {
ASTContext &Ctx = getASTContext();
ASTUnresolvedSet *Set;
@@ -1880,7 +1915,7 @@ bool CXXRecordDecl::mayBeAbstract() const {
for (const auto &B : bases()) {
const auto *BaseDecl =
- cast<CXXRecordDecl>(B.getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl());
if (BaseDecl->isAbstract())
return true;
}
@@ -1933,6 +1968,16 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,
QualType(), nullptr, SourceLocation());
}
+RequiresExprBodyDecl *RequiresExprBodyDecl::Create(
+ ASTContext &C, DeclContext *DC, SourceLocation StartLoc) {
+ return new (C, DC) RequiresExprBodyDecl(C, DC, StartLoc);
+}
+
+RequiresExprBodyDecl *RequiresExprBodyDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ return new (C, ID) RequiresExprBodyDecl(C, nullptr, SourceLocation());
+}
+
void CXXMethodDecl::anchor() {}
bool CXXMethodDecl::isStatic() const {
@@ -1993,17 +2038,36 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
if (auto *MD = getCorrespondingMethodDeclaredInClass(RD, MayBeBase))
return MD;
+ llvm::SmallVector<CXXMethodDecl*, 4> FinalOverriders;
+ auto AddFinalOverrider = [&](CXXMethodDecl *D) {
+ // If this function is overridden by a candidate final overrider, it is not
+ // a final overrider.
+ for (CXXMethodDecl *OtherD : FinalOverriders) {
+ if (declaresSameEntity(D, OtherD) || recursivelyOverrides(OtherD, D))
+ return;
+ }
+
+ // Other candidate final overriders might be overridden by this function.
+ FinalOverriders.erase(
+ std::remove_if(FinalOverriders.begin(), FinalOverriders.end(),
+ [&](CXXMethodDecl *OtherD) {
+ return recursivelyOverrides(D, OtherD);
+ }),
+ FinalOverriders.end());
+
+ FinalOverriders.push_back(D);
+ };
+
for (const auto &I : RD->bases()) {
const RecordType *RT = I.getType()->getAs<RecordType>();
if (!RT)
continue;
const auto *Base = cast<CXXRecordDecl>(RT->getDecl());
- CXXMethodDecl *T = this->getCorrespondingMethodInClass(Base);
- if (T)
- return T;
+ if (CXXMethodDecl *D = this->getCorrespondingMethodInClass(Base))
+ AddFinalOverrider(D);
}
- return nullptr;
+ return FinalOverriders.size() == 1 ? FinalOverriders.front() : nullptr;
}
CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
@@ -2012,16 +2076,19 @@ CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
QualType T, TypeSourceInfo *TInfo,
StorageClass SC, bool isInline,
ConstexprSpecKind ConstexprKind,
- SourceLocation EndLocation) {
+ SourceLocation EndLocation,
+ Expr *TrailingRequiresClause) {
return new (C, RD)
CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC,
- isInline, ConstexprKind, EndLocation);
+ isInline, ConstexprKind, EndLocation,
+ TrailingRequiresClause);
}
CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) CXXMethodDecl(
CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(),
- QualType(), nullptr, SC_None, false, CSK_unspecified, SourceLocation());
+ QualType(), nullptr, SC_None, false, CSK_unspecified, SourceLocation(),
+ nullptr);
}
CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
@@ -2057,6 +2124,11 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
CXXMethodDecl *DevirtualizedMethod =
getCorrespondingMethodInClass(BestDynamicDecl);
+ // If there final overrider in the dynamic type is ambiguous, we can't
+ // devirtualize this call.
+ if (!DevirtualizedMethod)
+ return nullptr;
+
// If that method is pure virtual, we can't devirtualize. If this code is
// reached, the result would be UB, not a direct call to the derived class
// function, and we can't assume the derived class function is defined.
@@ -2067,10 +2139,15 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
if (DevirtualizedMethod->hasAttr<FinalAttr>())
return DevirtualizedMethod;
- // Similarly, if the class itself is marked 'final' it can't be overridden
- // and we can therefore devirtualize the member function call.
+ // Similarly, if the class itself or its destructor is marked 'final',
+ // the class can't be derived from and we can therefore devirtualize the
+ // member function call.
if (BestDynamicDecl->hasAttr<FinalAttr>())
return DevirtualizedMethod;
+ if (const auto *dtor = BestDynamicDecl->getDestructor()) {
+ if (dtor->hasAttr<FinalAttr>())
+ return DevirtualizedMethod;
+ }
if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
@@ -2397,9 +2474,11 @@ CXXConstructorDecl::CXXConstructorDecl(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
- ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited)
+ ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited,
+ Expr *TrailingRequiresClause)
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
- SC_None, isInline, ConstexprKind, SourceLocation()) {
+ SC_None, isInline, ConstexprKind, SourceLocation(),
+ TrailingRequiresClause) {
setNumCtorInitializers(0);
setInheritingConstructor(static_cast<bool>(Inherited));
setImplicit(isImplicitlyDeclared);
@@ -2423,7 +2502,7 @@ CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C,
auto *Result = new (C, ID, Extra)
CXXConstructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(),
QualType(), nullptr, ExplicitSpecifier(), false, false,
- CSK_unspecified, InheritedConstructor());
+ CSK_unspecified, InheritedConstructor(), nullptr);
Result->setInheritingConstructor(isInheritingConstructor);
Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier =
hasTraillingExplicit;
@@ -2435,7 +2514,8 @@ CXXConstructorDecl *CXXConstructorDecl::Create(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
- ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited) {
+ ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited,
+ Expr *TrailingRequiresClause) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
@@ -2444,7 +2524,8 @@ CXXConstructorDecl *CXXConstructorDecl::Create(
Inherited ? 1 : 0, ES.getExpr() ? 1 : 0);
return new (C, RD, Extra)
CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline,
- isImplicitlyDeclared, ConstexprKind, Inherited);
+ isImplicitlyDeclared, ConstexprKind, Inherited,
+ TrailingRequiresClause);
}
CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
@@ -2532,7 +2613,7 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const {
return false;
return (getNumParams() == 0 &&
- getType()->getAs<FunctionProtoType>()->isVariadic()) ||
+ getType()->castAs<FunctionProtoType>()->isVariadic()) ||
(getNumParams() == 1) ||
(getNumParams() > 1 &&
(getParamDecl(1)->hasDefaultArg() ||
@@ -2565,20 +2646,22 @@ CXXDestructorDecl *
CXXDestructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID)
CXXDestructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(),
- QualType(), nullptr, false, false);
+ QualType(), nullptr, false, false, CSK_unspecified,
+ nullptr);
}
-CXXDestructorDecl *
-CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
- SourceLocation StartLoc,
- const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isImplicitlyDeclared) {
+CXXDestructorDecl *CXXDestructorDecl::Create(
+ ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
+ const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
+ bool isInline, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
+ Expr *TrailingRequiresClause) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXDestructorName &&
"Name must refer to a destructor");
- return new (C, RD) CXXDestructorDecl(C, RD, StartLoc, NameInfo, T, TInfo,
- isInline, isImplicitlyDeclared);
+ return new (C, RD)
+ CXXDestructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline,
+ isImplicitlyDeclared, ConstexprKind,
+ TrailingRequiresClause);
}
void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) {
@@ -2597,20 +2680,20 @@ CXXConversionDecl *
CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) CXXConversionDecl(
C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
- false, ExplicitSpecifier(), CSK_unspecified, SourceLocation());
+ false, ExplicitSpecifier(), CSK_unspecified, SourceLocation(), nullptr);
}
CXXConversionDecl *CXXConversionDecl::Create(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
bool isInline, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind,
- SourceLocation EndLocation) {
+ SourceLocation EndLocation, Expr *TrailingRequiresClause) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConversionFunctionName &&
"Name must refer to a conversion function");
return new (C, RD)
CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, ES,
- ConstexprKind, EndLocation);
+ ConstexprKind, EndLocation, TrailingRequiresClause);
}
bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
@@ -2762,6 +2845,36 @@ NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
SourceLocation(), nullptr);
}
+void LifetimeExtendedTemporaryDecl::anchor() {}
+
+/// Retrieve the storage duration for the materialized temporary.
+StorageDuration LifetimeExtendedTemporaryDecl::getStorageDuration() const {
+ const ValueDecl *ExtendingDecl = getExtendingDecl();
+ if (!ExtendingDecl)
+ return SD_FullExpression;
+ // FIXME: This is not necessarily correct for a temporary materialized
+ // within a default initializer.
+ if (isa<FieldDecl>(ExtendingDecl))
+ return SD_Automatic;
+ // FIXME: This only works because storage class specifiers are not allowed
+ // on decomposition declarations.
+ if (isa<BindingDecl>(ExtendingDecl))
+ return ExtendingDecl->getDeclContext()->isFunctionOrMethod() ? SD_Automatic
+ : SD_Static;
+ return cast<VarDecl>(ExtendingDecl)->getStorageDuration();
+}
+
+APValue *LifetimeExtendedTemporaryDecl::getOrCreateValue(bool MayCreate) const {
+ assert(getStorageDuration() == SD_Static &&
+ "don't need to cache the computed value for this temporary");
+ if (MayCreate && !Value) {
+ Value = (new (getASTContext()) APValue);
+ getASTContext().addDestruction(Value);
+ }
+ assert(Value && "may not be null");
+ return Value;
+}
+
void UsingShadowDecl::anchor() {}
UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC,
diff --git a/contrib/llvm-project/clang/lib/AST/DeclObjC.cpp b/contrib/llvm-project/clang/lib/AST/DeclObjC.cpp
index bf748fbab8e9..9a84e3c4a510 100644
--- a/contrib/llvm-project/clang/lib/AST/DeclObjC.cpp
+++ b/contrib/llvm-project/clang/lib/AST/DeclObjC.cpp
@@ -775,14 +775,12 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
// ObjCMethodDecl
//===----------------------------------------------------------------------===//
-ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
- Selector SelInfo, QualType T,
- TypeSourceInfo *ReturnTInfo,
- DeclContext *contextDecl, bool isInstance,
- bool isVariadic, bool isPropertyAccessor,
- bool isImplicitlyDeclared, bool isDefined,
- ImplementationControl impControl,
- bool HasRelatedResultType)
+ObjCMethodDecl::ObjCMethodDecl(
+ SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo,
+ QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl,
+ bool isInstance, bool isVariadic, bool isPropertyAccessor,
+ bool isSynthesizedAccessorStub, bool isImplicitlyDeclared, bool isDefined,
+ ImplementationControl impControl, bool HasRelatedResultType)
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
DeclContext(ObjCMethod), MethodDeclType(T), ReturnTInfo(ReturnTInfo),
DeclEndLoc(endLoc) {
@@ -793,6 +791,7 @@ ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
setInstanceMethod(isInstance);
setVariadic(isVariadic);
setPropertyAccessor(isPropertyAccessor);
+ setSynthesizedAccessorStub(isSynthesizedAccessorStub);
setDefined(isDefined);
setIsRedeclaration(false);
setHasRedeclaration(false);
@@ -810,12 +809,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create(
ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc,
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
DeclContext *contextDecl, bool isInstance, bool isVariadic,
- bool isPropertyAccessor, bool isImplicitlyDeclared, bool isDefined,
- ImplementationControl impControl, bool HasRelatedResultType) {
+ bool isPropertyAccessor, bool isSynthesizedAccessorStub,
+ bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl,
+ bool HasRelatedResultType) {
return new (C, contextDecl) ObjCMethodDecl(
beginLoc, endLoc, SelInfo, T, ReturnTInfo, contextDecl, isInstance,
- isVariadic, isPropertyAccessor, isImplicitlyDeclared, isDefined,
- impControl, HasRelatedResultType);
+ isVariadic, isPropertyAccessor, isSynthesizedAccessorStub,
+ isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType);
}
ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
@@ -823,6 +823,10 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
Selector(), QualType(), nullptr, nullptr);
}
+bool ObjCMethodDecl::isDirectMethod() const {
+ return hasAttr<ObjCDirectAttr>();
+}
+
bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const {
return getMethodFamily() == OMF_init &&
hasAttr<ObjCDesignatedInitializerAttr>();
@@ -952,24 +956,32 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclarationImpl() {
ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() {
auto *CtxD = cast<Decl>(getDeclContext());
+ const auto &Sel = getSelector();
if (auto *ImplD = dyn_cast<ObjCImplementationDecl>(CtxD)) {
- if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
- if (ObjCMethodDecl *MD = IFD->getMethod(getSelector(),
- isInstanceMethod()))
+ if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) {
+ // When the container is the ObjCImplementationDecl (the primary
+ // @implementation), then the canonical Decl is either in
+ // the class Interface, or in any of its extension.
+ //
+ // So when we don't find it in the ObjCInterfaceDecl,
+ // sift through extensions too.
+ if (ObjCMethodDecl *MD = IFD->getMethod(Sel, isInstanceMethod()))
return MD;
+ for (auto *Ext : IFD->known_extensions())
+ if (ObjCMethodDecl *MD = Ext->getMethod(Sel, isInstanceMethod()))
+ return MD;
+ }
} else if (auto *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
- if (ObjCMethodDecl *MD = CatD->getMethod(getSelector(),
- isInstanceMethod()))
+ if (ObjCMethodDecl *MD = CatD->getMethod(Sel, isInstanceMethod()))
return MD;
}
if (isRedeclaration()) {
// It is possible that we have not done deserializing the ObjCMethod yet.
ObjCMethodDecl *MD =
- cast<ObjCContainerDecl>(CtxD)->getMethod(getSelector(),
- isInstanceMethod());
+ cast<ObjCContainerDecl>(CtxD)->getMethod(Sel, isInstanceMethod());
return MD ? MD : this;
}
@@ -1077,7 +1089,7 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
QualType ObjCMethodDecl::getSelfType(ASTContext &Context,
const ObjCInterfaceDecl *OID,
bool &selfIsPseudoStrong,
- bool &selfIsConsumed) {
+ bool &selfIsConsumed) const {
QualType selfTy;
selfIsPseudoStrong = false;
selfIsConsumed = false;
@@ -1306,6 +1318,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
if (isPropertyAccessor()) {
const auto *Container = cast<ObjCContainerDecl>(getParent());
+ // For accessor stubs, go back to the interface.
+ if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container))
+ if (isSynthesizedAccessorStub())
+ Container = ImplDecl->getClassInterface();
+
bool IsGetter = (NumArgs == 0);
bool IsInstance = isInstanceMethod();
@@ -1358,6 +1375,15 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
}
}
+ assert(isSynthesizedAccessorStub() && "expected an accessor stub");
+ for (const auto *Cat : ClassDecl->known_categories()) {
+ if (Cat == Container)
+ continue;
+
+ if (const auto *Found = findMatchingProperty(Cat))
+ return Found;
+ }
+
llvm_unreachable("Marked as a property accessor but no property found!");
}
diff --git a/contrib/llvm-project/clang/lib/AST/DeclPrinter.cpp b/contrib/llvm-project/clang/lib/AST/DeclPrinter.cpp
index f5c69944034a..4cedcbed0644 100644
--- a/contrib/llvm-project/clang/lib/AST/DeclPrinter.cpp
+++ b/contrib/llvm-project/clang/lib/AST/DeclPrinter.cpp
@@ -108,8 +108,8 @@ namespace {
void printTemplateParameters(const TemplateParameterList *Params,
bool OmitTemplateKW = false);
- void printTemplateArguments(const TemplateArgumentList &Args,
- const TemplateParameterList *Params = nullptr);
+ void printTemplateArguments(llvm::ArrayRef<TemplateArgument> Args);
+ void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args);
void prettyPrintAttributes(Decl *D);
void prettyPrintPragmas(Decl *D);
void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
@@ -625,21 +625,26 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (Policy.FullyQualifiedName) {
Proto += D->getQualifiedNameAsString();
} else {
+ llvm::raw_string_ostream OS(Proto);
if (!Policy.SuppressScope) {
if (const NestedNameSpecifier *NS = D->getQualifier()) {
- llvm::raw_string_ostream OS(Proto);
NS->print(OS, Policy);
}
}
- Proto += D->getNameInfo().getAsString();
+ D->getNameInfo().printName(OS, Policy);
}
if (GuideDecl)
Proto = GuideDecl->getDeducedTemplate()->getDeclName().getAsString();
- if (const TemplateArgumentList *TArgs = D->getTemplateSpecializationArgs()) {
+ if (D->isFunctionTemplateSpecialization()) {
llvm::raw_string_ostream POut(Proto);
DeclPrinter TArgPrinter(POut, SubPolicy, Context, Indentation);
- TArgPrinter.printTemplateArguments(*TArgs);
+ const auto *TArgAsWritten = D->getTemplateSpecializationArgsAsWritten();
+ if (TArgAsWritten && !Policy.PrintCanonicalTypes)
+ TArgPrinter.printTemplateArguments(TArgAsWritten->arguments());
+ else if (const TemplateArgumentList *TArgs =
+ D->getTemplateSpecializationArgs())
+ TArgPrinter.printTemplateArguments(TArgs->asArray());
}
QualType Ty = D->getType();
@@ -735,6 +740,11 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Proto.clear();
}
Out << Proto;
+
+ if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) {
+ Out << " requires ";
+ TrailingRequiresClause->printPretty(Out, nullptr, SubPolicy, Indentation);
+ }
} else {
Ty.print(Out, Policy, Proto);
}
@@ -957,10 +967,15 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (D->getIdentifier()) {
Out << ' ' << *D;
- if (auto S = dyn_cast<ClassTemplatePartialSpecializationDecl>(D))
- printTemplateArguments(S->getTemplateArgs(), S->getTemplateParameters());
- else if (auto S = dyn_cast<ClassTemplateSpecializationDecl>(D))
- printTemplateArguments(S->getTemplateArgs());
+ if (auto S = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ ArrayRef<TemplateArgument> Args = S->getTemplateArgs().asArray();
+ if (!Policy.PrintCanonicalTypes)
+ if (const auto* TSI = S->getTypeAsWritten())
+ if (const auto *TST =
+ dyn_cast<TemplateSpecializationType>(TSI->getType()))
+ Args = TST->template_arguments();
+ printTemplateArguments(Args);
+ }
}
if (D->isCompleteDefinition()) {
@@ -1038,7 +1053,9 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params,
if (auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
- if (TTP->wasDeclaredWithTypename())
+ if (const TypeConstraint *TC = TTP->getTypeConstraint())
+ TC->print(Out, Policy);
+ else if (TTP->wasDeclaredWithTypename())
Out << "typename";
else
Out << "class";
@@ -1076,40 +1093,22 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params,
Out << ' ';
}
-void DeclPrinter::printTemplateArguments(const TemplateArgumentList &Args,
- const TemplateParameterList *Params) {
+void DeclPrinter::printTemplateArguments(ArrayRef<TemplateArgument> Args) {
Out << "<";
for (size_t I = 0, E = Args.size(); I < E; ++I) {
- const TemplateArgument &A = Args[I];
if (I)
Out << ", ";
- if (Params) {
- if (A.getKind() == TemplateArgument::Type)
- if (auto T = A.getAsType()->getAs<TemplateTypeParmType>()) {
- auto P = cast<TemplateTypeParmDecl>(Params->getParam(T->getIndex()));
- Out << *P;
- continue;
- }
- if (A.getKind() == TemplateArgument::Template) {
- if (auto T = A.getAsTemplate().getAsTemplateDecl())
- if (auto TD = dyn_cast<TemplateTemplateParmDecl>(T)) {
- auto P = cast<TemplateTemplateParmDecl>(
- Params->getParam(TD->getIndex()));
- Out << *P;
- continue;
- }
- }
- if (A.getKind() == TemplateArgument::Expression) {
- if (auto E = dyn_cast<DeclRefExpr>(A.getAsExpr()))
- if (auto N = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) {
- auto P = cast<NonTypeTemplateParmDecl>(
- Params->getParam(N->getIndex()));
- Out << *P;
- continue;
- }
- }
- }
- A.print(Policy, Out);
+ Args[I].print(Policy, Out);
+ }
+ Out << ">";
+}
+
+void DeclPrinter::printTemplateArguments(ArrayRef<TemplateArgumentLoc> Args) {
+ Out << "<";
+ for (size_t I = 0, E = Args.size(); I < E; ++I) {
+ if (I)
+ Out << ", ";
+ Args[I].getArgument().print(Policy, Out);
}
Out << ">";
}
@@ -1462,6 +1461,11 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
first = false;
}
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_direct) {
+ Out << (first ? "" : ", ") << "direct";
+ first = false;
+ }
+
if (PDecl->getPropertyAttributes() &
ObjCPropertyDecl::OBJC_PR_nonatomic) {
Out << (first ? "" : ", ") << "nonatomic";
diff --git a/contrib/llvm-project/clang/lib/AST/DeclTemplate.cpp b/contrib/llvm-project/clang/lib/AST/DeclTemplate.cpp
index 40c39c845db6..b5e4ec2d7f43 100644
--- a/contrib/llvm-project/clang/lib/AST/DeclTemplate.cpp
+++ b/contrib/llvm-project/clang/lib/AST/DeclTemplate.cpp
@@ -43,32 +43,45 @@ using namespace clang;
// TemplateParameterList Implementation
//===----------------------------------------------------------------------===//
-TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
+
+TemplateParameterList::TemplateParameterList(const ASTContext& C,
+ SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ArrayRef<NamedDecl *> Params,
SourceLocation RAngleLoc,
Expr *RequiresClause)
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
NumParams(Params.size()), ContainsUnexpandedParameterPack(false),
- HasRequiresClause(static_cast<bool>(RequiresClause)) {
+ HasRequiresClause(RequiresClause != nullptr),
+ HasConstrainedParameters(false) {
for (unsigned Idx = 0; Idx < NumParams; ++Idx) {
NamedDecl *P = Params[Idx];
begin()[Idx] = P;
- if (!P->isTemplateParameterPack()) {
- if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P))
- if (NTTP->getType()->containsUnexpandedParameterPack())
- ContainsUnexpandedParameterPack = true;
-
- if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P))
- if (TTP->getTemplateParameters()->containsUnexpandedParameterPack())
- ContainsUnexpandedParameterPack = true;
-
- // FIXME: If a default argument contains an unexpanded parameter pack, the
- // template parameter list does too.
+ bool IsPack = P->isTemplateParameterPack();
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
+ if (!IsPack && NTTP->getType()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+ if (NTTP->hasPlaceholderTypeConstraint())
+ HasConstrainedParameters = true;
+ } else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) {
+ if (!IsPack &&
+ TTP->getTemplateParameters()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+ } else if (const TypeConstraint *TC =
+ cast<TemplateTypeParmDecl>(P)->getTypeConstraint()) {
+ if (TC->getImmediatelyDeclaredConstraint()
+ ->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+ HasConstrainedParameters = true;
}
+ // FIXME: If a default argument contains an unexpanded parameter pack, the
+ // template parameter list does too.
}
- if (RequiresClause) {
+
+ if (HasRequiresClause) {
+ if (RequiresClause->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
*getTrailingObjects<Expr *>() = RequiresClause;
}
}
@@ -81,7 +94,7 @@ TemplateParameterList::Create(const ASTContext &C, SourceLocation TemplateLoc,
void *Mem = C.Allocate(totalSizeToAlloc<NamedDecl *, Expr *>(
Params.size(), RequiresClause ? 1u : 0u),
alignof(TemplateParameterList));
- return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params,
+ return new (Mem) TemplateParameterList(C, TemplateLoc, LAngleLoc, Params,
RAngleLoc, RequiresClause);
}
@@ -89,11 +102,23 @@ unsigned TemplateParameterList::getMinRequiredArguments() const {
unsigned NumRequiredArgs = 0;
for (const NamedDecl *P : asArray()) {
if (P->isTemplateParameterPack()) {
- if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P))
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
if (NTTP->isExpandedParameterPack()) {
NumRequiredArgs += NTTP->getNumExpansionTypes();
continue;
}
+ } else if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(P)) {
+ if (TTP->isExpandedParameterPack()) {
+ NumRequiredArgs += TTP->getNumExpansionParameters();
+ continue;
+ }
+ } else {
+ const auto *TP = cast<TemplateTemplateParmDecl>(P);
+ if (TP->isExpandedParameterPack()) {
+ NumRequiredArgs += TP->getNumExpansionTemplateParameters();
+ continue;
+ }
+ }
break;
}
@@ -136,6 +161,26 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
}
}
+void TemplateParameterList::
+getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
+ if (HasConstrainedParameters)
+ for (const NamedDecl *Param : *this) {
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ if (const auto *TC = TTP->getTypeConstraint())
+ AC.push_back(TC->getImmediatelyDeclaredConstraint());
+ } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (const Expr *E = NTTP->getPlaceholderTypeConstraint())
+ AC.push_back(E);
+ }
+ }
+ if (HasRequiresClause)
+ AC.push_back(getRequiresClause());
+}
+
+bool TemplateParameterList::hasAssociatedConstraints() const {
+ return HasRequiresClause || HasConstrainedParameters;
+}
+
namespace clang {
void *allocateDefaultArgStorageChain(const ASTContext &C) {
@@ -145,6 +190,33 @@ void *allocateDefaultArgStorageChain(const ASTContext &C) {
} // namespace clang
//===----------------------------------------------------------------------===//
+// TemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+TemplateDecl::TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ DeclarationName Name, TemplateParameterList *Params,
+ NamedDecl *Decl)
+ : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl), TemplateParams(Params) {}
+
+void TemplateDecl::anchor() {}
+
+void TemplateDecl::
+getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
+ TemplateParams->getAssociatedConstraints(AC);
+ if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl()))
+ if (const Expr *TRC = FD->getTrailingRequiresClause())
+ AC.push_back(TRC);
+}
+
+bool TemplateDecl::hasAssociatedConstraints() const {
+ if (TemplateParams->hasAssociatedConstraints())
+ return true;
+ if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl()))
+ return FD->getTrailingRequiresClause();
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
// RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -195,15 +267,16 @@ void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
}
}
-template<class EntryType>
+template<class EntryType, typename... ProfileArguments>
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
RedeclarableTemplateDecl::findSpecializationImpl(
- llvm::FoldingSetVector<EntryType> &Specs, ArrayRef<TemplateArgument> Args,
- void *&InsertPos) {
+ llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos,
+ ProfileArguments&&... ProfileArgs) {
using SETraits = SpecEntryTraits<EntryType>;
llvm::FoldingSetNodeID ID;
- EntryType::Profile(ID, Args, getASTContext());
+ EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
+ getASTContext());
EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos);
return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr;
}
@@ -218,8 +291,8 @@ void RedeclarableTemplateDecl::addSpecializationImpl(
#ifndef NDEBUG
void *CorrectInsertPos;
assert(!findSpecializationImpl(Specializations,
- SETraits::getTemplateArgs(Entry),
- CorrectInsertPos) &&
+ CorrectInsertPos,
+ SETraits::getTemplateArgs(Entry)) &&
InsertPos == CorrectInsertPos &&
"given incorrect InsertPos for specialization");
#endif
@@ -276,7 +349,7 @@ FunctionTemplateDecl::getSpecializations() const {
FunctionDecl *
FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), Args, InsertPos);
+ return findSpecializationImpl(getSpecializations(), InsertPos, Args);
}
void FunctionTemplateDecl::addSpecialization(
@@ -344,19 +417,10 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
- NamedDecl *Decl,
- Expr *AssociatedConstraints) {
+ NamedDecl *Decl) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
- if (!AssociatedConstraints) {
- return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl);
- }
-
- auto *const CTDI = new (C) ConstrainedTemplateDeclInfo;
- auto *const New =
- new (C, DC) ClassTemplateDecl(CTDI, C, DC, L, Name, Params, Decl);
- New->setAssociatedConstraints(AssociatedConstraints);
- return New;
+ return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl);
}
ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
@@ -391,7 +455,7 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
ClassTemplateSpecializationDecl *
ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), Args, InsertPos);
+ return findSpecializationImpl(getSpecializations(), InsertPos, Args);
}
void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
@@ -400,9 +464,51 @@ void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
}
ClassTemplatePartialSpecializationDecl *
-ClassTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args,
- void *&InsertPos) {
- return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos);
+ClassTemplateDecl::findPartialSpecialization(
+ ArrayRef<TemplateArgument> Args,
+ TemplateParameterList *TPL, void *&InsertPos) {
+ return findSpecializationImpl(getPartialSpecializations(), InsertPos, Args,
+ TPL);
+}
+
+static void ProfileTemplateParameterList(ASTContext &C,
+ llvm::FoldingSetNodeID &ID, const TemplateParameterList *TPL) {
+ const Expr *RC = TPL->getRequiresClause();
+ ID.AddBoolean(RC != nullptr);
+ if (RC)
+ RC->Profile(ID, C, /*Canonical=*/true);
+ ID.AddInteger(TPL->size());
+ for (NamedDecl *D : *TPL) {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ ID.AddInteger(0);
+ ID.AddBoolean(NTTP->isParameterPack());
+ NTTP->getType().getCanonicalType().Profile(ID);
+ continue;
+ }
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D)) {
+ ID.AddInteger(1);
+ ID.AddBoolean(TTP->isParameterPack());
+ ID.AddBoolean(TTP->hasTypeConstraint());
+ if (const TypeConstraint *TC = TTP->getTypeConstraint())
+ TC->getImmediatelyDeclaredConstraint()->Profile(ID, C,
+ /*Canonical=*/true);
+ continue;
+ }
+ const auto *TTP = cast<TemplateTemplateParmDecl>(D);
+ ID.AddInteger(2);
+ ID.AddBoolean(TTP->isParameterPack());
+ ProfileTemplateParameterList(C, ID, TTP->getTemplateParameters());
+ }
+}
+
+void
+ClassTemplatePartialSpecializationDecl::Profile(llvm::FoldingSetNodeID &ID,
+ ArrayRef<TemplateArgument> TemplateArgs, TemplateParameterList *TPL,
+ ASTContext &Context) {
+ ID.AddInteger(TemplateArgs.size());
+ for (const TemplateArgument &TemplateArg : TemplateArgs)
+ TemplateArg.Profile(ID, Context);
+ ProfileTemplateParameterList(Context, ID, TPL);
}
void ClassTemplateDecl::AddPartialSpecialization(
@@ -486,9 +592,14 @@ TemplateTypeParmDecl *
TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation KeyLoc, SourceLocation NameLoc,
unsigned D, unsigned P, IdentifierInfo *Id,
- bool Typename, bool ParameterPack) {
+ bool Typename, bool ParameterPack,
+ bool HasTypeConstraint,
+ Optional<unsigned> NumExpanded) {
auto *TTPDecl =
- new (C, DC) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename);
+ new (C, DC,
+ additionalSizeToAlloc<TypeConstraint>(HasTypeConstraint ? 1 : 0))
+ TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename,
+ HasTypeConstraint, NumExpanded);
QualType TTPType = C.getTemplateTypeParmType(D, P, ParameterPack, TTPDecl);
TTPDecl->setTypeForDecl(TTPType.getTypePtr());
return TTPDecl;
@@ -497,7 +608,17 @@ TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
TemplateTypeParmDecl *
TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
return new (C, ID) TemplateTypeParmDecl(nullptr, SourceLocation(),
- SourceLocation(), nullptr, false);
+ SourceLocation(), nullptr, false,
+ false, None);
+}
+
+TemplateTypeParmDecl *
+TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, unsigned ID,
+ bool HasTypeConstraint) {
+ return new (C, ID,
+ additionalSizeToAlloc<TypeConstraint>(HasTypeConstraint ? 1 : 0))
+ TemplateTypeParmDecl(nullptr, SourceLocation(), SourceLocation(),
+ nullptr, false, HasTypeConstraint, None);
}
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
@@ -510,20 +631,38 @@ SourceRange TemplateTypeParmDecl::getSourceRange() const {
if (hasDefaultArgument() && !defaultArgumentWasInherited())
return SourceRange(getBeginLoc(),
getDefaultArgumentInfo()->getTypeLoc().getEndLoc());
- else
- return TypeDecl::getSourceRange();
+ // TypeDecl::getSourceRange returns a range containing name location, which is
+ // wrong for unnamed template parameters. e.g:
+ // it will return <[[typename>]] instead of <[[typename]]>
+ else if (getDeclName().isEmpty())
+ return SourceRange(getBeginLoc());
+ return TypeDecl::getSourceRange();
}
unsigned TemplateTypeParmDecl::getDepth() const {
- return getTypeForDecl()->getAs<TemplateTypeParmType>()->getDepth();
+ return getTypeForDecl()->castAs<TemplateTypeParmType>()->getDepth();
}
unsigned TemplateTypeParmDecl::getIndex() const {
- return getTypeForDecl()->getAs<TemplateTypeParmType>()->getIndex();
+ return getTypeForDecl()->castAs<TemplateTypeParmType>()->getIndex();
}
bool TemplateTypeParmDecl::isParameterPack() const {
- return getTypeForDecl()->getAs<TemplateTypeParmType>()->isParameterPack();
+ return getTypeForDecl()->castAs<TemplateTypeParmType>()->isParameterPack();
+}
+
+void TemplateTypeParmDecl::setTypeConstraint(NestedNameSpecifierLoc NNS,
+ DeclarationNameInfo NameInfo, NamedDecl *FoundDecl, ConceptDecl *CD,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ Expr *ImmediatelyDeclaredConstraint) {
+ assert(HasTypeConstraint &&
+ "HasTypeConstraint=true must be passed at construction in order to "
+ "call setTypeConstraint");
+ assert(!TypeConstraintInitialized &&
+ "TypeConstraint was already initialized!");
+ new (getTrailingObjects<TypeConstraint>()) TypeConstraint(NNS, NameInfo,
+ FoundDecl, CD, ArgsAsWritten, ImmediatelyDeclaredConstraint);
+ TypeConstraintInitialized = true;
}
//===----------------------------------------------------------------------===//
@@ -553,8 +692,14 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
unsigned D, unsigned P, IdentifierInfo *Id,
QualType T, bool ParameterPack,
TypeSourceInfo *TInfo) {
- return new (C, DC) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id,
- T, ParameterPack, TInfo);
+ AutoType *AT =
+ C.getLangOpts().CPlusPlus2a ? T->getContainedAutoType() : nullptr;
+ return new (C, DC,
+ additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+ Expr *>(0,
+ AT && AT->isConstrained() ? 1 : 0))
+ NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, ParameterPack,
+ TInfo);
}
NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
@@ -562,26 +707,34 @@ NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes,
ArrayRef<TypeSourceInfo *> ExpandedTInfos) {
+ AutoType *AT = TInfo->getType()->getContainedAutoType();
return new (C, DC,
- additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>(
- ExpandedTypes.size()))
+ additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+ Expr *>(
+ ExpandedTypes.size(), AT && AT->isConstrained() ? 1 : 0))
NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, TInfo,
ExpandedTypes, ExpandedTInfos);
}
NonTypeTemplateParmDecl *
-NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- return new (C, ID) NonTypeTemplateParmDecl(nullptr, SourceLocation(),
- SourceLocation(), 0, 0, nullptr,
- QualType(), false, nullptr);
+NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+ bool HasTypeConstraint) {
+ return new (C, ID, additionalSizeToAlloc<std::pair<QualType,
+ TypeSourceInfo *>,
+ Expr *>(0,
+ HasTypeConstraint ? 1 : 0))
+ NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
+ 0, 0, nullptr, QualType(), false, nullptr);
}
NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
- unsigned NumExpandedTypes) {
+ unsigned NumExpandedTypes,
+ bool HasTypeConstraint) {
auto *NTTP =
- new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>(
- NumExpandedTypes))
+ new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+ Expr *>(
+ NumExpandedTypes, HasTypeConstraint ? 1 : 0))
NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
0, 0, nullptr, QualType(), nullptr, None,
None);
@@ -704,12 +857,6 @@ FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
}
//===----------------------------------------------------------------------===//
-// TemplateDecl Implementation
-//===----------------------------------------------------------------------===//
-
-void TemplateDecl::anchor() {}
-
-//===----------------------------------------------------------------------===//
// ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
@@ -1010,7 +1157,7 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
VarTemplateSpecializationDecl *
VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), Args, InsertPos);
+ return findSpecializationImpl(getSpecializations(), InsertPos, Args);
}
void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
@@ -1020,8 +1167,19 @@ void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
VarTemplatePartialSpecializationDecl *
VarTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args,
- void *&InsertPos) {
- return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos);
+ TemplateParameterList *TPL, void *&InsertPos) {
+ return findSpecializationImpl(getPartialSpecializations(), InsertPos, Args,
+ TPL);
+}
+
+void
+VarTemplatePartialSpecializationDecl::Profile(llvm::FoldingSetNodeID &ID,
+ ArrayRef<TemplateArgument> TemplateArgs, TemplateParameterList *TPL,
+ ASTContext &Context) {
+ ID.AddInteger(TemplateArgs.size());
+ for (const TemplateArgument &TemplateArg : TemplateArgs)
+ TemplateArg.Profile(ID, Context);
+ ProfileTemplateParameterList(Context, ID, TPL);
}
void VarTemplateDecl::AddPartialSpecialization(
@@ -1175,7 +1333,8 @@ createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) {
// typename T
auto *T = TemplateTypeParmDecl::Create(
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/1, /*Position=*/0,
- /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false);
+ /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false,
+ /*HasTypeConstraint=*/false);
T->setImplicit(true);
// T ...Ints
@@ -1200,7 +1359,8 @@ createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) {
// typename T
auto *TemplateTypeParm = TemplateTypeParmDecl::Create(
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/1,
- /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false);
+ /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false,
+ /*HasTypeConstraint=*/false);
TemplateTypeParm->setImplicit(true);
// T N
@@ -1228,7 +1388,8 @@ createTypePackElementParameterList(const ASTContext &C, DeclContext *DC) {
// typename ...T
auto *Ts = TemplateTypeParmDecl::Create(
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/1,
- /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/true);
+ /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/true,
+ /*HasTypeConstraint=*/false);
Ts->setImplicit(true);
// template <std::size_t Index, typename ...T>
@@ -1258,3 +1419,15 @@ BuiltinTemplateDecl::BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC,
: TemplateDecl(BuiltinTemplate, DC, SourceLocation(), Name,
createBuiltinTemplateParameterList(C, DC, BTK)),
BTK(BTK) {}
+
+void TypeConstraint::print(llvm::raw_ostream &OS, PrintingPolicy Policy) const {
+ if (NestedNameSpec)
+ NestedNameSpec.getNestedNameSpecifier()->print(OS, Policy);
+ ConceptName.printName(OS, Policy);
+ if (hasExplicitTemplateArgs()) {
+ OS << "<";
+ for (auto &ArgLoc : ArgsAsWritten->arguments())
+ ArgLoc.getArgument().print(Policy, OS);
+ OS << ">";
+ }
+} \ No newline at end of file
diff --git a/contrib/llvm-project/clang/lib/AST/DeclarationName.cpp b/contrib/llvm-project/clang/lib/AST/DeclarationName.cpp
index fe69c71aa3dd..4eb11bc57e52 100644
--- a/contrib/llvm-project/clang/lib/AST/DeclarationName.cpp
+++ b/contrib/llvm-project/clang/lib/AST/DeclarationName.cpp
@@ -134,7 +134,8 @@ static void printCXXConstructorDestructorName(QualType ClassType,
ClassType.print(OS, Policy);
}
-void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) {
+void DeclarationName::print(raw_ostream &OS,
+ const PrintingPolicy &Policy) const {
switch (getNameKind()) {
case DeclarationName::Identifier:
if (const IdentifierInfo *II = getAsIdentifierInfo())
@@ -447,11 +448,17 @@ bool DeclarationNameInfo::isInstantiationDependent() const {
std::string DeclarationNameInfo::getAsString() const {
std::string Result;
llvm::raw_string_ostream OS(Result);
- printName(OS);
+ OS << *this;
return OS.str();
}
-void DeclarationNameInfo::printName(raw_ostream &OS) const {
+raw_ostream &clang::operator<<(raw_ostream &OS, DeclarationNameInfo DNInfo) {
+ LangOptions LO;
+ DNInfo.printName(OS, PrintingPolicy(LangOptions()));
+ return OS;
+}
+
+void DeclarationNameInfo::printName(raw_ostream &OS, PrintingPolicy Policy) const {
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
case DeclarationName::ObjCZeroArgSelector:
@@ -461,7 +468,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
case DeclarationName::CXXDeductionGuideName:
- OS << Name;
+ Name.print(OS, Policy);
return;
case DeclarationName::CXXConstructorName:
@@ -473,13 +480,11 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
OS << "operator ";
LangOptions LO;
- LO.CPlusPlus = true;
- LO.Bool = true;
- PrintingPolicy PP(LO);
- PP.SuppressScope = true;
- OS << TInfo->getType().getAsString(PP);
+ Policy.adjustForCPlusPlus();
+ Policy.SuppressScope = true;
+ OS << TInfo->getType().getAsString(Policy);
} else
- OS << Name;
+ Name.print(OS, Policy);
return;
}
llvm_unreachable("Unexpected declaration name kind");
diff --git a/contrib/llvm-project/clang/lib/AST/Expr.cpp b/contrib/llvm-project/clang/lib/AST/Expr.cpp
index 6ef77b8aee68..fea7d606f261 100644
--- a/contrib/llvm-project/clang/lib/AST/Expr.cpp
+++ b/contrib/llvm-project/clang/lib/AST/Expr.cpp
@@ -49,7 +49,7 @@ const Expr *Expr::getBestDynamicClassTypeExpr() const {
// Step into initializer for materialized temporaries.
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) {
- E = MTE->GetTemporaryExpr();
+ E = MTE->getSubExpr();
continue;
}
@@ -85,8 +85,8 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
CE->getCastKind() == CK_UncheckedDerivedToBase) &&
E->getType()->isRecordType()) {
E = CE->getSubExpr();
- CXXRecordDecl *Derived
- = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
+ auto *Derived =
+ cast<CXXRecordDecl>(E->getType()->castAs<RecordType>()->getDecl());
Adjustments.push_back(SubobjectAdjustment(CE, Derived));
continue;
}
@@ -127,11 +127,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
return E;
}
-/// isKnownToHaveBooleanValue - Return true if this is an integer expression
-/// that is known to return 0 or 1. This happens for _Bool/bool expressions
-/// but also int expressions which are produced by things like comparisons in
-/// C.
-bool Expr::isKnownToHaveBooleanValue() const {
+bool Expr::isKnownToHaveBooleanValue(bool Semantic) const {
const Expr *E = IgnoreParens();
// If this value has _Bool type, it is obvious 0/1.
@@ -142,7 +138,7 @@ bool Expr::isKnownToHaveBooleanValue() const {
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
switch (UO->getOpcode()) {
case UO_Plus:
- return UO->getSubExpr()->isKnownToHaveBooleanValue();
+ return UO->getSubExpr()->isKnownToHaveBooleanValue(Semantic);
case UO_LNot:
return true;
default:
@@ -152,8 +148,9 @@ bool Expr::isKnownToHaveBooleanValue() const {
// Only look through implicit casts. If the user writes
// '(int) (a && b)' treat it as an arbitrary int.
+ // FIXME: Should we look through any cast expression in !Semantic mode?
if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
- return CE->getSubExpr()->isKnownToHaveBooleanValue();
+ return CE->getSubExpr()->isKnownToHaveBooleanValue(Semantic);
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
switch (BO->getOpcode()) {
@@ -172,18 +169,30 @@ bool Expr::isKnownToHaveBooleanValue() const {
case BO_Xor: // Bitwise XOR operator.
case BO_Or: // Bitwise OR operator.
// Handle things like (x==2)|(y==12).
- return BO->getLHS()->isKnownToHaveBooleanValue() &&
- BO->getRHS()->isKnownToHaveBooleanValue();
+ return BO->getLHS()->isKnownToHaveBooleanValue(Semantic) &&
+ BO->getRHS()->isKnownToHaveBooleanValue(Semantic);
case BO_Comma:
case BO_Assign:
- return BO->getRHS()->isKnownToHaveBooleanValue();
+ return BO->getRHS()->isKnownToHaveBooleanValue(Semantic);
}
}
if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E))
- return CO->getTrueExpr()->isKnownToHaveBooleanValue() &&
- CO->getFalseExpr()->isKnownToHaveBooleanValue();
+ return CO->getTrueExpr()->isKnownToHaveBooleanValue(Semantic) &&
+ CO->getFalseExpr()->isKnownToHaveBooleanValue(Semantic);
+
+ if (isa<ObjCBoolLiteralExpr>(E))
+ return true;
+
+ if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
+ return OVE->getSourceExpr()->isKnownToHaveBooleanValue(Semantic);
+
+ if (const FieldDecl *FD = E->getSourceBitField())
+ if (!Semantic && FD->getType()->isUnsignedIntegerType() &&
+ !FD->getBitWidth()->isValueDependent() &&
+ FD->getBitWidthValue(FD->getASTContext()) == 1)
+ return true;
return false;
}
@@ -1669,6 +1678,20 @@ MemberExpr *MemberExpr::Create(
MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl,
NameInfo, T, VK, OK, NOUR);
+ if (isa<FieldDecl>(MemberDecl)) {
+ DeclContext *DC = MemberDecl->getDeclContext();
+ // dyn_cast_or_null is used to handle objC variables which do not
+ // have a declaration context.
+ CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC);
+ if (RD && RD->isDependentContext() && RD->isCurrentInstantiation(DC))
+ E->setTypeDependent(T->isDependentType());
+
+ // Bitfield with value-dependent width is type-dependent.
+ FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl);
+ if (FD && FD->isBitField() && FD->getBitWidth()->isValueDependent())
+ E->setTypeDependent(true);
+ }
+
if (HasQualOrFound) {
// FIXME: Wrong. We should be looking at the member declaration we found.
if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) {
@@ -1805,7 +1828,7 @@ bool CastExpr::CastConsistency() const {
auto Ty = getType();
auto SETy = getSubExpr()->getType();
assert(getValueKindForType(Ty) == Expr::getValueKindForType(SETy));
- if (/*isRValue()*/ !Ty->getPointeeType().isNull()) {
+ if (isRValue()) {
Ty = Ty->getPointeeType();
SETy = SETy->getPointeeType();
}
@@ -1885,7 +1908,7 @@ namespace {
const Expr *skipImplicitTemporary(const Expr *E) {
// Skip through reference binding to temporary.
if (auto *Materialize = dyn_cast<MaterializeTemporaryExpr>(E))
- E = Materialize->GetTemporaryExpr();
+ E = Materialize->getSubExpr();
// Skip any temporary bindings; they're implicit.
if (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
@@ -2563,13 +2586,31 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case CXXTemporaryObjectExprClass:
case CXXConstructExprClass: {
if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) {
- if (Type->hasAttr<WarnUnusedAttr>()) {
+ const auto *WarnURAttr = Type->getAttr<WarnUnusedResultAttr>();
+ if (Type->hasAttr<WarnUnusedAttr>() ||
+ (WarnURAttr && WarnURAttr->IsCXX11NoDiscard())) {
+ WarnE = this;
+ Loc = getBeginLoc();
+ R1 = getSourceRange();
+ return true;
+ }
+ }
+
+ const auto *CE = cast<CXXConstructExpr>(this);
+ if (const CXXConstructorDecl *Ctor = CE->getConstructor()) {
+ const auto *WarnURAttr = Ctor->getAttr<WarnUnusedResultAttr>();
+ if (WarnURAttr && WarnURAttr->IsCXX11NoDiscard()) {
WarnE = this;
Loc = getBeginLoc();
R1 = getSourceRange();
+
+ if (unsigned NumArgs = CE->getNumArgs())
+ R2 = SourceRange(CE->getArg(0)->getBeginLoc(),
+ CE->getArg(NumArgs - 1)->getEndLoc());
return true;
}
}
+
return false;
}
@@ -2697,8 +2738,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case CXXDeleteExprClass:
return false;
case MaterializeTemporaryExprClass:
- return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
- ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
+ return cast<MaterializeTemporaryExpr>(this)
+ ->getSubExpr()
+ ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
case CXXBindTemporaryExprClass:
return cast<CXXBindTemporaryExpr>(this)->getSubExpr()
->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
@@ -2722,8 +2764,8 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
case ImplicitCastExprClass:
return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case MaterializeTemporaryExprClass:
- return cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr()
- ->isOBJCGCCandidate(Ctx);
+ return cast<MaterializeTemporaryExpr>(E)->getSubExpr()->isOBJCGCCandidate(
+ Ctx);
case CStyleCastExprClass:
return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case DeclRefExprClass: {
@@ -2798,7 +2840,7 @@ static Expr *IgnoreImpCastsExtraSingleStep(Expr *E) {
return SubE;
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
- return MTE->GetTemporaryExpr();
+ return MTE->getSubExpr();
if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
return NTTP->getReplacement();
@@ -2814,7 +2856,7 @@ static Expr *IgnoreCastsSingleStep(Expr *E) {
return FE->getSubExpr();
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
- return MTE->GetTemporaryExpr();
+ return MTE->getSubExpr();
if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
return NTTP->getReplacement();
@@ -2848,7 +2890,7 @@ static Expr *IgnoreImplicitSingleStep(Expr *E) {
return SubE;
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
- return MTE->GetTemporaryExpr();
+ return MTE->getSubExpr();
if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
return BTE->getSubExpr();
@@ -2856,6 +2898,13 @@ static Expr *IgnoreImplicitSingleStep(Expr *E) {
return E;
}
+static Expr *IgnoreImplicitAsWrittenSingleStep(Expr *E) {
+ if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+ return ICE->getSubExprAsWritten();
+
+ return IgnoreImplicitSingleStep(E);
+}
+
static Expr *IgnoreParensSingleStep(Expr *E) {
if (auto *PE = dyn_cast<ParenExpr>(E))
return PE->getSubExpr();
@@ -2935,6 +2984,10 @@ Expr *Expr::IgnoreImplicit() {
return IgnoreExprNodes(this, IgnoreImplicitSingleStep);
}
+Expr *Expr::IgnoreImplicitAsWritten() {
+ return IgnoreExprNodes(this, IgnoreImplicitAsWrittenSingleStep);
+}
+
Expr *Expr::IgnoreParens() {
return IgnoreExprNodes(this, IgnoreParensSingleStep);
}
@@ -2972,10 +3025,38 @@ Expr *Expr::IgnoreParenNoopCasts(const ASTContext &Ctx) {
});
}
+Expr *Expr::IgnoreUnlessSpelledInSource() {
+ Expr *E = this;
+
+ Expr *LastE = nullptr;
+ while (E != LastE) {
+ LastE = E;
+ E = E->IgnoreParenImpCasts();
+
+ auto SR = E->getSourceRange();
+
+ if (auto *C = dyn_cast<CXXConstructExpr>(E)) {
+ if (C->getNumArgs() == 1) {
+ Expr *A = C->getArg(0);
+ if (A->getSourceRange() == SR || !isa<CXXTemporaryObjectExpr>(C))
+ E = A;
+ }
+ }
+
+ if (auto *C = dyn_cast<CXXMemberCallExpr>(E)) {
+ Expr *ExprNode = C->getImplicitObjectArgument()->IgnoreParenImpCasts();
+ if (ExprNode->getSourceRange() == SR)
+ E = ExprNode;
+ }
+ }
+
+ return E;
+}
+
bool Expr::isDefaultArgument() const {
const Expr *E = this;
if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E))
- E = M->GetTemporaryExpr();
+ E = M->getSubExpr();
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
E = ICE->getSubExprAsWritten();
@@ -2987,7 +3068,7 @@ bool Expr::isDefaultArgument() const {
/// expressions.
static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) {
if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E))
- E = M->GetTemporaryExpr();
+ E = M->getSubExpr();
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() == CK_NoOp)
@@ -3082,7 +3163,7 @@ bool Expr::isImplicitCXXThis() const {
if (const MaterializeTemporaryExpr *M
= dyn_cast<MaterializeTemporaryExpr>(E)) {
- E = M->GetTemporaryExpr();
+ E = M->getSubExpr();
continue;
}
@@ -3181,7 +3262,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
if (ILE->getType()->isRecordType()) {
unsigned ElementNo = 0;
- RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = ILE->getType()->castAs<RecordType>()->getDecl();
for (const auto *Field : RD->fields()) {
// If this is a union, skip all the fields that aren't being initialized.
if (RD->isUnion() && ILE->getInitializedFieldInUnion() != Field)
@@ -3259,8 +3340,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
break;
}
case MaterializeTemporaryExprClass:
- return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
- ->isConstantInitializer(Ctx, false, Culprit);
+ return cast<MaterializeTemporaryExpr>(this)
+ ->getSubExpr()
+ ->isConstantInitializer(Ctx, false, Culprit);
case SubstNonTypeTemplateParmExprClass:
return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement()
@@ -3379,6 +3461,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case CXXUuidofExprClass:
case OpaqueValueExprClass:
case SourceLocExprClass:
+ case ConceptSpecializationExprClass:
+ case RequiresExprClass:
// These never have a side-effect.
return false;
@@ -3448,6 +3532,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case ArrayInitLoopExprClass:
case ParenListExprClass:
case CXXPseudoDestructorExprClass:
+ case CXXRewrittenBinaryOperatorClass:
case CXXStdInitializerListExprClass:
case SubstNonTypeTemplateParmExprClass:
case MaterializeTemporaryExprClass:
@@ -3725,7 +3810,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return NPCK_GNUNull;
} else if (const MaterializeTemporaryExpr *M
= dyn_cast<MaterializeTemporaryExpr>(this)) {
- return M->GetTemporaryExpr()->isNullPointerConstant(Ctx, NPC);
+ return M->getSubExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(this)) {
if (const Expr *Source = OVE->getSourceExpr())
return Source->isNullPointerConstant(Ctx, NPC);
@@ -3897,6 +3982,112 @@ bool Expr::refersToGlobalRegisterVar() const {
return false;
}
+bool Expr::isSameComparisonOperand(const Expr* E1, const Expr* E2) {
+ E1 = E1->IgnoreParens();
+ E2 = E2->IgnoreParens();
+
+ if (E1->getStmtClass() != E2->getStmtClass())
+ return false;
+
+ switch (E1->getStmtClass()) {
+ default:
+ return false;
+ case CXXThisExprClass:
+ return true;
+ case DeclRefExprClass: {
+ // DeclRefExpr without an ImplicitCastExpr can happen for integral
+ // template parameters.
+ const auto *DRE1 = cast<DeclRefExpr>(E1);
+ const auto *DRE2 = cast<DeclRefExpr>(E2);
+ return DRE1->isRValue() && DRE2->isRValue() &&
+ DRE1->getDecl() == DRE2->getDecl();
+ }
+ case ImplicitCastExprClass: {
+ // Peel off implicit casts.
+ while (true) {
+ const auto *ICE1 = dyn_cast<ImplicitCastExpr>(E1);
+ const auto *ICE2 = dyn_cast<ImplicitCastExpr>(E2);
+ if (!ICE1 || !ICE2)
+ return false;
+ if (ICE1->getCastKind() != ICE2->getCastKind())
+ return false;
+ E1 = ICE1->getSubExpr()->IgnoreParens();
+ E2 = ICE2->getSubExpr()->IgnoreParens();
+ // The final cast must be one of these types.
+ if (ICE1->getCastKind() == CK_LValueToRValue ||
+ ICE1->getCastKind() == CK_ArrayToPointerDecay ||
+ ICE1->getCastKind() == CK_FunctionToPointerDecay) {
+ break;
+ }
+ }
+
+ const auto *DRE1 = dyn_cast<DeclRefExpr>(E1);
+ const auto *DRE2 = dyn_cast<DeclRefExpr>(E2);
+ if (DRE1 && DRE2)
+ return declaresSameEntity(DRE1->getDecl(), DRE2->getDecl());
+
+ const auto *Ivar1 = dyn_cast<ObjCIvarRefExpr>(E1);
+ const auto *Ivar2 = dyn_cast<ObjCIvarRefExpr>(E2);
+ if (Ivar1 && Ivar2) {
+ return Ivar1->isFreeIvar() && Ivar2->isFreeIvar() &&
+ declaresSameEntity(Ivar1->getDecl(), Ivar2->getDecl());
+ }
+
+ const auto *Array1 = dyn_cast<ArraySubscriptExpr>(E1);
+ const auto *Array2 = dyn_cast<ArraySubscriptExpr>(E2);
+ if (Array1 && Array2) {
+ if (!isSameComparisonOperand(Array1->getBase(), Array2->getBase()))
+ return false;
+
+ auto Idx1 = Array1->getIdx();
+ auto Idx2 = Array2->getIdx();
+ const auto Integer1 = dyn_cast<IntegerLiteral>(Idx1);
+ const auto Integer2 = dyn_cast<IntegerLiteral>(Idx2);
+ if (Integer1 && Integer2) {
+ if (!llvm::APInt::isSameValue(Integer1->getValue(),
+ Integer2->getValue()))
+ return false;
+ } else {
+ if (!isSameComparisonOperand(Idx1, Idx2))
+ return false;
+ }
+
+ return true;
+ }
+
+ // Walk the MemberExpr chain.
+ while (isa<MemberExpr>(E1) && isa<MemberExpr>(E2)) {
+ const auto *ME1 = cast<MemberExpr>(E1);
+ const auto *ME2 = cast<MemberExpr>(E2);
+ if (!declaresSameEntity(ME1->getMemberDecl(), ME2->getMemberDecl()))
+ return false;
+ if (const auto *D = dyn_cast<VarDecl>(ME1->getMemberDecl()))
+ if (D->isStaticDataMember())
+ return true;
+ E1 = ME1->getBase()->IgnoreParenImpCasts();
+ E2 = ME2->getBase()->IgnoreParenImpCasts();
+ }
+
+ if (isa<CXXThisExpr>(E1) && isa<CXXThisExpr>(E2))
+ return true;
+
+ // A static member variable can end the MemberExpr chain with either
+ // a MemberExpr or a DeclRefExpr.
+ auto getAnyDecl = [](const Expr *E) -> const ValueDecl * {
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
+ return DRE->getDecl();
+ if (const auto *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl();
+ return nullptr;
+ };
+
+ const ValueDecl *VD1 = getAnyDecl(E1);
+ const ValueDecl *VD2 = getAnyDecl(E2);
+ return declaresSameEntity(VD1, VD2);
+ }
+ }
+}
+
/// isArrow - Return true if the base expression is a pointer to vector,
/// return false if the base expression is a vector.
bool ExtVectorElementExpr::isArrow() const {
@@ -4328,7 +4519,7 @@ const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
e = ewc->getSubExpr();
if (const MaterializeTemporaryExpr *m = dyn_cast<MaterializeTemporaryExpr>(e))
- e = m->GetTemporaryExpr();
+ e = m->getSubExpr();
e = cast<CXXConstructExpr>(e)->getArg(0);
while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
e = ice->getSubExpr();
@@ -4466,6 +4657,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
case AO__c11_atomic_fetch_and:
case AO__c11_atomic_fetch_or:
case AO__c11_atomic_fetch_xor:
+ case AO__c11_atomic_fetch_max:
+ case AO__c11_atomic_fetch_min:
case AO__atomic_fetch_add:
case AO__atomic_fetch_sub:
case AO__atomic_fetch_and:
@@ -4478,6 +4671,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
case AO__atomic_or_fetch:
case AO__atomic_xor_fetch:
case AO__atomic_nand_fetch:
+ case AO__atomic_min_fetch:
+ case AO__atomic_max_fetch:
case AO__atomic_fetch_min:
case AO__atomic_fetch_max:
return 3;
diff --git a/contrib/llvm-project/clang/lib/AST/ExprCXX.cpp b/contrib/llvm-project/clang/lib/AST/ExprCXX.cpp
index c5f86a4cc12b..e4bd218ae2d3 100644
--- a/contrib/llvm-project/clang/lib/AST/ExprCXX.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ExprCXX.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclAccessPair.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/LambdaCapture.h"
@@ -58,6 +59,76 @@ bool CXXOperatorCallExpr::isInfixBinaryOp() const {
}
}
+CXXRewrittenBinaryOperator::DecomposedForm
+CXXRewrittenBinaryOperator::getDecomposedForm() const {
+ DecomposedForm Result = {};
+ const Expr *E = getSemanticForm()->IgnoreImplicit();
+
+ // Remove an outer '!' if it exists (only happens for a '!=' rewrite).
+ bool SkippedNot = false;
+ if (auto *NotEq = dyn_cast<UnaryOperator>(E)) {
+ assert(NotEq->getOpcode() == UO_LNot);
+ E = NotEq->getSubExpr()->IgnoreImplicit();
+ SkippedNot = true;
+ }
+
+ // Decompose the outer binary operator.
+ if (auto *BO = dyn_cast<BinaryOperator>(E)) {
+ assert(!SkippedNot || BO->getOpcode() == BO_EQ);
+ Result.Opcode = SkippedNot ? BO_NE : BO->getOpcode();
+ Result.LHS = BO->getLHS();
+ Result.RHS = BO->getRHS();
+ Result.InnerBinOp = BO;
+ } else if (auto *BO = dyn_cast<CXXOperatorCallExpr>(E)) {
+ assert(!SkippedNot || BO->getOperator() == OO_EqualEqual);
+ assert(BO->isInfixBinaryOp());
+ switch (BO->getOperator()) {
+ case OO_Less: Result.Opcode = BO_LT; break;
+ case OO_LessEqual: Result.Opcode = BO_LE; break;
+ case OO_Greater: Result.Opcode = BO_GT; break;
+ case OO_GreaterEqual: Result.Opcode = BO_GE; break;
+ case OO_Spaceship: Result.Opcode = BO_Cmp; break;
+ case OO_EqualEqual: Result.Opcode = SkippedNot ? BO_NE : BO_EQ; break;
+ default: llvm_unreachable("unexpected binop in rewritten operator expr");
+ }
+ Result.LHS = BO->getArg(0);
+ Result.RHS = BO->getArg(1);
+ Result.InnerBinOp = BO;
+ } else {
+ llvm_unreachable("unexpected rewritten operator form");
+ }
+
+ // Put the operands in the right order for == and !=, and canonicalize the
+ // <=> subexpression onto the LHS for all other forms.
+ if (isReversed())
+ std::swap(Result.LHS, Result.RHS);
+
+ // If this isn't a spaceship rewrite, we're done.
+ if (Result.Opcode == BO_EQ || Result.Opcode == BO_NE)
+ return Result;
+
+ // Otherwise, we expect a <=> to now be on the LHS.
+ E = Result.LHS->IgnoreImplicitAsWritten();
+ if (auto *BO = dyn_cast<BinaryOperator>(E)) {
+ assert(BO->getOpcode() == BO_Cmp);
+ Result.LHS = BO->getLHS();
+ Result.RHS = BO->getRHS();
+ Result.InnerBinOp = BO;
+ } else if (auto *BO = dyn_cast<CXXOperatorCallExpr>(E)) {
+ assert(BO->getOperator() == OO_Spaceship);
+ Result.LHS = BO->getArg(0);
+ Result.RHS = BO->getArg(1);
+ Result.InnerBinOp = BO;
+ } else {
+ llvm_unreachable("unexpected rewritten operator form");
+ }
+
+ // Put the comparison operands in the right order.
+ if (isReversed())
+ std::swap(Result.LHS, Result.RHS);
+ return Result;
+}
+
bool CXXTypeidExpr::isPotentiallyEvaluated() const {
if (isTypeOperand())
return false;
@@ -124,6 +195,8 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
if (ArraySize) {
if (Expr *SizeExpr = *ArraySize) {
+ if (SizeExpr->isValueDependent())
+ ExprBits.ValueDependent = true;
if (SizeExpr->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (SizeExpr->containsUnexpandedParameterPack())
@@ -134,6 +207,8 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
}
if (Initializer) {
+ if (Initializer->isValueDependent())
+ ExprBits.ValueDependent = true;
if (Initializer->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (Initializer->containsUnexpandedParameterPack())
@@ -143,6 +218,8 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
}
for (unsigned I = 0; I != PlacementArgs.size(); ++I) {
+ if (PlacementArgs[I]->isValueDependent())
+ ExprBits.ValueDependent = true;
if (PlacementArgs[I]->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (PlacementArgs[I]->containsUnexpandedParameterPack())
@@ -245,7 +322,7 @@ QualType CXXDeleteExpr::getDestroyedType() const {
if (ArgType->isDependentType() && !ArgType->isPointerType())
return QualType();
- return ArgType->getAs<PointerType>()->getPointeeType();
+ return ArgType->castAs<PointerType>()->getPointeeType();
}
// CXXPseudoDestructorExpr
@@ -1212,6 +1289,11 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const {
return Record->getLambdaCallOperator();
}
+FunctionTemplateDecl *LambdaExpr::getDependentCallOperator() const {
+ CXXRecordDecl *Record = getLambdaClass();
+ return Record->getDependentLambdaCallOperator();
+}
+
TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
CXXRecordDecl *Record = getLambdaClass();
return Record->getGenericLambdaTemplateParameterList();
@@ -1501,11 +1583,8 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() {
// Otherwise the naming class must have been the base class.
else {
QualType BaseType = getBaseType().getNonReferenceType();
- if (isArrow()) {
- const auto *PT = BaseType->getAs<PointerType>();
- assert(PT && "base of arrow member access is not pointer");
- BaseType = PT->getPointeeType();
- }
+ if (isArrow())
+ BaseType = BaseType->castAs<PointerType>()->getPointeeType();
Record = BaseType->getAsCXXRecordDecl();
assert(Record && "base of member expression does not name record");
@@ -1575,7 +1654,23 @@ FunctionParmPackExpr::CreateEmpty(const ASTContext &Context,
FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr);
}
-void MaterializeTemporaryExpr::setExtendingDecl(const ValueDecl *ExtendedBy,
+MaterializeTemporaryExpr::MaterializeTemporaryExpr(
+ QualType T, Expr *Temporary, bool BoundToLvalueReference,
+ LifetimeExtendedTemporaryDecl *MTD)
+ : Expr(MaterializeTemporaryExprClass, T,
+ BoundToLvalueReference ? VK_LValue : VK_XValue, OK_Ordinary,
+ Temporary->isTypeDependent(), Temporary->isValueDependent(),
+ Temporary->isInstantiationDependent(),
+ Temporary->containsUnexpandedParameterPack()) {
+ if (MTD) {
+ State = MTD;
+ MTD->ExprWithTemporary = Temporary;
+ return;
+ }
+ State = Temporary;
+}
+
+void MaterializeTemporaryExpr::setExtendingDecl(ValueDecl *ExtendedBy,
unsigned ManglingNumber) {
// We only need extra state if we have to remember more than just the Stmt.
if (!ExtendedBy)
@@ -1583,13 +1678,11 @@ void MaterializeTemporaryExpr::setExtendingDecl(const ValueDecl *ExtendedBy,
// We may need to allocate extra storage for the mangling number and the
// extended-by ValueDecl.
- if (!State.is<ExtraState *>()) {
- auto *ES = new (ExtendedBy->getASTContext()) ExtraState;
- ES->Temporary = State.get<Stmt *>();
- State = ES;
- }
+ if (!State.is<LifetimeExtendedTemporaryDecl *>())
+ State = LifetimeExtendedTemporaryDecl::Create(
+ cast<Expr>(State.get<Stmt *>()), ExtendedBy, ManglingNumber);
- auto ES = State.get<ExtraState *>();
+ auto ES = State.get<LifetimeExtendedTemporaryDecl *>();
ES->ExtendingDecl = ExtendedBy;
ES->ManglingNumber = ManglingNumber;
}
diff --git a/contrib/llvm-project/clang/lib/AST/ExprClassification.cpp b/contrib/llvm-project/clang/lib/AST/ExprClassification.cpp
index c61ee703aca8..d201af31f521 100644
--- a/contrib/llvm-project/clang/lib/AST/ExprClassification.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ExprClassification.cpp
@@ -192,6 +192,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::NoInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
case Expr::SourceLocExprClass:
+ case Expr::ConceptSpecializationExprClass:
+ case Expr::RequiresExprClass:
return Cl::CL_PRValue;
case Expr::ConstantExprClass:
@@ -306,6 +308,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CUDAKernelCallExprClass:
return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType(Ctx));
+ case Expr::CXXRewrittenBinaryOperatorClass:
+ return ClassifyInternal(
+ Ctx, cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm());
+
// __builtin_choose_expr is equivalent to the chosen expression.
case Expr::ChooseExprClass:
return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr());
diff --git a/contrib/llvm-project/clang/lib/AST/ExprConcepts.cpp b/contrib/llvm-project/clang/lib/AST/ExprConcepts.cpp
new file mode 100644
index 000000000000..b5a3686dc99a
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/ExprConcepts.cpp
@@ -0,0 +1,218 @@
+//===- ExprCXX.cpp - (C++) Expression AST Node Implementation -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the subclesses of Expr class declared in ExprCXX.h
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ExprConcepts.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConcept.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/TrailingObjects.h"
+#include <algorithm>
+#include <utility>
+#include <string>
+
+using namespace clang;
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C,
+ NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
+ DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ const ConstraintSatisfaction *Satisfaction)
+ : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
+ /*TypeDependent=*/false,
+ // All the flags below are set in setTemplateArguments.
+ /*ValueDependent=*/!Satisfaction, /*InstantiationDependent=*/false,
+ /*ContainsUnexpandedParameterPacks=*/false),
+ ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
+ NamedConcept, ArgsAsWritten),
+ NumTemplateArgs(ConvertedArgs.size()),
+ Satisfaction(Satisfaction ?
+ ASTConstraintSatisfaction::Create(C, *Satisfaction) :
+ nullptr) {
+ setTemplateArguments(ConvertedArgs);
+ bool IsInstantiationDependent = false;
+ bool ContainsUnexpandedParameterPack = false;
+ for (const TemplateArgumentLoc& ArgLoc : ArgsAsWritten->arguments()) {
+ if (ArgLoc.getArgument().isInstantiationDependent())
+ IsInstantiationDependent = true;
+ if (ArgLoc.getArgument().containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+ if (ContainsUnexpandedParameterPack && IsInstantiationDependent)
+ break;
+ }
+
+ // Currently guaranteed by the fact concepts can only be at namespace-scope.
+ assert(!NestedNameSpec ||
+ (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() &&
+ !NestedNameSpec.getNestedNameSpecifier()
+ ->containsUnexpandedParameterPack()));
+ setInstantiationDependent(IsInstantiationDependent);
+ setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
+ assert((!isValueDependent() || isInstantiationDependent()) &&
+ "should not be value-dependent");
+}
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
+ unsigned NumTemplateArgs)
+ : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
+ NumTemplateArgs(NumTemplateArgs) { }
+
+void ConceptSpecializationExpr::setTemplateArguments(
+ ArrayRef<TemplateArgument> Converted) {
+ assert(Converted.size() == NumTemplateArgs);
+ std::uninitialized_copy(Converted.begin(), Converted.end(),
+ getTrailingObjects<TemplateArgument>());
+}
+
+ConceptSpecializationExpr *
+ConceptSpecializationExpr::Create(const ASTContext &C,
+ NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc,
+ DeclarationNameInfo ConceptNameInfo,
+ NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ const ConstraintSatisfaction *Satisfaction) {
+ void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
+ ConvertedArgs.size()));
+ return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
+ ConceptNameInfo, FoundDecl,
+ NamedConcept, ArgsAsWritten,
+ ConvertedArgs, Satisfaction);
+}
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(
+ const ASTContext &C, ConceptDecl *NamedConcept,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ const ConstraintSatisfaction *Satisfaction, bool Dependent,
+ bool ContainsUnexpandedParameterPack)
+ : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
+ /*TypeDependent=*/false,
+ /*ValueDependent=*/!Satisfaction, Dependent,
+ ContainsUnexpandedParameterPack),
+ ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
+ DeclarationNameInfo(), NamedConcept,
+ NamedConcept, nullptr),
+ NumTemplateArgs(ConvertedArgs.size()),
+ Satisfaction(Satisfaction ?
+ ASTConstraintSatisfaction::Create(C, *Satisfaction) :
+ nullptr) {
+ setTemplateArguments(ConvertedArgs);
+}
+
+ConceptSpecializationExpr *
+ConceptSpecializationExpr::Create(const ASTContext &C,
+ ConceptDecl *NamedConcept,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ const ConstraintSatisfaction *Satisfaction,
+ bool Dependent,
+ bool ContainsUnexpandedParameterPack) {
+ void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
+ ConvertedArgs.size()));
+ return new (Buffer) ConceptSpecializationExpr(
+ C, NamedConcept, ConvertedArgs, Satisfaction, Dependent,
+ ContainsUnexpandedParameterPack);
+}
+
+ConceptSpecializationExpr *
+ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
+ unsigned NumTemplateArgs) {
+ void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
+ NumTemplateArgs));
+ return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
+}
+
+const TypeConstraint *
+concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
+ assert(isTypeConstraint());
+ auto TPL =
+ TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
+ return cast<TemplateTypeParmDecl>(TPL->getParam(0))
+ ->getTypeConstraint();
+}
+
+RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation RBraceLoc)
+ : Expr(RequiresExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
+ /*TD=*/false, /*VD=*/false, /*ID=*/false,
+ /*ContainsUnexpandedParameterPack=*/false),
+ NumLocalParameters(LocalParameters.size()),
+ NumRequirements(Requirements.size()), Body(Body), RBraceLoc(RBraceLoc) {
+ RequiresExprBits.IsSatisfied = false;
+ RequiresExprBits.RequiresKWLoc = RequiresKWLoc;
+ bool Dependent = false;
+ bool ContainsUnexpandedParameterPack = false;
+ for (ParmVarDecl *P : LocalParameters) {
+ Dependent |= P->getType()->isInstantiationDependentType();
+ ContainsUnexpandedParameterPack |=
+ P->getType()->containsUnexpandedParameterPack();
+ }
+ RequiresExprBits.IsSatisfied = true;
+ for (concepts::Requirement *R : Requirements) {
+ Dependent |= R->isDependent();
+ ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack();
+ if (!Dependent) {
+ RequiresExprBits.IsSatisfied = R->isSatisfied();
+ if (!RequiresExprBits.IsSatisfied)
+ break;
+ }
+ }
+ std::copy(LocalParameters.begin(), LocalParameters.end(),
+ getTrailingObjects<ParmVarDecl *>());
+ std::copy(Requirements.begin(), Requirements.end(),
+ getTrailingObjects<concepts::Requirement *>());
+ RequiresExprBits.IsSatisfied |= Dependent;
+ setValueDependent(Dependent);
+ setInstantiationDependent(Dependent);
+ setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
+}
+
+RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
+ unsigned NumLocalParameters,
+ unsigned NumRequirements)
+ : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
+ NumRequirements(NumRequirements) { }
+
+RequiresExpr *
+RequiresExpr::Create(ASTContext &C, SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation RBraceLoc) {
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
+ LocalParameters.size(), Requirements.size()),
+ alignof(RequiresExpr));
+ return new (Mem) RequiresExpr(C, RequiresKWLoc, Body, LocalParameters,
+ Requirements, RBraceLoc);
+}
+
+RequiresExpr *
+RequiresExpr::Create(ASTContext &C, EmptyShell Empty,
+ unsigned NumLocalParameters, unsigned NumRequirements) {
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
+ NumLocalParameters, NumRequirements),
+ alignof(RequiresExpr));
+ return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements);
+}
diff --git a/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp b/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp
index e4d4c8885ac9..c3ebe08cba05 100644
--- a/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp
@@ -32,15 +32,20 @@
//
//===----------------------------------------------------------------------===//
+#include "Interp/Context.h"
+#include "Interp/Frame.h"
+#include "Interp/State.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTLambda.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CurrentSourceLocExprScope.h"
-#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/OSLog.h"
+#include "clang/AST/OptionalDiagnostic.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
@@ -62,12 +67,10 @@ using llvm::APSInt;
using llvm::APFloat;
using llvm::Optional;
-static bool IsGlobalLValue(APValue::LValueBase B);
-
namespace {
struct LValue;
- struct CallStackFrame;
- struct EvalInfo;
+ class CallStackFrame;
+ class EvalInfo;
using SourceLocExprScopeGuard =
CurrentSourceLocExprScope::SourceLocExprScopeGuard;
@@ -94,6 +97,9 @@ namespace {
if (B.is<TypeInfoLValue>())
return B.getTypeInfoType();
+ if (B.is<DynamicAllocLValue>())
+ return B.getDynamicAllocType();
+
const Expr *Base = B.get<const Expr*>();
// For a materialized temporary, the type of the temporary we materialized
@@ -102,7 +108,7 @@ namespace {
dyn_cast<MaterializeTemporaryExpr>(Base)) {
SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
- const Expr *Temp = MTE->GetTemporaryExpr();
+ const Expr *Temp = MTE->getSubExpr();
const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs,
Adjustments);
// Keep any cv-qualifiers from the reference if we generated a temporary
@@ -130,6 +136,14 @@ namespace {
return E.getAsBaseOrMember().getInt();
}
+ /// Given an expression, determine the type used to store the result of
+ /// evaluating that expression.
+ static QualType getStorageType(const ASTContext &Ctx, const Expr *E) {
+ if (E->isRValue())
+ return E->getType();
+ return Ctx.getLValueReferenceType(E->getType());
+ }
+
/// Given a CallExpr, try to get the alloc_size attribute. May return null.
static const AllocSizeAttr *getAllocSizeAttr(const CallExpr *CE) {
const FunctionDecl *Callee = CE->getDirectCallee();
@@ -222,12 +236,6 @@ namespace {
return MostDerivedLength;
}
- // The order of this enum is important for diagnostics.
- enum CheckSubobjectKind {
- CSK_Base, CSK_Derived, CSK_Field, CSK_ArrayToPointer, CSK_ArrayIndex,
- CSK_Real, CSK_Imag
- };
-
/// A path from a glvalue to a subobject of that glvalue.
struct SubobjectDesignator {
/// True if the subobject was named in a manner not supported by C++11. Such
@@ -480,7 +488,8 @@ namespace {
};
/// A stack frame in the constexpr call stack.
- struct CallStackFrame {
+ class CallStackFrame : public interp::Frame {
+ public:
EvalInfo &Info;
/// Parent - The caller of this stack frame.
@@ -573,7 +582,26 @@ namespace {
return 0;
}
- APValue &createTemporary(const void *Key, bool IsLifetimeExtended);
+ /// Allocate storage for an object of type T in this stack frame.
+ /// Populates LV with a handle to the created object. Key identifies
+ /// the temporary within the stack frame, and must not be reused without
+ /// bumping the temporary version number.
+ template<typename KeyT>
+ APValue &createTemporary(const KeyT *Key, QualType T,
+ bool IsLifetimeExtended, LValue &LV);
+
+ void describe(llvm::raw_ostream &OS) override;
+
+ Frame *getCaller() const override { return Caller; }
+ SourceLocation getCallLocation() const override { return CallLoc; }
+ const FunctionDecl *getCallee() const override { return Callee; }
+
+ bool isStdFunction() const {
+ for (const DeclContext *DC = Callee; DC; DC = DC->getParent())
+ if (DC->isStdNamespace())
+ return true;
+ return false;
+ }
};
/// Temporarily override 'this'.
@@ -591,71 +619,42 @@ namespace {
CallStackFrame &Frame;
const LValue *OldThis;
};
+}
- /// A partial diagnostic which we might know in advance that we are not going
- /// to emit.
- class OptionalDiagnostic {
- PartialDiagnostic *Diag;
-
- public:
- explicit OptionalDiagnostic(PartialDiagnostic *Diag = nullptr)
- : Diag(Diag) {}
-
- template<typename T>
- OptionalDiagnostic &operator<<(const T &v) {
- if (Diag)
- *Diag << v;
- return *this;
- }
-
- OptionalDiagnostic &operator<<(const APSInt &I) {
- if (Diag) {
- SmallVector<char, 32> Buffer;
- I.toString(Buffer);
- *Diag << StringRef(Buffer.data(), Buffer.size());
- }
- return *this;
- }
-
- OptionalDiagnostic &operator<<(const APFloat &F) {
- if (Diag) {
- // FIXME: Force the precision of the source value down so we don't
- // print digits which are usually useless (we don't really care here if
- // we truncate a digit by accident in edge cases). Ideally,
- // APFloat::toString would automatically print the shortest
- // representation which rounds to the correct value, but it's a bit
- // tricky to implement.
- unsigned precision =
- llvm::APFloat::semanticsPrecision(F.getSemantics());
- precision = (precision * 59 + 195) / 196;
- SmallVector<char, 32> Buffer;
- F.toString(Buffer, precision);
- *Diag << StringRef(Buffer.data(), Buffer.size());
- }
- return *this;
- }
-
- OptionalDiagnostic &operator<<(const APFixedPoint &FX) {
- if (Diag) {
- SmallVector<char, 32> Buffer;
- FX.toString(Buffer);
- *Diag << StringRef(Buffer.data(), Buffer.size());
- }
- return *this;
- }
- };
+static bool HandleDestruction(EvalInfo &Info, const Expr *E,
+ const LValue &This, QualType ThisType);
+static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc,
+ APValue::LValueBase LVBase, APValue &Value,
+ QualType T);
+namespace {
/// A cleanup, and a flag indicating whether it is lifetime-extended.
class Cleanup {
llvm::PointerIntPair<APValue*, 1, bool> Value;
+ APValue::LValueBase Base;
+ QualType T;
public:
- Cleanup(APValue *Val, bool IsLifetimeExtended)
- : Value(Val, IsLifetimeExtended) {}
+ Cleanup(APValue *Val, APValue::LValueBase Base, QualType T,
+ bool IsLifetimeExtended)
+ : Value(Val, IsLifetimeExtended), Base(Base), T(T) {}
bool isLifetimeExtended() const { return Value.getInt(); }
- void endLifetime() {
+ bool endLifetime(EvalInfo &Info, bool RunDestructors) {
+ if (RunDestructors) {
+ SourceLocation Loc;
+ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
+ Loc = VD->getLocation();
+ else if (const Expr *E = Base.dyn_cast<const Expr*>())
+ Loc = E->getExprLoc();
+ return HandleDestruction(Info, Loc, Base, *Value.getPointer(), T);
+ }
*Value.getPointer() = APValue();
+ return true;
+ }
+
+ bool hasSideEffect() {
+ return T.isDestructedType();
}
};
@@ -671,7 +670,13 @@ namespace {
return llvm::hash_combine(Obj.Base, Obj.Path);
}
};
- enum class ConstructionPhase { None, Bases, AfterBases };
+ enum class ConstructionPhase {
+ None,
+ Bases,
+ AfterBases,
+ Destroying,
+ DestroyingBases
+ };
}
namespace llvm {
@@ -693,6 +698,37 @@ template<> struct DenseMapInfo<ObjectUnderConstruction> {
}
namespace {
+ /// A dynamically-allocated heap object.
+ struct DynAlloc {
+ /// The value of this heap-allocated object.
+ APValue Value;
+ /// The allocating expression; used for diagnostics. Either a CXXNewExpr
+ /// or a CallExpr (the latter is for direct calls to operator new inside
+ /// std::allocator<T>::allocate).
+ const Expr *AllocExpr = nullptr;
+
+ enum Kind {
+ New,
+ ArrayNew,
+ StdAllocator
+ };
+
+ /// Get the kind of the allocation. This must match between allocation
+ /// and deallocation.
+ Kind getKind() const {
+ if (auto *NE = dyn_cast<CXXNewExpr>(AllocExpr))
+ return NE->isArray() ? ArrayNew : New;
+ assert(isa<CallExpr>(AllocExpr));
+ return StdAllocator;
+ }
+ };
+
+ struct DynAllocOrder {
+ bool operator()(DynamicAllocLValue L, DynamicAllocLValue R) const {
+ return L.getIndex() < R.getIndex();
+ }
+ };
+
/// EvalInfo - This is a private struct used by the evaluator to capture
/// information about a subexpression as it is folded. It retains information
/// about the AST context, but also maintains information about the folded
@@ -707,7 +743,8 @@ namespace {
/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
/// evaluate the expression regardless of what the RHS is, but C only allows
/// certain things in certain situations.
- struct EvalInfo {
+ class EvalInfo : public interp::State {
+ public:
ASTContext &Ctx;
/// EvalStatus - Contains information about the evaluation.
@@ -727,6 +764,10 @@ namespace {
/// we will evaluate.
unsigned StepsLeft;
+ /// Enable the experimental new constant interpreter. If an expression is
+ /// not supported by the interpreter, an error is triggered.
+ bool EnableNewConstInterp;
+
/// BottomFrame - The frame in which evaluation started. This must be
/// initialized after CurrentCall and CallStackDepth.
CallStackFrame BottomFrame;
@@ -739,6 +780,15 @@ namespace {
/// evaluated, if any.
APValue::LValueBase EvaluatingDecl;
+ enum class EvaluatingDeclKind {
+ None,
+ /// We're evaluating the construction of EvaluatingDecl.
+ Ctor,
+ /// We're evaluating the destruction of EvaluatingDecl.
+ Dtor,
+ };
+ EvaluatingDeclKind IsEvaluatingDecl = EvaluatingDeclKind::None;
+
/// EvaluatingDeclValue - This is the value being constructed for the
/// declaration whose initializer is being evaluated, if any.
APValue *EvaluatingDeclValue;
@@ -747,6 +797,14 @@ namespace {
llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase>
ObjectsUnderConstruction;
+ /// Current heap allocations, along with the location where each was
+ /// allocated. We use std::map here because we need stable addresses
+ /// for the stored APValues.
+ std::map<DynamicAllocLValue, DynAlloc, DynAllocOrder> HeapAllocs;
+
+ /// The number of heap allocations performed so far in this evaluation.
+ unsigned NumHeapAllocs = 0;
+
struct EvaluatingConstructorRAII {
EvalInfo &EI;
ObjectUnderConstruction Object;
@@ -768,9 +826,29 @@ namespace {
}
};
+ struct EvaluatingDestructorRAII {
+ EvalInfo &EI;
+ ObjectUnderConstruction Object;
+ bool DidInsert;
+ EvaluatingDestructorRAII(EvalInfo &EI, ObjectUnderConstruction Object)
+ : EI(EI), Object(Object) {
+ DidInsert = EI.ObjectsUnderConstruction
+ .insert({Object, ConstructionPhase::Destroying})
+ .second;
+ }
+ void startedDestroyingBases() {
+ EI.ObjectsUnderConstruction[Object] =
+ ConstructionPhase::DestroyingBases;
+ }
+ ~EvaluatingDestructorRAII() {
+ if (DidInsert)
+ EI.ObjectsUnderConstruction.erase(Object);
+ }
+ };
+
ConstructionPhase
- isEvaluatingConstructor(APValue::LValueBase Base,
- ArrayRef<APValue::LValuePathEntry> Path) {
+ isEvaluatingCtorDtor(APValue::LValueBase Base,
+ ArrayRef<APValue::LValuePathEntry> Path) {
return ObjectsUnderConstruction.lookup({Base, Path});
}
@@ -827,32 +905,39 @@ namespace {
/// Are we checking whether the expression is a potential constant
/// expression?
- bool checkingPotentialConstantExpression() const {
+ bool checkingPotentialConstantExpression() const override {
return CheckingPotentialConstantExpression;
}
/// Are we checking an expression for overflow?
// FIXME: We should check for any kind of undefined or suspicious behavior
// in such constructs, not just overflow.
- bool checkingForUndefinedBehavior() { return CheckingForUndefinedBehavior; }
+ bool checkingForUndefinedBehavior() const override {
+ return CheckingForUndefinedBehavior;
+ }
EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
- : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
- CallStackDepth(0), NextCallIndex(1),
- StepsLeft(getLangOpts().ConstexprStepLimit),
- BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
- EvaluatingDecl((const ValueDecl *)nullptr),
- EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false),
- InConstantContext(false), EvalMode(Mode) {}
-
- void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
+ : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
+ CallStackDepth(0), NextCallIndex(1),
+ StepsLeft(C.getLangOpts().ConstexprStepLimit),
+ EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
+ BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
+ EvaluatingDecl((const ValueDecl *)nullptr),
+ EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
+ HasFoldFailureDiagnostic(false), InConstantContext(false),
+ EvalMode(Mode) {}
+
+ ~EvalInfo() {
+ discardCleanups();
+ }
+
+ void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
+ EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
EvaluatingDecl = Base;
+ IsEvaluatingDecl = EDK;
EvaluatingDeclValue = &Value;
}
- const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
-
bool CheckCallLimit(SourceLocation Loc) {
// Don't perform any constexpr calls (other than the call we're checking)
// when checking a potential constant expression.
@@ -895,116 +980,113 @@ namespace {
return true;
}
- private:
- /// Add a diagnostic to the diagnostics list.
- PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) {
- PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator());
- EvalStatus.Diag->push_back(std::make_pair(Loc, PD));
- return EvalStatus.Diag->back().second;
+ APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV);
+
+ Optional<DynAlloc*> lookupDynamicAlloc(DynamicAllocLValue DA) {
+ Optional<DynAlloc*> Result;
+ auto It = HeapAllocs.find(DA);
+ if (It != HeapAllocs.end())
+ Result = &It->second;
+ return Result;
}
- /// Add notes containing a call stack to the current point of evaluation.
- void addCallStack(unsigned Limit);
+ /// Information about a stack frame for std::allocator<T>::[de]allocate.
+ struct StdAllocatorCaller {
+ unsigned FrameIndex;
+ QualType ElemType;
+ explicit operator bool() const { return FrameIndex != 0; };
+ };
- private:
- OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId,
- unsigned ExtraNotes, bool IsCCEDiag) {
+ StdAllocatorCaller getStdAllocatorCaller(StringRef FnName) const {
+ for (const CallStackFrame *Call = CurrentCall; Call != &BottomFrame;
+ Call = Call->Caller) {
+ const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Call->Callee);
+ if (!MD)
+ continue;
+ const IdentifierInfo *FnII = MD->getIdentifier();
+ if (!FnII || !FnII->isStr(FnName))
+ continue;
- if (EvalStatus.Diag) {
- // If we have a prior diagnostic, it will be noting that the expression
- // isn't a constant expression. This diagnostic is more important,
- // unless we require this evaluation to produce a constant expression.
- //
- // FIXME: We might want to show both diagnostics to the user in
- // EM_ConstantFold mode.
- if (!EvalStatus.Diag->empty()) {
- switch (EvalMode) {
- case EM_ConstantFold:
- case EM_IgnoreSideEffects:
- if (!HasFoldFailureDiagnostic)
- break;
- // We've already failed to fold something. Keep that diagnostic.
- LLVM_FALLTHROUGH;
- case EM_ConstantExpression:
- case EM_ConstantExpressionUnevaluated:
- HasActiveDiagnostic = false;
- return OptionalDiagnostic();
- }
- }
+ const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
+ if (!CTSD)
+ continue;
- unsigned CallStackNotes = CallStackDepth - 1;
- unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit();
- if (Limit)
- CallStackNotes = std::min(CallStackNotes, Limit + 1);
- if (checkingPotentialConstantExpression())
- CallStackNotes = 0;
-
- HasActiveDiagnostic = true;
- HasFoldFailureDiagnostic = !IsCCEDiag;
- EvalStatus.Diag->clear();
- EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
- addDiag(Loc, DiagId);
- if (!checkingPotentialConstantExpression())
- addCallStack(Limit);
- return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
+ const IdentifierInfo *ClassII = CTSD->getIdentifier();
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ if (CTSD->isInStdNamespace() && ClassII &&
+ ClassII->isStr("allocator") && TAL.size() >= 1 &&
+ TAL[0].getKind() == TemplateArgument::Type)
+ return {Call->Index, TAL[0].getAsType()};
}
- HasActiveDiagnostic = false;
- return OptionalDiagnostic();
- }
- public:
- // Diagnose that the evaluation could not be folded (FF => FoldFailure)
- OptionalDiagnostic
- FFDiag(SourceLocation Loc,
- diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0) {
- return Diag(Loc, DiagId, ExtraNotes, false);
- }
- OptionalDiagnostic FFDiag(const Expr *E, diag::kind DiagId
- = diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0) {
- if (EvalStatus.Diag)
- return Diag(E->getExprLoc(), DiagId, ExtraNotes, /*IsCCEDiag*/false);
- HasActiveDiagnostic = false;
- return OptionalDiagnostic();
+ return {};
}
- /// Diagnose that the evaluation does not produce a C++11 core constant
- /// expression.
- ///
- /// FIXME: Stop evaluating if we're in EM_ConstantExpression mode
- /// and we produce one of these.
- OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId
- = diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0) {
- // Don't override a previous diagnostic. Don't bother collecting
- // diagnostics if we're evaluating for overflow.
- if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) {
- HasActiveDiagnostic = false;
- return OptionalDiagnostic();
+ void performLifetimeExtension() {
+ // Disable the cleanups for lifetime-extended temporaries.
+ CleanupStack.erase(
+ std::remove_if(CleanupStack.begin(), CleanupStack.end(),
+ [](Cleanup &C) { return C.isLifetimeExtended(); }),
+ CleanupStack.end());
+ }
+
+ /// Throw away any remaining cleanups at the end of evaluation. If any
+ /// cleanups would have had a side-effect, note that as an unmodeled
+ /// side-effect and return false. Otherwise, return true.
+ bool discardCleanups() {
+ for (Cleanup &C : CleanupStack) {
+ if (C.hasSideEffect() && !noteSideEffect()) {
+ CleanupStack.clear();
+ return false;
+ }
}
- return Diag(Loc, DiagId, ExtraNotes, true);
- }
- OptionalDiagnostic CCEDiag(const Expr *E, diag::kind DiagId
- = diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0) {
- return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
- }
- /// Add a note to a prior diagnostic.
- OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId) {
- if (!HasActiveDiagnostic)
- return OptionalDiagnostic();
- return OptionalDiagnostic(&addDiag(Loc, DiagId));
+ CleanupStack.clear();
+ return true;
}
- /// Add a stack of notes to a prior diagnostic.
- void addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
- if (HasActiveDiagnostic) {
- EvalStatus.Diag->insert(EvalStatus.Diag->end(),
- Diags.begin(), Diags.end());
+ private:
+ interp::Frame *getCurrentFrame() override { return CurrentCall; }
+ const interp::Frame *getBottomFrame() const override { return &BottomFrame; }
+
+ bool hasActiveDiagnostic() override { return HasActiveDiagnostic; }
+ void setActiveDiagnostic(bool Flag) override { HasActiveDiagnostic = Flag; }
+
+ void setFoldFailureDiagnostic(bool Flag) override {
+ HasFoldFailureDiagnostic = Flag;
+ }
+
+ Expr::EvalStatus &getEvalStatus() const override { return EvalStatus; }
+
+ ASTContext &getCtx() const override { return Ctx; }
+
+ // If we have a prior diagnostic, it will be noting that the expression
+ // isn't a constant expression. This diagnostic is more important,
+ // unless we require this evaluation to produce a constant expression.
+ //
+ // FIXME: We might want to show both diagnostics to the user in
+ // EM_ConstantFold mode.
+ bool hasPriorDiagnostic() override {
+ if (!EvalStatus.Diag->empty()) {
+ switch (EvalMode) {
+ case EM_ConstantFold:
+ case EM_IgnoreSideEffects:
+ if (!HasFoldFailureDiagnostic)
+ break;
+ // We've already failed to fold something. Keep that diagnostic.
+ LLVM_FALLTHROUGH;
+ case EM_ConstantExpression:
+ case EM_ConstantExpressionUnevaluated:
+ setActiveDiagnostic(false);
+ return true;
+ }
}
+ return false;
}
+ unsigned getCallStackDepth() override { return CallStackDepth; }
+
+ public:
/// Should we continue evaluation after encountering a side-effect that we
/// couldn't model?
bool keepEvaluatingAfterSideEffect() {
@@ -1047,14 +1129,14 @@ namespace {
/// Note that we hit something that was technically undefined behavior, but
/// that we can evaluate past it (such as signed overflow or floating-point
/// division by zero.)
- bool noteUndefinedBehavior() {
+ bool noteUndefinedBehavior() override {
EvalStatus.HasUndefinedBehavior = true;
return keepEvaluatingAfterUndefinedBehavior();
}
/// Should we continue evaluation as much as possible after encountering a
/// construct which can't be reduced to a value?
- bool keepEvaluatingAfterFailure() {
+ bool keepEvaluatingAfterFailure() const override {
if (!StepsLeft)
return false;
@@ -1206,29 +1288,45 @@ namespace {
// temporaries created in different iterations of a loop.
Info.CurrentCall->pushTempVersion();
}
+ bool destroy(bool RunDestructors = true) {
+ bool OK = cleanup(Info, RunDestructors, OldStackSize);
+ OldStackSize = -1U;
+ return OK;
+ }
~ScopeRAII() {
+ if (OldStackSize != -1U)
+ destroy(false);
// Body moved to a static method to encourage the compiler to inline away
// instances of this class.
- cleanup(Info, OldStackSize);
Info.CurrentCall->popTempVersion();
}
private:
- static void cleanup(EvalInfo &Info, unsigned OldStackSize) {
- unsigned NewEnd = OldStackSize;
- for (unsigned I = OldStackSize, N = Info.CleanupStack.size();
- I != N; ++I) {
- if (IsFullExpression && Info.CleanupStack[I].isLifetimeExtended()) {
- // Full-expression cleanup of a lifetime-extended temporary: nothing
- // to do, just move this cleanup to the right place in the stack.
- std::swap(Info.CleanupStack[I], Info.CleanupStack[NewEnd]);
- ++NewEnd;
- } else {
- // End the lifetime of the object.
- Info.CleanupStack[I].endLifetime();
+ static bool cleanup(EvalInfo &Info, bool RunDestructors,
+ unsigned OldStackSize) {
+ assert(OldStackSize <= Info.CleanupStack.size() &&
+ "running cleanups out of order?");
+
+ // Run all cleanups for a block scope, and non-lifetime-extended cleanups
+ // for a full-expression scope.
+ bool Success = true;
+ for (unsigned I = Info.CleanupStack.size(); I > OldStackSize; --I) {
+ if (!(IsFullExpression &&
+ Info.CleanupStack[I - 1].isLifetimeExtended())) {
+ if (!Info.CleanupStack[I - 1].endLifetime(Info, RunDestructors)) {
+ Success = false;
+ break;
+ }
}
}
- Info.CleanupStack.erase(Info.CleanupStack.begin() + NewEnd,
- Info.CleanupStack.end());
+
+ // Compact lifetime-extended cleanups.
+ auto NewEnd = Info.CleanupStack.begin() + OldStackSize;
+ if (IsFullExpression)
+ NewEnd =
+ std::remove_if(NewEnd, Info.CleanupStack.end(),
+ [](Cleanup &C) { return !C.isLifetimeExtended(); });
+ Info.CleanupStack.erase(NewEnd, Info.CleanupStack.end());
+ return Success;
}
};
typedef ScopeRAII<false> BlockScopeRAII;
@@ -1288,74 +1386,14 @@ CallStackFrame::~CallStackFrame() {
Info.CurrentCall = Caller;
}
-APValue &CallStackFrame::createTemporary(const void *Key,
- bool IsLifetimeExtended) {
- unsigned Version = Info.CurrentCall->getTempVersion();
- APValue &Result = Temporaries[MapKeyTy(Key, Version)];
- assert(Result.isAbsent() && "temporary created multiple times");
- Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended));
- return Result;
-}
-
-static void describeCall(CallStackFrame *Frame, raw_ostream &Out);
-
-void EvalInfo::addCallStack(unsigned Limit) {
- // Determine which calls to skip, if any.
- unsigned ActiveCalls = CallStackDepth - 1;
- unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart;
- if (Limit && Limit < ActiveCalls) {
- SkipStart = Limit / 2 + Limit % 2;
- SkipEnd = ActiveCalls - Limit / 2;
- }
-
- // Walk the call stack and add the diagnostics.
- unsigned CallIdx = 0;
- for (CallStackFrame *Frame = CurrentCall; Frame != &BottomFrame;
- Frame = Frame->Caller, ++CallIdx) {
- // Skip this call?
- if (CallIdx >= SkipStart && CallIdx < SkipEnd) {
- if (CallIdx == SkipStart) {
- // Note that we're skipping calls.
- addDiag(Frame->CallLoc, diag::note_constexpr_calls_suppressed)
- << unsigned(ActiveCalls - Limit);
- }
- continue;
- }
-
- // Use a different note for an inheriting constructor, because from the
- // user's perspective it's not really a function at all.
- if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(Frame->Callee)) {
- if (CD->isInheritingConstructor()) {
- addDiag(Frame->CallLoc, diag::note_constexpr_inherited_ctor_call_here)
- << CD->getParent();
- continue;
- }
- }
-
- SmallVector<char, 128> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- describeCall(Frame, Out);
- addDiag(Frame->CallLoc, diag::note_constexpr_call_here) << Out.str();
- }
+static bool isRead(AccessKinds AK) {
+ return AK == AK_Read || AK == AK_ReadObjectRepresentation;
}
-/// Kinds of access we can perform on an object, for diagnostics. Note that
-/// we consider a member function call to be a kind of access, even though
-/// it is not formally an access of the object, because it has (largely) the
-/// same set of semantic restrictions.
-enum AccessKinds {
- AK_Read,
- AK_Assign,
- AK_Increment,
- AK_Decrement,
- AK_MemberCall,
- AK_DynamicCast,
- AK_TypeId,
-};
-
static bool isModification(AccessKinds AK) {
switch (AK) {
case AK_Read:
+ case AK_ReadObjectRepresentation:
case AK_MemberCall:
case AK_DynamicCast:
case AK_TypeId:
@@ -1363,14 +1401,20 @@ static bool isModification(AccessKinds AK) {
case AK_Assign:
case AK_Increment:
case AK_Decrement:
+ case AK_Construct:
+ case AK_Destroy:
return true;
}
llvm_unreachable("unknown access kind");
}
+static bool isAnyAccess(AccessKinds AK) {
+ return isRead(AK) || isModification(AK);
+}
+
/// Is this an access per the C++ definition?
static bool isFormalAccess(AccessKinds AK) {
- return AK == AK_Read || isModification(AK);
+ return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy;
}
namespace {
@@ -1466,9 +1510,10 @@ namespace {
IsNullPtr = false;
}
- void setNull(QualType PointerTy, uint64_t TargetVal) {
+ void setNull(ASTContext &Ctx, QualType PointerTy) {
Base = (Expr *)nullptr;
- Offset = CharUnits::fromQuantity(TargetVal);
+ Offset =
+ CharUnits::fromQuantity(Ctx.getTargetNullPointerValue(PointerTy));
InvalidBase = false;
Designator = SubobjectDesignator(PointerTy->getPointeeType());
IsNullPtr = true;
@@ -1478,6 +1523,12 @@ namespace {
set(B, true);
}
+ std::string toString(ASTContext &Ctx, QualType T) const {
+ APValue Printable;
+ moveInto(Printable);
+ return Printable.getAsString(Ctx, T);
+ }
+
private:
// Check that this LValue is not based on a null pointer. If it is, produce
// a diagnostic and mark the designator as invalid.
@@ -1700,15 +1751,6 @@ static bool EvaluateFixedPoint(const Expr *E, APFixedPoint &Result,
// Misc utilities
//===----------------------------------------------------------------------===//
-/// A helper function to create a temporary and set an LValue.
-template <class KeyTy>
-static APValue &createTemporary(const KeyTy *Key, bool IsLifetimeExtended,
- LValue &LV, CallStackFrame &Frame) {
- LV.set({Key, Frame.Info.CurrentCall->Index,
- Frame.Info.CurrentCall->getTempVersion()});
- return Frame.createTemporary(Key, IsLifetimeExtended);
-}
-
/// Negate an APSInt in place, converting it to a signed form if necessary, and
/// preserving its value (by extending by up to one bit as needed).
static void negateAsSigned(APSInt &Int) {
@@ -1719,37 +1761,74 @@ static void negateAsSigned(APSInt &Int) {
Int = -Int;
}
+template<typename KeyT>
+APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
+ bool IsLifetimeExtended, LValue &LV) {
+ unsigned Version = getTempVersion();
+ APValue::LValueBase Base(Key, Index, Version);
+ LV.set(Base);
+ APValue &Result = Temporaries[MapKeyTy(Key, Version)];
+ assert(Result.isAbsent() && "temporary created multiple times");
+
+ // If we're creating a temporary immediately in the operand of a speculative
+ // evaluation, don't register a cleanup to be run outside the speculative
+ // evaluation context, since we won't actually be able to initialize this
+ // object.
+ if (Index <= Info.SpeculativeEvaluationDepth) {
+ if (T.isDestructedType())
+ Info.noteSideEffect();
+ } else {
+ Info.CleanupStack.push_back(Cleanup(&Result, Base, T, IsLifetimeExtended));
+ }
+ return Result;
+}
+
+APValue *EvalInfo::createHeapAlloc(const Expr *E, QualType T, LValue &LV) {
+ if (NumHeapAllocs > DynamicAllocLValue::getMaxIndex()) {
+ FFDiag(E, diag::note_constexpr_heap_alloc_limit_exceeded);
+ return nullptr;
+ }
+
+ DynamicAllocLValue DA(NumHeapAllocs++);
+ LV.set(APValue::LValueBase::getDynamicAlloc(DA, T));
+ auto Result = HeapAllocs.emplace(std::piecewise_construct,
+ std::forward_as_tuple(DA), std::tuple<>());
+ assert(Result.second && "reused a heap alloc index?");
+ Result.first->second.AllocExpr = E;
+ return &Result.first->second.Value;
+}
+
/// Produce a string describing the given constexpr call.
-static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
+void CallStackFrame::describe(raw_ostream &Out) {
unsigned ArgIndex = 0;
- bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
- !isa<CXXConstructorDecl>(Frame->Callee) &&
- cast<CXXMethodDecl>(Frame->Callee)->isInstance();
+ bool IsMemberCall = isa<CXXMethodDecl>(Callee) &&
+ !isa<CXXConstructorDecl>(Callee) &&
+ cast<CXXMethodDecl>(Callee)->isInstance();
if (!IsMemberCall)
- Out << *Frame->Callee << '(';
+ Out << *Callee << '(';
- if (Frame->This && IsMemberCall) {
+ if (This && IsMemberCall) {
APValue Val;
- Frame->This->moveInto(Val);
- Val.printPretty(Out, Frame->Info.Ctx,
- Frame->This->Designator.MostDerivedType);
+ This->moveInto(Val);
+ Val.printPretty(Out, Info.Ctx,
+ This->Designator.MostDerivedType);
// FIXME: Add parens around Val if needed.
- Out << "->" << *Frame->Callee << '(';
+ Out << "->" << *Callee << '(';
IsMemberCall = false;
}
- for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(),
- E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) {
+ for (FunctionDecl::param_const_iterator I = Callee->param_begin(),
+ E = Callee->param_end(); I != E; ++I, ++ArgIndex) {
if (ArgIndex > (unsigned)IsMemberCall)
Out << ", ";
const ParmVarDecl *Param = *I;
- const APValue &Arg = Frame->Arguments[ArgIndex];
- Arg.printPretty(Out, Frame->Info.Ctx, Param->getType());
+ const APValue &Arg = Arguments[ArgIndex];
+ Arg.printPretty(Out, Info.Ctx, Param->getType());
if (ArgIndex == 0 && IsMemberCall)
- Out << "->" << *Frame->Callee << '(';
+ Out << "->" << *Callee << '(';
}
Out << ')';
@@ -1789,7 +1868,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
return isa<FunctionDecl>(D);
}
- if (B.is<TypeInfoLValue>())
+ if (B.is<TypeInfoLValue>() || B.is<DynamicAllocLValue>())
return true;
const Expr *E = B.get<const Expr*>();
@@ -1888,15 +1967,39 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
Info.Note(VD->getLocation(), diag::note_declared_at);
else if (const Expr *E = Base.dyn_cast<const Expr*>())
Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here);
+ else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
+ // FIXME: Produce a note for dangling pointers too.
+ if (Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA))
+ Info.Note((*Alloc)->AllocExpr->getExprLoc(),
+ diag::note_constexpr_dynamic_alloc_here);
+ }
// We have no information to show for a typeid(T) object.
}
+enum class CheckEvaluationResultKind {
+ ConstantExpression,
+ FullyInitialized,
+};
+
+/// Materialized temporaries that we've already checked to determine if they're
+/// initializsed by a constant expression.
+using CheckedTemporaries =
+ llvm::SmallPtrSet<const MaterializeTemporaryExpr *, 8>;
+
+static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
+ EvalInfo &Info, SourceLocation DiagLoc,
+ QualType Type, const APValue &Value,
+ Expr::ConstExprUsage Usage,
+ SourceLocation SubobjectLoc,
+ CheckedTemporaries &CheckedTemps);
+
/// Check that this reference or pointer core constant expression is a valid
/// value for an address or reference constant expression. Return true if we
/// can fold this expression, whether or not it's a constant expression.
static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
QualType Type, const LValue &LVal,
- Expr::ConstExprUsage Usage) {
+ Expr::ConstExprUsage Usage,
+ CheckedTemporaries &CheckedTemps) {
bool IsReferenceType = Type->isReferenceType();
APValue::LValueBase Base = LVal.getLValueBase();
@@ -1922,14 +2025,23 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
LVal.getLValueCallIndex() == 0) &&
"have call index for global lvalue");
+ if (Base.is<DynamicAllocLValue>()) {
+ Info.FFDiag(Loc, diag::note_constexpr_dynamic_alloc)
+ << IsReferenceType << !Designator.Entries.empty();
+ NoteLValueLocation(Info, Base);
+ return false;
+ }
+
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) {
// Check if this is a thread-local variable.
if (Var->getTLSKind())
+ // FIXME: Diagnostic!
return false;
// A dllimport variable never acts like a constant.
if (Usage == Expr::EvaluateForCodeGen && Var->hasAttr<DLLImportAttr>())
+ // FIXME: Diagnostic!
return false;
}
if (const auto *FD = dyn_cast<const FunctionDecl>(VD)) {
@@ -1945,6 +2057,25 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// perform initialization with the address of the thunk.
if (Info.getLangOpts().CPlusPlus && Usage == Expr::EvaluateForCodeGen &&
FD->hasAttr<DLLImportAttr>())
+ // FIXME: Diagnostic!
+ return false;
+ }
+ } else if (const auto *MTE = dyn_cast_or_null<MaterializeTemporaryExpr>(
+ Base.dyn_cast<const Expr *>())) {
+ if (CheckedTemps.insert(MTE).second) {
+ QualType TempType = getType(Base);
+ if (TempType.isDestructedType()) {
+ Info.FFDiag(MTE->getExprLoc(),
+ diag::note_constexpr_unsupported_tempoarary_nontrivial_dtor)
+ << TempType;
+ return false;
+ }
+
+ APValue *V = MTE->getOrCreateValue(false);
+ assert(V && "evasluation result refers to uninitialised temporary");
+ if (!CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
+ Info, MTE->getExprLoc(), TempType, *V,
+ Usage, SourceLocation(), CheckedTemps))
return false;
}
}
@@ -2019,14 +2150,12 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
return false;
}
-/// Check that this core constant expression value is a valid value for a
-/// constant expression. If not, report an appropriate diagnostic. Does not
-/// check that the expression is of literal type.
-static bool
-CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
- const APValue &Value,
- Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen,
- SourceLocation SubobjectLoc = SourceLocation()) {
+static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
+ EvalInfo &Info, SourceLocation DiagLoc,
+ QualType Type, const APValue &Value,
+ Expr::ConstExprUsage Usage,
+ SourceLocation SubobjectLoc,
+ CheckedTemporaries &CheckedTemps) {
if (!Value.hasValue()) {
Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
<< true << Type;
@@ -2046,30 +2175,31 @@ CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
if (Value.isArray()) {
QualType EltTy = Type->castAsArrayTypeUnsafe()->getElementType();
for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) {
- if (!CheckConstantExpression(Info, DiagLoc, EltTy,
- Value.getArrayInitializedElt(I), Usage,
- SubobjectLoc))
+ if (!CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
+ Value.getArrayInitializedElt(I), Usage,
+ SubobjectLoc, CheckedTemps))
return false;
}
if (!Value.hasArrayFiller())
return true;
- return CheckConstantExpression(Info, DiagLoc, EltTy, Value.getArrayFiller(),
- Usage, SubobjectLoc);
+ return CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
+ Value.getArrayFiller(), Usage, SubobjectLoc,
+ CheckedTemps);
}
if (Value.isUnion() && Value.getUnionField()) {
- return CheckConstantExpression(Info, DiagLoc,
- Value.getUnionField()->getType(),
- Value.getUnionValue(), Usage,
- Value.getUnionField()->getLocation());
+ return CheckEvaluationResult(
+ CERK, Info, DiagLoc, Value.getUnionField()->getType(),
+ Value.getUnionValue(), Usage, Value.getUnionField()->getLocation(),
+ CheckedTemps);
}
if (Value.isStruct()) {
RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
unsigned BaseIndex = 0;
for (const CXXBaseSpecifier &BS : CD->bases()) {
- if (!CheckConstantExpression(Info, DiagLoc, BS.getType(),
- Value.getStructBase(BaseIndex), Usage,
- BS.getBeginLoc()))
+ if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(),
+ Value.getStructBase(BaseIndex), Usage,
+ BS.getBeginLoc(), CheckedTemps))
return false;
++BaseIndex;
}
@@ -2078,26 +2208,66 @@ CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
if (I->isUnnamedBitfield())
continue;
- if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
- Value.getStructField(I->getFieldIndex()),
- Usage, I->getLocation()))
+ if (!CheckEvaluationResult(CERK, Info, DiagLoc, I->getType(),
+ Value.getStructField(I->getFieldIndex()),
+ Usage, I->getLocation(), CheckedTemps))
return false;
}
}
- if (Value.isLValue()) {
+ if (Value.isLValue() &&
+ CERK == CheckEvaluationResultKind::ConstantExpression) {
LValue LVal;
LVal.setFrom(Info.Ctx, Value);
- return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Usage);
+ return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Usage,
+ CheckedTemps);
}
- if (Value.isMemberPointer())
+ if (Value.isMemberPointer() &&
+ CERK == CheckEvaluationResultKind::ConstantExpression)
return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Usage);
// Everything else is fine.
return true;
}
+/// Check that this core constant expression value is a valid value for a
+/// constant expression. If not, report an appropriate diagnostic. Does not
+/// check that the expression is of literal type.
+static bool
+CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
+ const APValue &Value,
+ Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen) {
+ CheckedTemporaries CheckedTemps;
+ return CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
+ Info, DiagLoc, Type, Value, Usage,
+ SourceLocation(), CheckedTemps);
+}
+
+/// Check that this evaluated value is fully-initialized and can be loaded by
+/// an lvalue-to-rvalue conversion.
+static bool CheckFullyInitialized(EvalInfo &Info, SourceLocation DiagLoc,
+ QualType Type, const APValue &Value) {
+ CheckedTemporaries CheckedTemps;
+ return CheckEvaluationResult(
+ CheckEvaluationResultKind::FullyInitialized, Info, DiagLoc, Type, Value,
+ Expr::EvaluateForCodeGen, SourceLocation(), CheckedTemps);
+}
+
+/// Enforce C++2a [expr.const]/4.17, which disallows new-expressions unless
+/// "the allocated storage is deallocated within the evaluation".
+static bool CheckMemoryLeaks(EvalInfo &Info) {
+ if (!Info.HeapAllocs.empty()) {
+ // We can still fold to a constant despite a compile-time memory leak,
+ // so long as the heap allocation isn't referenced in the result (we check
+ // that in CheckConstantExpression).
+ Info.CCEDiag(Info.HeapAllocs.begin()->second.AllocExpr,
+ diag::note_constexpr_memory_leak)
+ << unsigned(Info.HeapAllocs.size() - 1);
+ }
+ return true;
+}
+
static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
// A null base expression indicates a null pointer. These are always
// evaluatable, and they are false unless the offset is zero.
@@ -2789,9 +2959,10 @@ static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
// FIXME: This is inefficient; we should probably introduce something similar
// to the LLVM ConstantDataArray to make this cheaper.
static void expandStringLiteral(EvalInfo &Info, const StringLiteral *S,
- APValue &Result) {
- const ConstantArrayType *CAT =
- Info.Ctx.getAsConstantArrayType(S->getType());
+ APValue &Result,
+ QualType AllocType = QualType()) {
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(
+ AllocType.isNull() ? S->getType() : AllocType);
assert(CAT && "string literal isn't an array");
QualType CharType = CAT->getElementType();
assert(CharType->isIntegerType() && "unexpected character type");
@@ -2855,8 +3026,8 @@ static bool isReadByLvalueToRvalueConversion(QualType T) {
/// Diagnose an attempt to read from any unreadable field within the specified
/// type, which might be a class type.
-static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
- QualType T) {
+static bool diagnoseMutableFields(EvalInfo &Info, const Expr *E, AccessKinds AK,
+ QualType T) {
CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
if (!RD)
return false;
@@ -2871,17 +3042,17 @@ static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
// FIXME: Add core issue number for the union case.
if (Field->isMutable() &&
(RD->isUnion() || isReadByLvalueToRvalueConversion(Field->getType()))) {
- Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1) << Field;
+ Info.FFDiag(E, diag::note_constexpr_access_mutable, 1) << AK << Field;
Info.Note(Field->getLocation(), diag::note_declared_at);
return true;
}
- if (diagnoseUnreadableFields(Info, E, Field->getType()))
+ if (diagnoseMutableFields(Info, E, AK, Field->getType()))
return true;
}
for (auto &BaseSpec : RD->bases())
- if (diagnoseUnreadableFields(Info, E, BaseSpec.getType()))
+ if (diagnoseMutableFields(Info, E, AK, BaseSpec.getType()))
return true;
// All mutable fields were empty, and thus not actually read.
@@ -2889,7 +3060,8 @@ static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
}
static bool lifetimeStartedInEvaluation(EvalInfo &Info,
- APValue::LValueBase Base) {
+ APValue::LValueBase Base,
+ bool MutableSubobject = false) {
// A temporary we created.
if (Base.getCallIndex())
return true;
@@ -2898,19 +3070,42 @@ static bool lifetimeStartedInEvaluation(EvalInfo &Info,
if (!Evaluating)
return false;
- // The variable whose initializer we're evaluating.
- if (auto *BaseD = Base.dyn_cast<const ValueDecl*>())
- if (declaresSameEntity(Evaluating, BaseD))
- return true;
+ auto *BaseD = Base.dyn_cast<const ValueDecl*>();
- // A temporary lifetime-extended by the variable whose initializer we're
- // evaluating.
- if (auto *BaseE = Base.dyn_cast<const Expr *>())
- if (auto *BaseMTE = dyn_cast<MaterializeTemporaryExpr>(BaseE))
- if (declaresSameEntity(BaseMTE->getExtendingDecl(), Evaluating))
- return true;
+ switch (Info.IsEvaluatingDecl) {
+ case EvalInfo::EvaluatingDeclKind::None:
+ return false;
- return false;
+ case EvalInfo::EvaluatingDeclKind::Ctor:
+ // The variable whose initializer we're evaluating.
+ if (BaseD)
+ return declaresSameEntity(Evaluating, BaseD);
+
+ // A temporary lifetime-extended by the variable whose initializer we're
+ // evaluating.
+ if (auto *BaseE = Base.dyn_cast<const Expr *>())
+ if (auto *BaseMTE = dyn_cast<MaterializeTemporaryExpr>(BaseE))
+ return declaresSameEntity(BaseMTE->getExtendingDecl(), Evaluating);
+ return false;
+
+ case EvalInfo::EvaluatingDeclKind::Dtor:
+ // C++2a [expr.const]p6:
+ // [during constant destruction] the lifetime of a and its non-mutable
+ // subobjects (but not its mutable subobjects) [are] considered to start
+ // within e.
+ //
+ // FIXME: We can meaningfully extend this to cover non-const objects, but
+ // we will need special handling: we should be able to access only
+ // subobjects of such objects that are themselves declared const.
+ if (!BaseD ||
+ !(BaseD->getType().isConstQualified() ||
+ BaseD->getType()->isReferenceType()) ||
+ MutableSubobject)
+ return false;
+ return declaresSameEntity(Evaluating, BaseD);
+ }
+
+ llvm_unreachable("unknown evaluating decl kind");
}
namespace {
@@ -2928,13 +3123,13 @@ struct CompleteObject {
CompleteObject(APValue::LValueBase Base, APValue *Value, QualType Type)
: Base(Base), Value(Value), Type(Type) {}
- bool mayReadMutableMembers(EvalInfo &Info) const {
+ bool mayAccessMutableMembers(EvalInfo &Info, AccessKinds AK) const {
// In C++14 onwards, it is permitted to read a mutable member whose
// lifetime began within the evaluation.
// FIXME: Should we also allow this in C++11?
if (!Info.getLangOpts().CPlusPlus14)
return false;
- return lifetimeStartedInEvaluation(Info, Base);
+ return lifetimeStartedInEvaluation(Info, Base, /*MutableSubobject*/true);
}
explicit operator bool() const { return !Type.isNull(); }
@@ -2982,19 +3177,22 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// Walk the designator's path to find the subobject.
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
// Reading an indeterminate value is undefined, but assigning over one is OK.
- if (O->isAbsent() || (O->isIndeterminate() && handler.AccessKind != AK_Assign)) {
+ if ((O->isAbsent() && !(handler.AccessKind == AK_Construct && I == N)) ||
+ (O->isIndeterminate() && handler.AccessKind != AK_Construct &&
+ handler.AccessKind != AK_Assign &&
+ handler.AccessKind != AK_ReadObjectRepresentation)) {
if (!Info.checkingPotentialConstantExpression())
Info.FFDiag(E, diag::note_constexpr_access_uninit)
<< handler.AccessKind << O->isIndeterminate();
return handler.failed();
}
- // C++ [class.ctor]p5:
+ // C++ [class.ctor]p5, C++ [class.dtor]p5:
// const and volatile semantics are not applied on an object under
- // construction.
+ // {con,de}struction.
if ((ObjType.isConstQualified() || ObjType.isVolatileQualified()) &&
ObjType->isRecordType() &&
- Info.isEvaluatingConstructor(
+ Info.isEvaluatingCtorDtor(
Obj.Base, llvm::makeArrayRef(Sub.Entries.begin(),
Sub.Entries.begin() + I)) !=
ConstructionPhase::None) {
@@ -3037,9 +3235,9 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// things we need to check: if there are any mutable subobjects, we
// cannot perform this read. (This only happens when performing a trivial
// copy or assignment.)
- if (ObjType->isRecordType() && handler.AccessKind == AK_Read &&
- !Obj.mayReadMutableMembers(Info) &&
- diagnoseUnreadableFields(Info, E, ObjType))
+ if (ObjType->isRecordType() &&
+ !Obj.mayAccessMutableMembers(Info, handler.AccessKind) &&
+ diagnoseMutableFields(Info, E, handler.AccessKind, ObjType))
return handler.failed();
}
@@ -3077,7 +3275,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (O->getArrayInitializedElts() > Index)
O = &O->getArrayInitializedElt(Index);
- else if (handler.AccessKind != AK_Read) {
+ else if (!isRead(handler.AccessKind)) {
expandArray(*O, Index);
O = &O->getArrayInitializedElt(Index);
} else
@@ -3107,10 +3305,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
: O->getComplexFloatReal(), ObjType);
}
} else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
- if (Field->isMutable() && handler.AccessKind == AK_Read &&
- !Obj.mayReadMutableMembers(Info)) {
- Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1)
- << Field;
+ if (Field->isMutable() &&
+ !Obj.mayAccessMutableMembers(Info, handler.AccessKind)) {
+ Info.FFDiag(E, diag::note_constexpr_access_mutable, 1)
+ << handler.AccessKind << Field;
Info.Note(Field->getLocation(), diag::note_declared_at);
return handler.failed();
}
@@ -3121,9 +3319,18 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
const FieldDecl *UnionField = O->getUnionField();
if (!UnionField ||
UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) {
- Info.FFDiag(E, diag::note_constexpr_access_inactive_union_member)
- << handler.AccessKind << Field << !UnionField << UnionField;
- return handler.failed();
+ if (I == N - 1 && handler.AccessKind == AK_Construct) {
+ // Placement new onto an inactive union member makes it active.
+ O->setUnion(Field, APValue());
+ } else {
+ // FIXME: If O->getUnionValue() is absent, report that there's no
+ // active union member rather than reporting the prior active union
+ // member. We'll need to fix nullptr_t to not use APValue() as its
+ // representation first.
+ Info.FFDiag(E, diag::note_constexpr_access_inactive_union_member)
+ << handler.AccessKind << Field << !UnionField << UnionField;
+ return handler.failed();
+ }
}
O = &O->getUnionValue();
} else
@@ -3147,15 +3354,17 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
namespace {
struct ExtractSubobjectHandler {
EvalInfo &Info;
+ const Expr *E;
APValue &Result;
-
- static const AccessKinds AccessKind = AK_Read;
+ const AccessKinds AccessKind;
typedef bool result_type;
bool failed() { return false; }
bool found(APValue &Subobj, QualType SubobjType) {
Result = Subobj;
- return true;
+ if (AccessKind == AK_ReadObjectRepresentation)
+ return true;
+ return CheckFullyInitialized(Info, E->getExprLoc(), SubobjType, Result);
}
bool found(APSInt &Value, QualType SubobjType) {
Result = APValue(Value);
@@ -3168,14 +3377,13 @@ struct ExtractSubobjectHandler {
};
} // end anonymous namespace
-const AccessKinds ExtractSubobjectHandler::AccessKind;
-
/// Extract the designated sub-object of an rvalue.
static bool extractSubobject(EvalInfo &Info, const Expr *E,
const CompleteObject &Obj,
- const SubobjectDesignator &Sub,
- APValue &Result) {
- ExtractSubobjectHandler Handler = { Info, Result };
+ const SubobjectDesignator &Sub, APValue &Result,
+ AccessKinds AK = AK_Read) {
+ assert(AK == AK_Read || AK == AK_ReadObjectRepresentation);
+ ExtractSubobjectHandler Handler = {Info, E, Result, AK};
return findSubobject(Info, E, Obj, Sub, Handler);
}
@@ -3321,13 +3529,13 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
}
- bool IsAccess = isFormalAccess(AK);
+ bool IsAccess = isAnyAccess(AK);
// C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type
// is not a constant expression (even if the object is non-volatile). We also
// apply this rule to C++98, in order to conform to the expected 'volatile'
// semantics.
- if (IsAccess && LValType.isVolatileQualified()) {
+ if (isFormalAccess(AK) && LValType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus)
Info.FFDiag(E, diag::note_constexpr_access_volatile_type)
<< AK << LValType;
@@ -3362,8 +3570,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// the variable we're reading must be const.
if (!Frame) {
if (Info.getLangOpts().CPlusPlus14 &&
- declaresSameEntity(
- VD, Info.EvaluatingDecl.dyn_cast<const ValueDecl *>())) {
+ lifetimeStartedInEvaluation(Info, LVal.Base)) {
// OK, we can read and modify an object if we're in the process of
// evaluating its initializer, because its lifetime began in this
// evaluation.
@@ -3422,6 +3629,14 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal, &LVal))
return CompleteObject();
+ } else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
+ Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA);
+ if (!Alloc) {
+ Info.FFDiag(E, diag::note_constexpr_access_deleted_object) << AK;
+ return CompleteObject();
+ }
+ return CompleteObject(LVal.Base, &(*Alloc)->Value,
+ LVal.Base.getDynamicAllocType());
} else {
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
@@ -3445,11 +3660,14 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// int x = ++r;
// constexpr int k = r;
// Therefore we use the C++14 rules in C++11 too.
- const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>();
- const ValueDecl *ED = MTE->getExtendingDecl();
+ //
+ // Note that temporaries whose lifetimes began while evaluating a
+ // variable's constructor are not usable while evaluating the
+ // corresponding destructor, not even if they're of const-qualified
+ // types.
if (!(BaseType.isConstQualified() &&
BaseType->isIntegralOrEnumerationType()) &&
- !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) {
+ !lifetimeStartedInEvaluation(Info, LVal.Base)) {
if (!IsAccess)
return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
Info.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
@@ -3457,7 +3675,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
return CompleteObject();
}
- BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
+ BaseVal = MTE->getOrCreateValue(false);
assert(BaseVal && "got reference to unevaluated temporary");
} else {
if (!IsAccess)
@@ -3501,15 +3719,22 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
/// case of a non-class type).
/// \param LVal - The glvalue on which we are attempting to perform this action.
/// \param RVal - The produced value will be placed here.
-static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
- QualType Type,
- const LValue &LVal, APValue &RVal) {
+/// \param WantObjectRepresentation - If true, we're looking for the object
+/// representation rather than the value, and in particular,
+/// there is no requirement that the result be fully initialized.
+static bool
+handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, QualType Type,
+ const LValue &LVal, APValue &RVal,
+ bool WantObjectRepresentation = false) {
if (LVal.Designator.Invalid)
return false;
// Check for special cases where there is no existing APValue to look at.
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
+ AccessKinds AK =
+ WantObjectRepresentation ? AK_ReadObjectRepresentation : AK_Read;
+
if (Base && !LVal.getLValueCallIndex() && !Type.isVolatileQualified()) {
if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) {
// In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
@@ -3523,7 +3748,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
if (!Evaluate(Lit, Info, CLE->getInitializer()))
return false;
CompleteObject LitObj(LVal.Base, &Lit, Base->getType());
- return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal);
+ return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal, AK);
} else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) {
// Special-case character extraction so we don't have to construct an
// APValue for the whole string.
@@ -3538,7 +3763,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
}
if (LVal.Designator.isOnePastTheEnd()) {
if (Info.getLangOpts().CPlusPlus11)
- Info.FFDiag(Conv, diag::note_constexpr_access_past_end) << AK_Read;
+ Info.FFDiag(Conv, diag::note_constexpr_access_past_end) << AK;
else
Info.FFDiag(Conv);
return false;
@@ -3549,8 +3774,8 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
}
}
- CompleteObject Obj = findCompleteObject(Info, Conv, AK_Read, LVal, Type);
- return Obj && extractSubobject(Info, Conv, Obj, LVal.Designator, RVal);
+ CompleteObject Obj = findCompleteObject(Info, Conv, AK, LVal, Type);
+ return Obj && extractSubobject(Info, Conv, Obj, LVal.Designator, RVal, AK);
}
/// Perform an assignment of Val to LVal. Takes ownership of Val.
@@ -3842,7 +4067,7 @@ static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal,
/// Build an lvalue for the object argument of a member function call.
static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
LValue &This) {
- if (Object->getType()->isPointerType())
+ if (Object->getType()->isPointerType() && Object->isRValue())
return EvaluatePointer(Object, This, Info);
if (Object->isGLValue())
@@ -4004,6 +4229,40 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
return CastToDerivedClass(Info, E, Result, TargetType, NewEntriesSize);
}
+/// Get the value to use for a default-initialized object of type T.
+static APValue getDefaultInitValue(QualType T) {
+ if (auto *RD = T->getAsCXXRecordDecl()) {
+ if (RD->isUnion())
+ return APValue((const FieldDecl*)nullptr);
+
+ APValue Struct(APValue::UninitStruct(), RD->getNumBases(),
+ std::distance(RD->field_begin(), RD->field_end()));
+
+ unsigned Index = 0;
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ End = RD->bases_end(); I != End; ++I, ++Index)
+ Struct.getStructBase(Index) = getDefaultInitValue(I->getType());
+
+ for (const auto *I : RD->fields()) {
+ if (I->isUnnamedBitfield())
+ continue;
+ Struct.getStructField(I->getFieldIndex()) =
+ getDefaultInitValue(I->getType());
+ }
+ return Struct;
+ }
+
+ if (auto *AT =
+ dyn_cast_or_null<ConstantArrayType>(T->getAsArrayTypeUnsafe())) {
+ APValue Array(APValue::UninitArray(), 0, AT->getSize().getZExtValue());
+ if (Array.hasArrayFiller())
+ Array.getArrayFiller() = getDefaultInitValue(AT->getElementType());
+ return Array;
+ }
+
+ return APValue::IndeterminateValue();
+}
+
namespace {
enum EvalStmtResult {
/// Evaluation failed.
@@ -4027,14 +4286,13 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
return true;
LValue Result;
- APValue &Val = createTemporary(VD, true, Result, *Info.CurrentCall);
+ APValue &Val =
+ Info.CurrentCall->createTemporary(VD, VD->getType(), true, Result);
const Expr *InitE = VD->getInit();
if (!InitE) {
- Info.FFDiag(VD->getBeginLoc(), diag::note_constexpr_uninitialized)
- << false << VD->getType();
- Val = APValue();
- return false;
+ Val = getDefaultInitValue(VD->getType());
+ return true;
}
if (InitE->isValueDependent())
@@ -4071,7 +4329,9 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl,
FullExpressionRAII Scope(Info);
if (CondDecl && !EvaluateDecl(Info, CondDecl))
return false;
- return EvaluateAsBooleanCondition(Cond, Result, Info);
+ if (!EvaluateAsBooleanCondition(Cond, Result, Info))
+ return false;
+ return Scope.destroy();
}
namespace {
@@ -4107,7 +4367,12 @@ static EvalStmtResult EvaluateLoopBody(StmtResult &Result, EvalInfo &Info,
const Stmt *Body,
const SwitchCase *Case = nullptr) {
BlockScopeRAII Scope(Info);
- switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) {
+
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case);
+ if (ESR != ESR_Failed && ESR != ESR_CaseNotFound && !Scope.destroy())
+ ESR = ESR_Failed;
+
+ switch (ESR) {
case ESR_Break:
return ESR_Succeeded;
case ESR_Succeeded:
@@ -4129,17 +4394,23 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
// Evaluate the switch condition.
APSInt Value;
{
- FullExpressionRAII Scope(Info);
if (const Stmt *Init = SS->getInit()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ ESR = ESR_Failed;
return ESR;
+ }
}
+
+ FullExpressionRAII CondScope(Info);
if (SS->getConditionVariable() &&
!EvaluateDecl(Info, SS->getConditionVariable()))
return ESR_Failed;
if (!EvaluateInteger(SS->getCond(), Value, Info))
return ESR_Failed;
+ if (!CondScope.destroy())
+ return ESR_Failed;
}
// Find the switch case corresponding to the value of the condition.
@@ -4163,10 +4434,14 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
}
if (!Found)
- return ESR_Succeeded;
+ return Scope.destroy() ? ESR_Succeeded : ESR_Failed;
// Search the switch body for the switch case and evaluate it from there.
- switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found)) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found);
+ if (ESR != ESR_Failed && ESR != ESR_CaseNotFound && !Scope.destroy())
+ return ESR_Failed;
+
+ switch (ESR) {
case ESR_Break:
return ESR_Succeeded;
case ESR_Succeeded:
@@ -4193,10 +4468,6 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// If we're hunting down a 'case' or 'default' label, recurse through
// substatements until we hit the label.
if (Case) {
- // FIXME: We don't start the lifetime of objects whose initialization we
- // jump over. However, such objects must be of class type with a trivial
- // default constructor that initialize all subobjects, so must be empty,
- // so this almost never matters.
switch (S->getStmtClass()) {
case Stmt::CompoundStmtClass:
// FIXME: Precompute which substatement of a compound statement we
@@ -4222,10 +4493,35 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// preceded by our switch label.
BlockScopeRAII Scope(Info);
+ // Step into the init statement in case it brings an (uninitialized)
+ // variable into scope.
+ if (const Stmt *Init = IS->getInit()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Init, Case);
+ if (ESR != ESR_CaseNotFound) {
+ assert(ESR != ESR_Succeeded);
+ return ESR;
+ }
+ }
+
+ // Condition variable must be initialized if it exists.
+ // FIXME: We can skip evaluating the body if there's a condition
+ // variable, as there can't be any case labels within it.
+ // (The same is true for 'for' statements.)
+
EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case);
- if (ESR != ESR_CaseNotFound || !IS->getElse())
+ if (ESR == ESR_Failed)
return ESR;
- return EvaluateStmt(Result, Info, IS->getElse(), Case);
+ if (ESR != ESR_CaseNotFound)
+ return Scope.destroy() ? ESR : ESR_Failed;
+ if (!IS->getElse())
+ return ESR_CaseNotFound;
+
+ ESR = EvaluateStmt(Result, Info, IS->getElse(), Case);
+ if (ESR == ESR_Failed)
+ return ESR;
+ if (ESR != ESR_CaseNotFound)
+ return Scope.destroy() ? ESR : ESR_Failed;
+ return ESR_CaseNotFound;
}
case Stmt::WhileStmtClass: {
@@ -4238,21 +4534,47 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
case Stmt::ForStmtClass: {
const ForStmt *FS = cast<ForStmt>(S);
+ BlockScopeRAII Scope(Info);
+
+ // Step into the init statement in case it brings an (uninitialized)
+ // variable into scope.
+ if (const Stmt *Init = FS->getInit()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Init, Case);
+ if (ESR != ESR_CaseNotFound) {
+ assert(ESR != ESR_Succeeded);
+ return ESR;
+ }
+ }
+
EvalStmtResult ESR =
EvaluateLoopBody(Result, Info, FS->getBody(), Case);
if (ESR != ESR_Continue)
return ESR;
if (FS->getInc()) {
FullExpressionRAII IncScope(Info);
- if (!EvaluateIgnoredValue(Info, FS->getInc()))
+ if (!EvaluateIgnoredValue(Info, FS->getInc()) || !IncScope.destroy())
return ESR_Failed;
}
break;
}
- case Stmt::DeclStmtClass:
- // FIXME: If the variable has initialization that can't be jumped over,
- // bail out of any immediately-surrounding compound-statement too.
+ case Stmt::DeclStmtClass: {
+ // Start the lifetime of any uninitialized variables we encounter. They
+ // might be used by the selected branch of the switch.
+ const DeclStmt *DS = cast<DeclStmt>(S);
+ for (const auto *D : DS->decls()) {
+ if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->hasLocalStorage() && !VD->getInit())
+ if (!EvaluateVarDecl(Info, VD))
+ return ESR_Failed;
+ // FIXME: If the variable has initialization that can't be jumped
+ // over, bail out of any immediately-surrounding compound-statement
+ // too. There can't be any case labels here.
+ }
+ }
+ return ESR_CaseNotFound;
+ }
+
default:
return ESR_CaseNotFound;
}
@@ -4263,8 +4585,10 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
if (const Expr *E = dyn_cast<Expr>(S)) {
// Don't bother evaluating beyond an expression-statement which couldn't
// be evaluated.
+ // FIXME: Do we need the FullExpressionRAII object here?
+ // VisitExprWithCleanups should create one when necessary.
FullExpressionRAII Scope(Info);
- if (!EvaluateIgnoredValue(Info, E))
+ if (!EvaluateIgnoredValue(Info, E) || !Scope.destroy())
return ESR_Failed;
return ESR_Succeeded;
}
@@ -4277,12 +4601,12 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
case Stmt::DeclStmtClass: {
const DeclStmt *DS = cast<DeclStmt>(S);
- for (const auto *DclIt : DS->decls()) {
+ for (const auto *D : DS->decls()) {
// Each declaration initialization is its own full-expression.
- // FIXME: This isn't quite right; if we're performing aggregate
- // initialization, each braced subexpression is its own full-expression.
FullExpressionRAII Scope(Info);
- if (!EvaluateDecl(Info, DclIt) && !Info.noteFailure())
+ if (!EvaluateDecl(Info, D) && !Info.noteFailure())
+ return ESR_Failed;
+ if (!Scope.destroy())
return ESR_Failed;
}
return ESR_Succeeded;
@@ -4296,7 +4620,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
? EvaluateInPlace(Result.Value, Info, *Result.Slot, RetExpr)
: Evaluate(Result.Value, Info, RetExpr)))
return ESR_Failed;
- return ESR_Returned;
+ return Scope.destroy() ? ESR_Returned : ESR_Failed;
}
case Stmt::CompoundStmtClass: {
@@ -4307,10 +4631,15 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
EvalStmtResult ESR = EvaluateStmt(Result, Info, BI, Case);
if (ESR == ESR_Succeeded)
Case = nullptr;
- else if (ESR != ESR_CaseNotFound)
+ else if (ESR != ESR_CaseNotFound) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
}
- return Case ? ESR_CaseNotFound : ESR_Succeeded;
+ if (Case)
+ return ESR_CaseNotFound;
+ return Scope.destroy() ? ESR_Succeeded : ESR_Failed;
}
case Stmt::IfStmtClass: {
@@ -4320,8 +4649,11 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
BlockScopeRAII Scope(Info);
if (const Stmt *Init = IS->getInit()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
}
bool Cond;
if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond))
@@ -4329,10 +4661,13 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
if (const Stmt *SubStmt = Cond ? IS->getThen() : IS->getElse()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, SubStmt);
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
}
- return ESR_Succeeded;
+ return Scope.destroy() ? ESR_Succeeded : ESR_Failed;
}
case Stmt::WhileStmtClass: {
@@ -4347,8 +4682,13 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
break;
EvalStmtResult ESR = EvaluateLoopBody(Result, Info, WS->getBody());
- if (ESR != ESR_Continue)
+ if (ESR != ESR_Continue) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
+ if (!Scope.destroy())
+ return ESR_Failed;
}
return ESR_Succeeded;
}
@@ -4363,7 +4703,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
Case = nullptr;
FullExpressionRAII CondScope(Info);
- if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info))
+ if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info) ||
+ !CondScope.destroy())
return ESR_Failed;
} while (Continue);
return ESR_Succeeded;
@@ -4371,14 +4712,17 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
case Stmt::ForStmtClass: {
const ForStmt *FS = cast<ForStmt>(S);
- BlockScopeRAII Scope(Info);
+ BlockScopeRAII ForScope(Info);
if (FS->getInit()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !ForScope.destroy())
+ return ESR_Failed;
return ESR;
+ }
}
while (true) {
- BlockScopeRAII Scope(Info);
+ BlockScopeRAII IterScope(Info);
bool Continue = true;
if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(),
FS->getCond(), Continue))
@@ -4387,16 +4731,22 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
break;
EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody());
- if (ESR != ESR_Continue)
+ if (ESR != ESR_Continue) {
+ if (ESR != ESR_Failed && (!IterScope.destroy() || !ForScope.destroy()))
+ return ESR_Failed;
return ESR;
+ }
if (FS->getInc()) {
FullExpressionRAII IncScope(Info);
- if (!EvaluateIgnoredValue(Info, FS->getInc()))
+ if (!EvaluateIgnoredValue(Info, FS->getInc()) || !IncScope.destroy())
return ESR_Failed;
}
+
+ if (!IterScope.destroy())
+ return ESR_Failed;
}
- return ESR_Succeeded;
+ return ForScope.destroy() ? ESR_Succeeded : ESR_Failed;
}
case Stmt::CXXForRangeStmtClass: {
@@ -4406,22 +4756,34 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// Evaluate the init-statement if present.
if (FS->getInit()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
}
// Initialize the __range variable.
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
// Create the __begin and __end iterators.
ESR = EvaluateStmt(Result, Info, FS->getBeginStmt());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
ESR = EvaluateStmt(Result, Info, FS->getEndStmt());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
while (true) {
// Condition: __begin != __end.
@@ -4437,20 +4799,29 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// User's variable declaration, initialized by *__begin.
BlockScopeRAII InnerScope(Info);
ESR = EvaluateStmt(Result, Info, FS->getLoopVarStmt());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && (!InnerScope.destroy() || !Scope.destroy()))
+ return ESR_Failed;
return ESR;
+ }
// Loop body.
ESR = EvaluateLoopBody(Result, Info, FS->getBody());
- if (ESR != ESR_Continue)
+ if (ESR != ESR_Continue) {
+ if (ESR != ESR_Failed && (!InnerScope.destroy() || !Scope.destroy()))
+ return ESR_Failed;
return ESR;
+ }
// Increment: ++__begin
if (!EvaluateIgnoredValue(Info, FS->getInc()))
return ESR_Failed;
+
+ if (!InnerScope.destroy())
+ return ESR_Failed;
}
- return ESR_Succeeded;
+ return Scope.destroy() ? ESR_Succeeded : ESR_Failed;
}
case Stmt::SwitchStmtClass:
@@ -4625,9 +4996,13 @@ static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This,
/// Check that the pointee of the 'this' pointer in a member function call is
/// either within its lifetime or in its period of construction or destruction.
-static bool checkNonVirtualMemberCallThisPointer(EvalInfo &Info, const Expr *E,
- const LValue &This) {
- return checkDynamicType(Info, E, This, AK_MemberCall, false);
+static bool
+checkNonVirtualMemberCallThisPointer(EvalInfo &Info, const Expr *E,
+ const LValue &This,
+ const CXXMethodDecl *NamedMember) {
+ return checkDynamicType(
+ Info, E, This,
+ isa<CXXDestructorDecl>(NamedMember) ? AK_Destroy : AK_MemberCall, false);
}
struct DynamicType {
@@ -4675,16 +5050,19 @@ static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E,
ArrayRef<APValue::LValuePathEntry> Path = This.Designator.Entries;
for (unsigned PathLength = This.Designator.MostDerivedPathLength;
PathLength <= Path.size(); ++PathLength) {
- switch (Info.isEvaluatingConstructor(This.getLValueBase(),
- Path.slice(0, PathLength))) {
+ switch (Info.isEvaluatingCtorDtor(This.getLValueBase(),
+ Path.slice(0, PathLength))) {
case ConstructionPhase::Bases:
- // We're constructing a base class. This is not the dynamic type.
+ case ConstructionPhase::DestroyingBases:
+ // We're constructing or destroying a base class. This is not the dynamic
+ // type.
break;
case ConstructionPhase::None:
case ConstructionPhase::AfterBases:
- // We've finished constructing the base classes, so this is the dynamic
- // type.
+ case ConstructionPhase::Destroying:
+ // We've finished constructing the base classes and not yet started
+ // destroying them again, so this is the dynamic type.
return DynamicType{getBaseClassType(This.Designator, PathLength),
PathLength};
}
@@ -4701,8 +5079,9 @@ static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E,
static const CXXMethodDecl *HandleVirtualDispatch(
EvalInfo &Info, const Expr *E, LValue &This, const CXXMethodDecl *Found,
llvm::SmallVectorImpl<QualType> &CovariantAdjustmentPath) {
- Optional<DynamicType> DynType =
- ComputeDynamicType(Info, E, This, AK_MemberCall);
+ Optional<DynamicType> DynType = ComputeDynamicType(
+ Info, E, This,
+ isa<CXXDestructorDecl>(Found) ? AK_Destroy : AK_MemberCall);
if (!DynType)
return nullptr;
@@ -4838,8 +5217,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E,
if (!E->isGLValue()) {
// The value of a failed cast to pointer type is the null pointer value
// of the required result type.
- auto TargetVal = Info.Ctx.getTargetNullPointerValue(E->getType());
- Ptr.setNull(E->getType(), TargetVal);
+ Ptr.setNull(Info.Ctx, E->getType());
return true;
}
@@ -4904,39 +5282,6 @@ struct StartLifetimeOfUnionMemberHandler {
static const AccessKinds AccessKind = AK_Assign;
- APValue getDefaultInitValue(QualType SubobjType) {
- if (auto *RD = SubobjType->getAsCXXRecordDecl()) {
- if (RD->isUnion())
- return APValue((const FieldDecl*)nullptr);
-
- APValue Struct(APValue::UninitStruct(), RD->getNumBases(),
- std::distance(RD->field_begin(), RD->field_end()));
-
- unsigned Index = 0;
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- End = RD->bases_end(); I != End; ++I, ++Index)
- Struct.getStructBase(Index) = getDefaultInitValue(I->getType());
-
- for (const auto *I : RD->fields()) {
- if (I->isUnnamedBitfield())
- continue;
- Struct.getStructField(I->getFieldIndex()) =
- getDefaultInitValue(I->getType());
- }
- return Struct;
- }
-
- if (auto *AT = dyn_cast_or_null<ConstantArrayType>(
- SubobjType->getAsArrayTypeUnsafe())) {
- APValue Array(APValue::UninitArray(), 0, AT->getSize().getZExtValue());
- if (Array.hasArrayFiller())
- Array.getArrayFiller() = getDefaultInitValue(AT->getElementType());
- return Array;
- }
-
- return APValue::IndeterminateValue();
- }
-
typedef bool result_type;
bool failed() { return false; }
bool found(APValue &Subobj, QualType SubobjType) {
@@ -4949,7 +5294,8 @@ struct StartLifetimeOfUnionMemberHandler {
// * No variant members' lifetimes begin
// * All scalar subobjects whose lifetimes begin have indeterminate values
assert(SubobjType->isUnionType());
- if (!declaresSameEntity(Subobj.getUnionField(), Field))
+ if (!declaresSameEntity(Subobj.getUnionField(), Field) ||
+ !Subobj.getUnionValue().hasValue())
Subobj.setUnion(Field, getDefaultInitValue(Field->getType()));
return true;
}
@@ -4981,12 +5327,21 @@ static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,
// -- If E is of the form A.B, S(E) contains the elements of S(A)...
if (auto *ME = dyn_cast<MemberExpr>(E)) {
auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
- if (!FD)
+ // Note that we can't implicitly start the lifetime of a reference,
+ // so we don't need to proceed any further if we reach one.
+ if (!FD || FD->getType()->isReferenceType())
break;
- // ... and also contains A.B if B names a union member
- if (FD->getParent()->isUnion())
- UnionPathLengths.push_back({PathLength - 1, FD});
+ // ... and also contains A.B if B names a union member ...
+ if (FD->getParent()->isUnion()) {
+ // ... of a non-class, non-array type, or of a class type with a
+ // trivial default constructor that is not deleted, or an array of
+ // such types.
+ auto *RD =
+ FD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ if (!RD || RD->hasTrivialDefaultConstructor())
+ UnionPathLengths.push_back({PathLength - 1, FD});
+ }
E = ME->getBase();
--PathLength;
@@ -5092,18 +5447,18 @@ static bool EvaluateArgs(ArrayRef<const Expr *> Args, ArgVector &ArgValues,
}
}
}
- for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
- I != E; ++I) {
- if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) {
+ for (unsigned Idx = 0; Idx < Args.size(); Idx++) {
+ if (!Evaluate(ArgValues[Idx], Info, Args[Idx])) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
if (!Info.noteFailure())
return false;
Success = false;
} else if (!ForbiddenNullArgs.empty() &&
- ForbiddenNullArgs[I - Args.begin()] &&
- ArgValues[I - Args.begin()].isNullPointer()) {
- Info.CCEDiag(*I, diag::note_non_null_attribute_failed);
+ ForbiddenNullArgs[Idx] &&
+ ArgValues[Idx].isLValue() &&
+ ArgValues[Idx].isNullPointer()) {
+ Info.CCEDiag(Args[Idx], diag::note_non_null_attribute_failed);
if (!Info.noteFailure())
return false;
Success = false;
@@ -5142,8 +5497,8 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
LValue RHS;
RHS.setFrom(Info.Ctx, ArgValues[0]);
APValue RHSValue;
- if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
- RHS, RHSValue))
+ if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), RHS,
+ RHSValue, MD->getParent()->isUnion()))
return false;
if (Info.getLangOpts().CPlusPlus2a && MD->isTrivial() &&
!HandleUnionActiveMemberChange(Info, Args[0], *This))
@@ -5206,7 +5561,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
{
FullExpressionRAII InitScope(Info);
- if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()))
+ if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()) ||
+ !InitScope.destroy())
return false;
}
return EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed;
@@ -5227,7 +5583,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
RHS.setFrom(Info.Ctx, ArgValues[0]);
return handleLValueToRValueConversion(
Info, E, Definition->getParamDecl(0)->getType().getNonReferenceType(),
- RHS, Result);
+ RHS, Result, Definition->getParent()->isUnion());
}
// Reserve space for the struct members.
@@ -5246,6 +5602,25 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
#ifndef NDEBUG
CXXRecordDecl::base_class_const_iterator BaseIt = RD->bases_begin();
#endif
+ CXXRecordDecl::field_iterator FieldIt = RD->field_begin();
+ auto SkipToField = [&](FieldDecl *FD, bool Indirect) {
+ // We might be initializing the same field again if this is an indirect
+ // field initialization.
+ if (FieldIt == RD->field_end() ||
+ FieldIt->getFieldIndex() > FD->getFieldIndex()) {
+ assert(Indirect && "fields out of order?");
+ return;
+ }
+
+ // Default-initialize any fields with no explicit initializer.
+ for (; !declaresSameEntity(*FieldIt, FD); ++FieldIt) {
+ assert(FieldIt != RD->field_end() && "missing field?");
+ if (!FieldIt->isUnnamedBitfield())
+ Result.getStructField(FieldIt->getFieldIndex()) =
+ getDefaultInitValue(FieldIt->getType());
+ }
+ ++FieldIt;
+ };
for (const auto *I : Definition->inits()) {
LValue Subobject = This;
LValue SubobjectParent = This;
@@ -5274,6 +5649,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
Result = APValue(FD);
Value = &Result.getUnionValue();
} else {
+ SkipToField(FD, false);
Value = &Result.getStructField(FD->getFieldIndex());
}
} else if (IndirectFieldDecl *IFD = I->getIndirectMember()) {
@@ -5293,8 +5669,10 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
if (CD->isUnion())
*Value = APValue(FD);
else
- *Value = APValue(APValue::UninitStruct(), CD->getNumBases(),
- std::distance(CD->field_begin(), CD->field_end()));
+ // FIXME: This immediately starts the lifetime of all members of an
+ // anonymous struct. It would be preferable to strictly start member
+ // lifetime in initialization order.
+ *Value = getDefaultInitValue(Info.Ctx.getRecordType(CD));
}
// Store Subobject as its parent before updating it for the last element
// in the chain.
@@ -5304,8 +5682,11 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
return false;
if (CD->isUnion())
Value = &Value->getUnionValue();
- else
+ else {
+ if (C == IndirectFieldChain.front() && !RD->isUnion())
+ SkipToField(FD, true);
Value = &Value->getStructField(FD->getFieldIndex());
+ }
}
} else {
llvm_unreachable("unknown base initializer kind");
@@ -5334,8 +5715,18 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
EvalObj.finishedConstructingBases();
}
+ // Default-initialize any remaining fields.
+ if (!RD->isUnion()) {
+ for (; FieldIt != RD->field_end(); ++FieldIt) {
+ if (!FieldIt->isUnnamedBitfield())
+ Result.getStructField(FieldIt->getFieldIndex()) =
+ getDefaultInitValue(FieldIt->getType());
+ }
+ }
+
return Success &&
- EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed;
+ EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed &&
+ LifetimeExtendedScope.destroy();
}
static bool HandleConstructorCall(const Expr *E, const LValue &This,
@@ -5350,6 +5741,381 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
Info, Result);
}
+static bool HandleDestructionImpl(EvalInfo &Info, SourceLocation CallLoc,
+ const LValue &This, APValue &Value,
+ QualType T) {
+ // Objects can only be destroyed while they're within their lifetimes.
+ // FIXME: We have no representation for whether an object of type nullptr_t
+ // is in its lifetime; it usually doesn't matter. Perhaps we should model it
+ // as indeterminate instead?
+ if (Value.isAbsent() && !T->isNullPtrType()) {
+ APValue Printable;
+ This.moveInto(Printable);
+ Info.FFDiag(CallLoc, diag::note_constexpr_destroy_out_of_lifetime)
+ << Printable.getAsString(Info.Ctx, Info.Ctx.getLValueReferenceType(T));
+ return false;
+ }
+
+ // Invent an expression for location purposes.
+ // FIXME: We shouldn't need to do this.
+ OpaqueValueExpr LocE(CallLoc, Info.Ctx.IntTy, VK_RValue);
+
+ // For arrays, destroy elements right-to-left.
+ if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(T)) {
+ uint64_t Size = CAT->getSize().getZExtValue();
+ QualType ElemT = CAT->getElementType();
+
+ LValue ElemLV = This;
+ ElemLV.addArray(Info, &LocE, CAT);
+ if (!HandleLValueArrayAdjustment(Info, &LocE, ElemLV, ElemT, Size))
+ return false;
+
+ // Ensure that we have actual array elements available to destroy; the
+ // destructors might mutate the value, so we can't run them on the array
+ // filler.
+ if (Size && Size > Value.getArrayInitializedElts())
+ expandArray(Value, Value.getArraySize() - 1);
+
+ for (; Size != 0; --Size) {
+ APValue &Elem = Value.getArrayInitializedElt(Size - 1);
+ if (!HandleLValueArrayAdjustment(Info, &LocE, ElemLV, ElemT, -1) ||
+ !HandleDestructionImpl(Info, CallLoc, ElemLV, Elem, ElemT))
+ return false;
+ }
+
+ // End the lifetime of this array now.
+ Value = APValue();
+ return true;
+ }
+
+ const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+ if (!RD) {
+ if (T.isDestructedType()) {
+ Info.FFDiag(CallLoc, diag::note_constexpr_unsupported_destruction) << T;
+ return false;
+ }
+
+ Value = APValue();
+ return true;
+ }
+
+ if (RD->getNumVBases()) {
+ Info.FFDiag(CallLoc, diag::note_constexpr_virtual_base) << RD;
+ return false;
+ }
+
+ const CXXDestructorDecl *DD = RD->getDestructor();
+ if (!DD && !RD->hasTrivialDestructor()) {
+ Info.FFDiag(CallLoc);
+ return false;
+ }
+
+ if (!DD || DD->isTrivial() ||
+ (RD->isAnonymousStructOrUnion() && RD->isUnion())) {
+ // A trivial destructor just ends the lifetime of the object. Check for
+ // this case before checking for a body, because we might not bother
+ // building a body for a trivial destructor. Note that it doesn't matter
+ // whether the destructor is constexpr in this case; all trivial
+ // destructors are constexpr.
+ //
+ // If an anonymous union would be destroyed, some enclosing destructor must
+ // have been explicitly defined, and the anonymous union destruction should
+ // have no effect.
+ Value = APValue();
+ return true;
+ }
+
+ if (!Info.CheckCallLimit(CallLoc))
+ return false;
+
+ const FunctionDecl *Definition = nullptr;
+ const Stmt *Body = DD->getBody(Definition);
+
+ if (!CheckConstexprFunction(Info, CallLoc, DD, Definition, Body))
+ return false;
+
+ CallStackFrame Frame(Info, CallLoc, Definition, &This, nullptr);
+
+ // We're now in the period of destruction of this object.
+ unsigned BasesLeft = RD->getNumBases();
+ EvalInfo::EvaluatingDestructorRAII EvalObj(
+ Info,
+ ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries});
+ if (!EvalObj.DidInsert) {
+ // C++2a [class.dtor]p19:
+ // the behavior is undefined if the destructor is invoked for an object
+ // whose lifetime has ended
+ // (Note that formally the lifetime ends when the period of destruction
+ // begins, even though certain uses of the object remain valid until the
+ // period of destruction ends.)
+ Info.FFDiag(CallLoc, diag::note_constexpr_double_destroy);
+ return false;
+ }
+
+ // FIXME: Creating an APValue just to hold a nonexistent return value is
+ // wasteful.
+ APValue RetVal;
+ StmtResult Ret = {RetVal, nullptr};
+ if (EvaluateStmt(Ret, Info, Definition->getBody()) == ESR_Failed)
+ return false;
+
+ // A union destructor does not implicitly destroy its members.
+ if (RD->isUnion())
+ return true;
+
+ const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+
+ // We don't have a good way to iterate fields in reverse, so collect all the
+ // fields first and then walk them backwards.
+ SmallVector<FieldDecl*, 16> Fields(RD->field_begin(), RD->field_end());
+ for (const FieldDecl *FD : llvm::reverse(Fields)) {
+ if (FD->isUnnamedBitfield())
+ continue;
+
+ LValue Subobject = This;
+ if (!HandleLValueMember(Info, &LocE, Subobject, FD, &Layout))
+ return false;
+
+ APValue *SubobjectValue = &Value.getStructField(FD->getFieldIndex());
+ if (!HandleDestructionImpl(Info, CallLoc, Subobject, *SubobjectValue,
+ FD->getType()))
+ return false;
+ }
+
+ if (BasesLeft != 0)
+ EvalObj.startedDestroyingBases();
+
+ // Destroy base classes in reverse order.
+ for (const CXXBaseSpecifier &Base : llvm::reverse(RD->bases())) {
+ --BasesLeft;
+
+ QualType BaseType = Base.getType();
+ LValue Subobject = This;
+ if (!HandleLValueDirectBase(Info, &LocE, Subobject, RD,
+ BaseType->getAsCXXRecordDecl(), &Layout))
+ return false;
+
+ APValue *SubobjectValue = &Value.getStructBase(BasesLeft);
+ if (!HandleDestructionImpl(Info, CallLoc, Subobject, *SubobjectValue,
+ BaseType))
+ return false;
+ }
+ assert(BasesLeft == 0 && "NumBases was wrong?");
+
+ // The period of destruction ends now. The object is gone.
+ Value = APValue();
+ return true;
+}
+
+namespace {
+struct DestroyObjectHandler {
+ EvalInfo &Info;
+ const Expr *E;
+ const LValue &This;
+ const AccessKinds AccessKind;
+
+ typedef bool result_type;
+ bool failed() { return false; }
+ bool found(APValue &Subobj, QualType SubobjType) {
+ return HandleDestructionImpl(Info, E->getExprLoc(), This, Subobj,
+ SubobjType);
+ }
+ bool found(APSInt &Value, QualType SubobjType) {
+ Info.FFDiag(E, diag::note_constexpr_destroy_complex_elem);
+ return false;
+ }
+ bool found(APFloat &Value, QualType SubobjType) {
+ Info.FFDiag(E, diag::note_constexpr_destroy_complex_elem);
+ return false;
+ }
+};
+}
+
+/// Perform a destructor or pseudo-destructor call on the given object, which
+/// might in general not be a complete object.
+static bool HandleDestruction(EvalInfo &Info, const Expr *E,
+ const LValue &This, QualType ThisType) {
+ CompleteObject Obj = findCompleteObject(Info, E, AK_Destroy, This, ThisType);
+ DestroyObjectHandler Handler = {Info, E, This, AK_Destroy};
+ return Obj && findSubobject(Info, E, Obj, This.Designator, Handler);
+}
+
+/// Destroy and end the lifetime of the given complete object.
+static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc,
+ APValue::LValueBase LVBase, APValue &Value,
+ QualType T) {
+ // If we've had an unmodeled side-effect, we can't rely on mutable state
+ // (such as the object we're about to destroy) being correct.
+ if (Info.EvalStatus.HasSideEffects)
+ return false;
+
+ LValue LV;
+ LV.set({LVBase});
+ return HandleDestructionImpl(Info, Loc, LV, Value, T);
+}
+
+/// Perform a call to 'perator new' or to `__builtin_operator_new'.
+static bool HandleOperatorNewCall(EvalInfo &Info, const CallExpr *E,
+ LValue &Result) {
+ if (Info.checkingPotentialConstantExpression() ||
+ Info.SpeculativeEvaluationDepth)
+ return false;
+
+ // This is permitted only within a call to std::allocator<T>::allocate.
+ auto Caller = Info.getStdAllocatorCaller("allocate");
+ if (!Caller) {
+ Info.FFDiag(E->getExprLoc(), Info.getLangOpts().CPlusPlus2a
+ ? diag::note_constexpr_new_untyped
+ : diag::note_constexpr_new);
+ return false;
+ }
+
+ QualType ElemType = Caller.ElemType;
+ if (ElemType->isIncompleteType() || ElemType->isFunctionType()) {
+ Info.FFDiag(E->getExprLoc(),
+ diag::note_constexpr_new_not_complete_object_type)
+ << (ElemType->isIncompleteType() ? 0 : 1) << ElemType;
+ return false;
+ }
+
+ APSInt ByteSize;
+ if (!EvaluateInteger(E->getArg(0), ByteSize, Info))
+ return false;
+ bool IsNothrow = false;
+ for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I) {
+ EvaluateIgnoredValue(Info, E->getArg(I));
+ IsNothrow |= E->getType()->isNothrowT();
+ }
+
+ CharUnits ElemSize;
+ if (!HandleSizeof(Info, E->getExprLoc(), ElemType, ElemSize))
+ return false;
+ APInt Size, Remainder;
+ APInt ElemSizeAP(ByteSize.getBitWidth(), ElemSize.getQuantity());
+ APInt::udivrem(ByteSize, ElemSizeAP, Size, Remainder);
+ if (Remainder != 0) {
+ // This likely indicates a bug in the implementation of 'std::allocator'.
+ Info.FFDiag(E->getExprLoc(), diag::note_constexpr_operator_new_bad_size)
+ << ByteSize << APSInt(ElemSizeAP, true) << ElemType;
+ return false;
+ }
+
+ if (ByteSize.getActiveBits() > ConstantArrayType::getMaxSizeBits(Info.Ctx)) {
+ if (IsNothrow) {
+ Result.setNull(Info.Ctx, E->getType());
+ return true;
+ }
+
+ Info.FFDiag(E, diag::note_constexpr_new_too_large) << APSInt(Size, true);
+ return false;
+ }
+
+ QualType AllocType = Info.Ctx.getConstantArrayType(ElemType, Size, nullptr,
+ ArrayType::Normal, 0);
+ APValue *Val = Info.createHeapAlloc(E, AllocType, Result);
+ *Val = APValue(APValue::UninitArray(), 0, Size.getZExtValue());
+ Result.addArray(Info, E, cast<ConstantArrayType>(AllocType));
+ return true;
+}
+
+static bool hasVirtualDestructor(QualType T) {
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ if (CXXDestructorDecl *DD = RD->getDestructor())
+ return DD->isVirtual();
+ return false;
+}
+
+static const FunctionDecl *getVirtualOperatorDelete(QualType T) {
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ if (CXXDestructorDecl *DD = RD->getDestructor())
+ return DD->isVirtual() ? DD->getOperatorDelete() : nullptr;
+ return nullptr;
+}
+
+/// Check that the given object is a suitable pointer to a heap allocation that
+/// still exists and is of the right kind for the purpose of a deletion.
+///
+/// On success, returns the heap allocation to deallocate. On failure, produces
+/// a diagnostic and returns None.
+static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
+ const LValue &Pointer,
+ DynAlloc::Kind DeallocKind) {
+ auto PointerAsString = [&] {
+ return Pointer.toString(Info.Ctx, Info.Ctx.VoidPtrTy);
+ };
+
+ DynamicAllocLValue DA = Pointer.Base.dyn_cast<DynamicAllocLValue>();
+ if (!DA) {
+ Info.FFDiag(E, diag::note_constexpr_delete_not_heap_alloc)
+ << PointerAsString();
+ if (Pointer.Base)
+ NoteLValueLocation(Info, Pointer.Base);
+ return None;
+ }
+
+ Optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
+ if (!Alloc) {
+ Info.FFDiag(E, diag::note_constexpr_double_delete);
+ return None;
+ }
+
+ QualType AllocType = Pointer.Base.getDynamicAllocType();
+ if (DeallocKind != (*Alloc)->getKind()) {
+ Info.FFDiag(E, diag::note_constexpr_new_delete_mismatch)
+ << DeallocKind << (*Alloc)->getKind() << AllocType;
+ NoteLValueLocation(Info, Pointer.Base);
+ return None;
+ }
+
+ bool Subobject = false;
+ if (DeallocKind == DynAlloc::New) {
+ Subobject = Pointer.Designator.MostDerivedPathLength != 0 ||
+ Pointer.Designator.isOnePastTheEnd();
+ } else {
+ Subobject = Pointer.Designator.Entries.size() != 1 ||
+ Pointer.Designator.Entries[0].getAsArrayIndex() != 0;
+ }
+ if (Subobject) {
+ Info.FFDiag(E, diag::note_constexpr_delete_subobject)
+ << PointerAsString() << Pointer.Designator.isOnePastTheEnd();
+ return None;
+ }
+
+ return Alloc;
+}
+
+// Perform a call to 'operator delete' or '__builtin_operator_delete'.
+bool HandleOperatorDeleteCall(EvalInfo &Info, const CallExpr *E) {
+ if (Info.checkingPotentialConstantExpression() ||
+ Info.SpeculativeEvaluationDepth)
+ return false;
+
+ // This is permitted only within a call to std::allocator<T>::deallocate.
+ if (!Info.getStdAllocatorCaller("deallocate")) {
+ Info.FFDiag(E->getExprLoc());
+ return true;
+ }
+
+ LValue Pointer;
+ if (!EvaluatePointer(E->getArg(0), Pointer, Info))
+ return false;
+ for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I)
+ EvaluateIgnoredValue(Info, E->getArg(I));
+
+ if (Pointer.Designator.Invalid)
+ return false;
+
+ // Deleting a null pointer has no effect.
+ if (Pointer.isNullPointer())
+ return true;
+
+ if (!CheckDeleteKind(Info, E, Pointer, DynAlloc::StdAllocator))
+ return false;
+
+ Info.HeapAllocs.erase(Pointer.Base.get<DynamicAllocLValue>());
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Generic Evaluation
//===----------------------------------------------------------------------===//
@@ -5682,9 +6448,8 @@ class BufferToAPValueConverter {
QualType RepresentationType = Ty->getDecl()->getIntegerType();
assert(!RepresentationType.isNull() &&
"enum forward decl should be caught by Sema");
- const BuiltinType *AsBuiltin =
- RepresentationType.getCanonicalType()->getAs<BuiltinType>();
- assert(AsBuiltin && "non-integral enum underlying type?");
+ const auto *AsBuiltin =
+ RepresentationType.getCanonicalType()->castAs<BuiltinType>();
// Recurse into the underlying type. Treat std::byte transparently as
// unsigned char.
return visit(AsBuiltin, Offset, /*EnumTy=*/Ty);
@@ -5728,7 +6493,7 @@ class BufferToAPValueConverter {
#define NON_CANONICAL_UNLESS_DEPENDENT(Class, Base) \
case Type::Class: \
llvm_unreachable("either dependent or not canonical!");
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
llvm_unreachable("Unhandled Type::TypeClass");
}
@@ -5819,9 +6584,9 @@ static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
LValue SourceLValue;
APValue SourceRValue;
SourceLValue.setFrom(Info.Ctx, SourceValue);
- if (!handleLValueToRValueConversion(Info, BCE,
- BCE->getSubExpr()->getType().withConst(),
- SourceLValue, SourceRValue))
+ if (!handleLValueToRValueConversion(
+ Info, BCE, BCE->getSubExpr()->getType().withConst(), SourceLValue,
+ SourceRValue, /*WantObjectRepresentation=*/true))
return false;
// Read out SourceValue into a char buffer.
@@ -5960,10 +6725,16 @@ public:
return StmtVisitorTy::Visit(E->getExpr());
}
- // We cannot create any objects for which cleanups are required, so there is
- // nothing to do here; all cleanups must come from unevaluated subexpressions.
- bool VisitExprWithCleanups(const ExprWithCleanups *E)
- { return StmtVisitorTy::Visit(E->getSubExpr()); }
+ bool VisitExprWithCleanups(const ExprWithCleanups *E) {
+ FullExpressionRAII Scope(Info);
+ return StmtVisitorTy::Visit(E->getSubExpr()) && Scope.destroy();
+ }
+
+ // Temporaries are registered when created, so we don't care about
+ // CXXBindTemporaryExpr.
+ bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E) {
+ return StmtVisitorTy::Visit(E->getSubExpr());
+ }
bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) {
CCEDiag(E, diag::note_constexpr_invalid_cast) << 0;
@@ -6000,10 +6771,18 @@ public:
}
}
+ bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E) {
+ return StmtVisitorTy::Visit(E->getSemanticForm());
+ }
+
bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
// Evaluate and cache the common expression. We treat it as a temporary,
// even though it's not quite the same thing.
- if (!Evaluate(Info.CurrentCall->createTemporary(E->getOpaqueValue(), false),
+ LValue CommonLV;
+ if (!Evaluate(Info.CurrentCall->createTemporary(
+ E->getOpaqueValue(),
+ getStorageType(Info.Ctx, E->getOpaqueValue()), false,
+ CommonLV),
Info, E->getCommon()))
return false;
@@ -6051,6 +6830,36 @@ public:
return StmtVisitorTy::Visit(Source);
}
+ bool VisitPseudoObjectExpr(const PseudoObjectExpr *E) {
+ for (const Expr *SemE : E->semantics()) {
+ if (auto *OVE = dyn_cast<OpaqueValueExpr>(SemE)) {
+ // FIXME: We can't handle the case where an OpaqueValueExpr is also the
+ // result expression: there could be two different LValues that would
+ // refer to the same object in that case, and we can't model that.
+ if (SemE == E->getResultExpr())
+ return Error(E);
+
+ // Unique OVEs get evaluated if and when we encounter them when
+ // emitting the rest of the semantic form, rather than eagerly.
+ if (OVE->isUnique())
+ continue;
+
+ LValue LV;
+ if (!Evaluate(Info.CurrentCall->createTemporary(
+ OVE, getStorageType(Info.Ctx, OVE), false, LV),
+ Info, OVE->getSourceExpr()))
+ return false;
+ } else if (SemE == E->getResultExpr()) {
+ if (!StmtVisitorTy::Visit(SemE))
+ return false;
+ } else {
+ if (!EvaluateIgnoredValue(Info, SemE))
+ return false;
+ }
+ }
+ return true;
+ }
+
bool VisitCallExpr(const CallExpr *E) {
APValue Result;
if (!handleCallExpr(E, Result, nullptr))
@@ -6082,11 +6891,21 @@ public:
HasQualifier = ME->hasQualifier();
} else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(Callee)) {
// Indirect bound member calls ('.*' or '->*').
- Member = dyn_cast_or_null<CXXMethodDecl>(
- HandleMemberPointerAccess(Info, BE, ThisVal, false));
+ const ValueDecl *D =
+ HandleMemberPointerAccess(Info, BE, ThisVal, false);
+ if (!D)
+ return false;
+ Member = dyn_cast<CXXMethodDecl>(D);
if (!Member)
return Error(Callee);
This = &ThisVal;
+ } else if (const auto *PDE = dyn_cast<CXXPseudoDestructorExpr>(Callee)) {
+ if (!Info.getLangOpts().CPlusPlus2a)
+ Info.CCEDiag(PDE, diag::note_constexpr_pseudo_destructor);
+ // FIXME: If pseudo-destructor calls ever start ending the lifetime of
+ // their callee, we should start calling HandleDestruction here.
+ // For now, we just evaluate the object argument and discard it.
+ return EvaluateObjectArgument(Info, PDE->getBase(), ThisVal);
} else
return Error(Callee);
FD = Member;
@@ -6155,6 +6974,17 @@ public:
FD = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);
} else
FD = LambdaCallOp;
+ } else if (FD->isReplaceableGlobalAllocationFunction()) {
+ if (FD->getDeclName().getCXXOverloadedOperator() == OO_New ||
+ FD->getDeclName().getCXXOverloadedOperator() == OO_Array_New) {
+ LValue Ptr;
+ if (!HandleOperatorNewCall(Info, E, Ptr))
+ return false;
+ Ptr.moveInto(Result);
+ return true;
+ } else {
+ return HandleOperatorDeleteCall(Info, E);
+ }
}
} else
return Error(E);
@@ -6170,11 +7000,20 @@ public:
return false;
} else {
// Check that the 'this' pointer points to an object of the right type.
- if (!checkNonVirtualMemberCallThisPointer(Info, E, *This))
+ // FIXME: If this is an assignment operator call, we may need to change
+ // the active union member before we check this.
+ if (!checkNonVirtualMemberCallThisPointer(Info, E, *This, NamedMember))
return false;
}
}
+ // Destructor calls are different enough that they have their own codepath.
+ if (auto *DD = dyn_cast<CXXDestructorDecl>(FD)) {
+ assert(This && "no 'this' pointer for destructor call");
+ return HandleDestruction(Info, E, *This,
+ Info.Ctx.getRecordType(DD->getParent()));
+ }
+
const FunctionDecl *Definition = nullptr;
Stmt *Body = FD->getBody(Definition);
@@ -6241,6 +7080,31 @@ public:
DerivedSuccess(Result, E);
}
+ bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E) {
+ APValue Val;
+ if (!Evaluate(Val, Info, E->getBase()))
+ return false;
+
+ if (Val.isVector()) {
+ SmallVector<uint32_t, 4> Indices;
+ E->getEncodedElementAccess(Indices);
+ if (Indices.size() == 1) {
+ // Return scalar.
+ return DerivedSuccess(Val.getVectorElt(Indices[0]), E);
+ } else {
+ // Construct new APValue vector.
+ SmallVector<APValue, 4> Elts;
+ for (unsigned I = 0; I < Indices.size(); ++I) {
+ Elts.push_back(Val.getVectorElt(Indices[I]));
+ }
+ APValue VecResult(Elts.data(), Indices.size());
+ return DerivedSuccess(VecResult, E);
+ }
+ }
+
+ return false;
+ }
+
bool VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
default:
@@ -6279,6 +7143,13 @@ public:
return false;
return DerivedSuccess(DestValue, E);
}
+
+ case CK_AddressSpaceConversion: {
+ APValue Value;
+ if (!Evaluate(Value, Info, E->getSubExpr()))
+ return false;
+ return DerivedSuccess(Value, E);
+ }
}
return Error(E);
@@ -6310,11 +7181,11 @@ public:
if (Info.checkingForUndefinedBehavior())
return Error(E);
- BlockScopeRAII Scope(Info);
const CompoundStmt *CS = E->getSubStmt();
if (CS->body_empty())
return true;
+ BlockScopeRAII Scope(Info);
for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
BE = CS->body_end();
/**/; ++BI) {
@@ -6325,7 +7196,7 @@ public:
diag::note_constexpr_stmt_expr_unsupported);
return false;
}
- return this->Visit(FinalExpr);
+ return this->Visit(FinalExpr) && Scope.destroy();
}
APValue ReturnValue;
@@ -6418,7 +7289,7 @@ public:
const ValueDecl *MD = E->getMemberDecl();
if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
- assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
+ assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() ==
FD->getParent()->getCanonicalDecl() && "record / field mismatch");
(void)BaseTy;
if (!HandleLValueMember(this->Info, E, Result, FD))
@@ -6657,8 +7528,8 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
// Walk through the expression to find the materialized temporary itself.
SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
- const Expr *Inner = E->GetTemporaryExpr()->
- skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+ const Expr *Inner =
+ E->getSubExpr()->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
// If we passed any comma operators, evaluate their LHSs.
for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
@@ -6670,20 +7541,18 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
// value for use outside this evaluation.
APValue *Value;
if (E->getStorageDuration() == SD_Static) {
- Value = Info.Ctx.getMaterializedTemporaryValue(E, true);
+ Value = E->getOrCreateValue(true);
*Value = APValue();
Result.set(E);
} else {
- Value = &createTemporary(E, E->getStorageDuration() == SD_Automatic, Result,
- *Info.CurrentCall);
+ Value = &Info.CurrentCall->createTemporary(
+ E, E->getType(), E->getStorageDuration() == SD_Automatic, Result);
}
QualType Type = Inner->getType();
// Materialize the temporary itself.
- if (!EvaluateInPlace(*Value, Info, Result, Inner) ||
- (E->getStorageDuration() == SD_Static &&
- !CheckConstantExpression(Info, E->getExprLoc(), Type, *Value))) {
+ if (!EvaluateInPlace(*Value, Info, Result, Inner)) {
*Value = APValue();
return false;
}
@@ -7013,8 +7882,7 @@ public:
return true;
}
bool ZeroInitialization(const Expr *E) {
- auto TargetVal = Info.Ctx.getTargetNullPointerValue(E->getType());
- Result.setNull(E->getType(), TargetVal);
+ Result.setNull(Info.Ctx, E->getType());
return true;
}
@@ -7056,6 +7924,11 @@ public:
// either copied into the closure object's field that represents the '*this'
// or refers to '*this'.
if (isLambdaCallOperator(Info.CurrentCall->Callee)) {
+ // Ensure we actually have captured 'this'. (an error will have
+ // been previously reported if not).
+ if (!Info.CurrentCall->LambdaThisCaptureField)
+ return false;
+
// Update 'Result' to refer to the data member/field of the closure object
// that represents the '*this' capture.
if (!HandleLValueMember(Info, E, Result,
@@ -7075,6 +7948,8 @@ public:
return true;
}
+ bool VisitCXXNewExpr(const CXXNewExpr *E);
+
bool VisitSourceLocExpr(const SourceLocExpr *E) {
assert(E->isStringType() && "SourceLocExpr isn't a pointer type?");
APValue LValResult = E->EvaluateInContext(
@@ -7139,12 +8014,22 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
// permitted in constant expressions in C++11. Bitcasts from cv void* are
// also static_casts, but we disallow them as a resolution to DR1312.
if (!E->getType()->isVoidPointerType()) {
- Result.Designator.setInvalid();
- if (SubExpr->getType()->isVoidPointerType())
- CCEDiag(E, diag::note_constexpr_invalid_cast)
- << 3 << SubExpr->getType();
- else
- CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ if (!Result.InvalidBase && !Result.Designator.Invalid &&
+ !Result.IsNullPtr &&
+ Info.Ctx.hasSameUnqualifiedType(Result.Designator.getType(Info.Ctx),
+ E->getType()->getPointeeType()) &&
+ Info.getStdAllocatorCaller("allocate")) {
+ // Inside a call to std::allocator::allocate and friends, we permit
+ // casting from void* back to cv1 T* for a pointer that points to a
+ // cv2 T.
+ } else {
+ Result.Designator.setInvalid();
+ if (SubExpr->getType()->isVoidPointerType())
+ CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << 3 << SubExpr->getType();
+ else
+ CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ }
}
if (E->getCastKind() == CK_AddressSpaceConversion && Result.IsNullPtr)
ZeroInitialization(E);
@@ -7207,8 +8092,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!evaluateLValue(SubExpr, Result))
return false;
} else {
- APValue &Value = createTemporary(SubExpr, false, Result,
- *Info.CurrentCall);
+ APValue &Value = Info.CurrentCall->createTemporary(
+ SubExpr, SubExpr->getType(), false, Result);
if (!EvaluateInPlace(Value, Info, Result, SubExpr))
return false;
}
@@ -7290,6 +8175,42 @@ static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E,
return GetAlignOfType(Info, E->getType(), ExprKind);
}
+static CharUnits getBaseAlignment(EvalInfo &Info, const LValue &Value) {
+ if (const auto *VD = Value.Base.dyn_cast<const ValueDecl *>())
+ return Info.Ctx.getDeclAlign(VD);
+ if (const auto *E = Value.Base.dyn_cast<const Expr *>())
+ return GetAlignOfExpr(Info, E, UETT_AlignOf);
+ return GetAlignOfType(Info, Value.Base.getTypeInfoType(), UETT_AlignOf);
+}
+
+/// Evaluate the value of the alignment argument to __builtin_align_{up,down},
+/// __builtin_is_aligned and __builtin_assume_aligned.
+static bool getAlignmentArgument(const Expr *E, QualType ForType,
+ EvalInfo &Info, APSInt &Alignment) {
+ if (!EvaluateInteger(E, Alignment, Info))
+ return false;
+ if (Alignment < 0 || !Alignment.isPowerOf2()) {
+ Info.FFDiag(E, diag::note_constexpr_invalid_alignment) << Alignment;
+ return false;
+ }
+ unsigned SrcWidth = Info.Ctx.getIntWidth(ForType);
+ APSInt MaxValue(APInt::getOneBitSet(SrcWidth, SrcWidth - 1));
+ if (APSInt::compareValues(Alignment, MaxValue) > 0) {
+ Info.FFDiag(E, diag::note_constexpr_alignment_too_big)
+ << MaxValue << ForType << Alignment;
+ return false;
+ }
+ // Ensure both alignment and source value have the same bit width so that we
+ // don't assert when computing the resulting value.
+ APSInt ExtAlignment =
+ APSInt(Alignment.zextOrTrunc(SrcWidth), /*isUnsigned=*/true);
+ assert(APSInt::compareValues(Alignment, ExtAlignment) == 0 &&
+ "Alignment should not be changed by ext/trunc");
+ Alignment = ExtAlignment;
+ assert(Alignment.getBitWidth() == SrcWidth);
+ return true;
+}
+
// To be clear: this happily visits unsupported builtins. Better name welcomed.
bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {
if (ExprEvaluatorBaseTy::VisitCallExpr(E))
@@ -7328,7 +8249,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
LValue OffsetResult(Result);
APSInt Alignment;
- if (!EvaluateInteger(E->getArg(1), Alignment, Info))
+ if (!getAlignmentArgument(E->getArg(1), E->getArg(0)->getType(), Info,
+ Alignment))
return false;
CharUnits Align = CharUnits::fromQuantity(Alignment.getZExtValue());
@@ -7343,16 +8265,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
// If there is a base object, then it must have the correct alignment.
if (OffsetResult.Base) {
- CharUnits BaseAlignment;
- if (const ValueDecl *VD =
- OffsetResult.Base.dyn_cast<const ValueDecl*>()) {
- BaseAlignment = Info.Ctx.getDeclAlign(VD);
- } else if (const Expr *E = OffsetResult.Base.dyn_cast<const Expr *>()) {
- BaseAlignment = GetAlignOfExpr(Info, E, UETT_AlignOf);
- } else {
- BaseAlignment = GetAlignOfType(
- Info, OffsetResult.Base.getTypeInfoType(), UETT_AlignOf);
- }
+ CharUnits BaseAlignment = getBaseAlignment(Info, OffsetResult);
if (BaseAlignment < Align) {
Result.Designator.setInvalid();
@@ -7381,6 +8294,45 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return true;
}
+ case Builtin::BI__builtin_align_up:
+ case Builtin::BI__builtin_align_down: {
+ if (!evaluatePointer(E->getArg(0), Result))
+ return false;
+ APSInt Alignment;
+ if (!getAlignmentArgument(E->getArg(1), E->getArg(0)->getType(), Info,
+ Alignment))
+ return false;
+ CharUnits BaseAlignment = getBaseAlignment(Info, Result);
+ CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Result.Offset);
+ // For align_up/align_down, we can return the same value if the alignment
+ // is known to be greater or equal to the requested value.
+ if (PtrAlign.getQuantity() >= Alignment)
+ return true;
+
+ // The alignment could be greater than the minimum at run-time, so we cannot
+ // infer much about the resulting pointer value. One case is possible:
+ // For `_Alignas(32) char buf[N]; __builtin_align_down(&buf[idx], 32)` we
+ // can infer the correct index if the requested alignment is smaller than
+ // the base alignment so we can perform the computation on the offset.
+ if (BaseAlignment.getQuantity() >= Alignment) {
+ assert(Alignment.getBitWidth() <= 64 &&
+ "Cannot handle > 64-bit address-space");
+ uint64_t Alignment64 = Alignment.getZExtValue();
+ CharUnits NewOffset = CharUnits::fromQuantity(
+ BuiltinOp == Builtin::BI__builtin_align_down
+ ? llvm::alignDown(Result.Offset.getQuantity(), Alignment64)
+ : llvm::alignTo(Result.Offset.getQuantity(), Alignment64));
+ Result.adjustOffset(NewOffset - Result.Offset);
+ // TODO: diagnose out-of-bounds values/only allow for arrays?
+ return true;
+ }
+ // Otherwise, we cannot constant-evaluate the result.
+ Info.FFDiag(E->getArg(0), diag::note_constexpr_alignment_adjust)
+ << Alignment;
+ return false;
+ }
+ case Builtin::BI__builtin_operator_new:
+ return HandleOperatorNewCall(Info, E, Result);
case Builtin::BI__builtin_launder:
return evaluatePointer(E->getArg(0), Result);
case Builtin::BIstrchr:
@@ -7616,6 +8568,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
while (true) {
APValue Val;
+ // FIXME: Set WantObjectRepresentation to true if we're copying a
+ // char-like type?
if (!handleLValueToRValueConversion(Info, E, T, Src, Val) ||
!handleAssignment(Info, E, Dest, T, Val))
return false;
@@ -7630,10 +8584,208 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
}
default:
- return visitNonBuiltinCallExpr(E);
+ break;
}
+
+ return visitNonBuiltinCallExpr(E);
}
+static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
+ APValue &Result, const InitListExpr *ILE,
+ QualType AllocType);
+
+bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
+ if (!Info.getLangOpts().CPlusPlus2a)
+ Info.CCEDiag(E, diag::note_constexpr_new);
+
+ // We cannot speculatively evaluate a delete expression.
+ if (Info.SpeculativeEvaluationDepth)
+ return false;
+
+ FunctionDecl *OperatorNew = E->getOperatorNew();
+
+ bool IsNothrow = false;
+ bool IsPlacement = false;
+ if (OperatorNew->isReservedGlobalPlacementOperator() &&
+ Info.CurrentCall->isStdFunction() && !E->isArray()) {
+ // FIXME Support array placement new.
+ assert(E->getNumPlacementArgs() == 1);
+ if (!EvaluatePointer(E->getPlacementArg(0), Result, Info))
+ return false;
+ if (Result.Designator.Invalid)
+ return false;
+ IsPlacement = true;
+ } else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
+ Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
+ << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
+ return false;
+ } else if (E->getNumPlacementArgs()) {
+ // The only new-placement list we support is of the form (std::nothrow).
+ //
+ // FIXME: There is no restriction on this, but it's not clear that any
+ // other form makes any sense. We get here for cases such as:
+ //
+ // new (std::align_val_t{N}) X(int)
+ //
+ // (which should presumably be valid only if N is a multiple of
+ // alignof(int), and in any case can't be deallocated unless N is
+ // alignof(X) and X has new-extended alignment).
+ if (E->getNumPlacementArgs() != 1 ||
+ !E->getPlacementArg(0)->getType()->isNothrowT())
+ return Error(E, diag::note_constexpr_new_placement);
+
+ LValue Nothrow;
+ if (!EvaluateLValue(E->getPlacementArg(0), Nothrow, Info))
+ return false;
+ IsNothrow = true;
+ }
+
+ const Expr *Init = E->getInitializer();
+ const InitListExpr *ResizedArrayILE = nullptr;
+
+ QualType AllocType = E->getAllocatedType();
+ if (Optional<const Expr*> ArraySize = E->getArraySize()) {
+ const Expr *Stripped = *ArraySize;
+ for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped);
+ Stripped = ICE->getSubExpr())
+ if (ICE->getCastKind() != CK_NoOp &&
+ ICE->getCastKind() != CK_IntegralCast)
+ break;
+
+ llvm::APSInt ArrayBound;
+ if (!EvaluateInteger(Stripped, ArrayBound, Info))
+ return false;
+
+ // C++ [expr.new]p9:
+ // The expression is erroneous if:
+ // -- [...] its value before converting to size_t [or] applying the
+ // second standard conversion sequence is less than zero
+ if (ArrayBound.isSigned() && ArrayBound.isNegative()) {
+ if (IsNothrow)
+ return ZeroInitialization(E);
+
+ Info.FFDiag(*ArraySize, diag::note_constexpr_new_negative)
+ << ArrayBound << (*ArraySize)->getSourceRange();
+ return false;
+ }
+
+ // -- its value is such that the size of the allocated object would
+ // exceed the implementation-defined limit
+ if (ConstantArrayType::getNumAddressingBits(Info.Ctx, AllocType,
+ ArrayBound) >
+ ConstantArrayType::getMaxSizeBits(Info.Ctx)) {
+ if (IsNothrow)
+ return ZeroInitialization(E);
+
+ Info.FFDiag(*ArraySize, diag::note_constexpr_new_too_large)
+ << ArrayBound << (*ArraySize)->getSourceRange();
+ return false;
+ }
+
+ // -- the new-initializer is a braced-init-list and the number of
+ // array elements for which initializers are provided [...]
+ // exceeds the number of elements to initialize
+ if (Init) {
+ auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType());
+ assert(CAT && "unexpected type for array initializer");
+
+ unsigned Bits =
+ std::max(CAT->getSize().getBitWidth(), ArrayBound.getBitWidth());
+ llvm::APInt InitBound = CAT->getSize().zextOrSelf(Bits);
+ llvm::APInt AllocBound = ArrayBound.zextOrSelf(Bits);
+ if (InitBound.ugt(AllocBound)) {
+ if (IsNothrow)
+ return ZeroInitialization(E);
+
+ Info.FFDiag(*ArraySize, diag::note_constexpr_new_too_small)
+ << AllocBound.toString(10, /*Signed=*/false)
+ << InitBound.toString(10, /*Signed=*/false)
+ << (*ArraySize)->getSourceRange();
+ return false;
+ }
+
+ // If the sizes differ, we must have an initializer list, and we need
+ // special handling for this case when we initialize.
+ if (InitBound != AllocBound)
+ ResizedArrayILE = cast<InitListExpr>(Init);
+ }
+
+ AllocType = Info.Ctx.getConstantArrayType(AllocType, ArrayBound, nullptr,
+ ArrayType::Normal, 0);
+ } else {
+ assert(!AllocType->isArrayType() &&
+ "array allocation with non-array new");
+ }
+
+ APValue *Val;
+ if (IsPlacement) {
+ AccessKinds AK = AK_Construct;
+ struct FindObjectHandler {
+ EvalInfo &Info;
+ const Expr *E;
+ QualType AllocType;
+ const AccessKinds AccessKind;
+ APValue *Value;
+
+ typedef bool result_type;
+ bool failed() { return false; }
+ bool found(APValue &Subobj, QualType SubobjType) {
+ // FIXME: Reject the cases where [basic.life]p8 would not permit the
+ // old name of the object to be used to name the new object.
+ if (!Info.Ctx.hasSameUnqualifiedType(SubobjType, AllocType)) {
+ Info.FFDiag(E, diag::note_constexpr_placement_new_wrong_type) <<
+ SubobjType << AllocType;
+ return false;
+ }
+ Value = &Subobj;
+ return true;
+ }
+ bool found(APSInt &Value, QualType SubobjType) {
+ Info.FFDiag(E, diag::note_constexpr_construct_complex_elem);
+ return false;
+ }
+ bool found(APFloat &Value, QualType SubobjType) {
+ Info.FFDiag(E, diag::note_constexpr_construct_complex_elem);
+ return false;
+ }
+ } Handler = {Info, E, AllocType, AK, nullptr};
+
+ CompleteObject Obj = findCompleteObject(Info, E, AK, Result, AllocType);
+ if (!Obj || !findSubobject(Info, E, Obj, Result.Designator, Handler))
+ return false;
+
+ Val = Handler.Value;
+
+ // [basic.life]p1:
+ // The lifetime of an object o of type T ends when [...] the storage
+ // which the object occupies is [...] reused by an object that is not
+ // nested within o (6.6.2).
+ *Val = APValue();
+ } else {
+ // Perform the allocation and obtain a pointer to the resulting object.
+ Val = Info.createHeapAlloc(E, AllocType, Result);
+ if (!Val)
+ return false;
+ }
+
+ if (ResizedArrayILE) {
+ if (!EvaluateArrayNewInitList(Info, Result, *Val, ResizedArrayILE,
+ AllocType))
+ return false;
+ } else if (Init) {
+ if (!EvaluateInPlace(*Val, Info, Result, Init))
+ return false;
+ } else {
+ *Val = getDefaultInitValue(AllocType);
+ }
+
+ // Array new returns a pointer to the first element, not a pointer to the
+ // array.
+ if (auto *AT = AllocType->getAsArrayTypeUnsafe())
+ Result.addArray(Info, E, cast<ConstantArrayType>(AT));
+
+ return true;
+}
//===----------------------------------------------------------------------===//
// Member Pointer Evaluation
//===----------------------------------------------------------------------===//
@@ -7757,7 +8909,6 @@ namespace {
bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
-
bool VisitBinCmp(const BinaryOperator *E);
};
}
@@ -7991,15 +9142,11 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
if (Result.hasValue())
return true;
- // We can get here in two different ways:
- // 1) We're performing value-initialization, and should zero-initialize
- // the object, or
- // 2) We're performing default-initialization of an object with a trivial
- // constexpr default constructor, in which case we should start the
- // lifetimes of all the base subobjects (there can be no data member
- // subobjects in this case) per [basic.life]p1.
- // Either way, ZeroInitialization is appropriate.
- return ZeroInitialization(E, T);
+ if (ZeroInit)
+ return ZeroInitialization(E, T);
+
+ Result = getDefaultInitValue(T);
+ return true;
}
const FunctionDecl *Definition = nullptr;
@@ -8012,7 +9159,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
if (E->isElidable() && !ZeroInit)
if (const MaterializeTemporaryExpr *ME
= dyn_cast<MaterializeTemporaryExpr>(E->getArg(0)))
- return Visit(ME->GetTemporaryExpr());
+ return Visit(ME->getSubExpr());
if (ZeroInit && !ZeroInitialization(E, T))
return false;
@@ -8099,9 +9246,8 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
const CXXRecordDecl *ClosureClass = E->getLambdaClass();
- if (ClosureClass->isInvalidDecl()) return false;
-
- if (Info.checkingPotentialConstantExpression()) return true;
+ if (ClosureClass->isInvalidDecl())
+ return false;
const size_t NumFields =
std::distance(ClosureClass->field_begin(), ClosureClass->field_end());
@@ -8161,7 +9307,8 @@ public:
/// Visit an expression which constructs the value of this temporary.
bool VisitConstructExpr(const Expr *E) {
- APValue &Value = createTemporary(E, false, Result, *Info.CurrentCall);
+ APValue &Value =
+ Info.CurrentCall->createTemporary(E, E->getType(), false, Result);
return EvaluateInPlace(Value, Info, Result, E);
}
@@ -8231,6 +9378,7 @@ namespace {
bool VisitUnaryImag(const UnaryOperator *E);
// FIXME: Missing: unary -, unary ~, binary add/sub/mul/div,
// binary comparisons, binary and/or/xor,
+ // conditional operator (for GNU conditional select),
// shufflevector, ExtVectorElementExpr
};
} // end anonymous namespace
@@ -8361,7 +9509,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
bool
VectorExprEvaluator::ZeroInitialization(const Expr *E) {
- const VectorType *VT = E->getType()->getAs<VectorType>();
+ const auto *VT = E->getType()->castAs<VectorType>();
QualType EltTy = VT->getElementType();
APValue ZeroElement;
if (EltTy->isIntegerType())
@@ -8419,14 +9567,16 @@ namespace {
bool VisitCallExpr(const CallExpr *E) {
return handleCallExpr(E, Result, &This);
}
- bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitInitListExpr(const InitListExpr *E,
+ QualType AllocType = QualType());
bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E,
const LValue &Subobject,
APValue *Value, QualType Type);
- bool VisitStringLiteral(const StringLiteral *E) {
- expandStringLiteral(Info, E, Result);
+ bool VisitStringLiteral(const StringLiteral *E,
+ QualType AllocType = QualType()) {
+ expandStringLiteral(Info, E, Result, AllocType);
return true;
}
};
@@ -8438,6 +9588,15 @@ static bool EvaluateArray(const Expr *E, const LValue &This,
return ArrayExprEvaluator(Info, This, Result).Visit(E);
}
+static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
+ APValue &Result, const InitListExpr *ILE,
+ QualType AllocType) {
+ assert(ILE->isRValue() && ILE->getType()->isArrayType() &&
+ "not an array rvalue");
+ return ArrayExprEvaluator(Info, This, Result)
+ .VisitInitListExpr(ILE, AllocType);
+}
+
// Return true iff the given array filler may depend on the element index.
static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) {
// For now, just whitelist non-class value-initialization and initialization
@@ -8454,15 +9613,23 @@ static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) {
return true;
}
-bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
- const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType());
+bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
+ QualType AllocType) {
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(
+ AllocType.isNull() ? E->getType() : AllocType);
if (!CAT)
return Error(E);
// C++11 [dcl.init.string]p1: A char array [...] can be initialized by [...]
// an appropriately-typed string literal enclosed in braces.
- if (E->isStringLiteralInit())
- return Visit(E->getInit(0));
+ if (E->isStringLiteralInit()) {
+ auto *SL = dyn_cast<StringLiteral>(E->getInit(0)->IgnoreParens());
+ // FIXME: Support ObjCEncodeExpr here once we support it in
+ // ArrayExprEvaluator generally.
+ if (!SL)
+ return Error(E);
+ return VisitStringLiteral(SL, AllocType);
+ }
bool Success = true;
@@ -8521,8 +9688,12 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
}
bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
+ LValue CommonLV;
if (E->getCommonExpr() &&
- !Evaluate(Info.CurrentCall->createTemporary(E->getCommonExpr(), false),
+ !Evaluate(Info.CurrentCall->createTemporary(
+ E->getCommonExpr(),
+ getStorageType(Info.Ctx, E->getCommonExpr()), false,
+ CommonLV),
Info, E->getCommonExpr()->getSourceExpr()))
return false;
@@ -8740,6 +9911,8 @@ public:
bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
bool VisitSourceLocExpr(const SourceLocExpr *E);
+ bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
+ bool VisitRequiresExpr(const RequiresExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
};
@@ -8922,7 +10095,7 @@ EvaluateBuiltinClassifyType(QualType T, const LangOptions &LangOpts) {
#define DEPENDENT_TYPE(ID, BASE) case Type::ID:
#define NON_CANONICAL_TYPE(ID, BASE) case Type::ID:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(ID, BASE) case Type::ID:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
case Type::Auto:
case Type::DeducedTemplateSpecialization:
llvm_unreachable("unexpected non-canonical or dependent type");
@@ -8986,6 +10159,9 @@ EvaluateBuiltinClassifyType(QualType T, const LangOptions &LangOpts) {
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
return GCCTypeClass::None;
case BuiltinType::Dependent:
@@ -9134,11 +10310,13 @@ static QualType getObjectType(APValue::LValueBase B) {
if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->getType();
- } else if (const Expr *E = B.get<const Expr*>()) {
+ } else if (const Expr *E = B.dyn_cast<const Expr*>()) {
if (isa<CompoundLiteralExpr>(E))
return E->getType();
} else if (B.is<TypeInfoLValue>()) {
return B.getTypeInfoType();
+ } else if (B.is<DynamicAllocLValue>()) {
+ return B.getDynamicAllocType();
}
return QualType();
@@ -9453,6 +10631,33 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
+static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info,
+ APValue &Val, APSInt &Alignment) {
+ QualType SrcTy = E->getArg(0)->getType();
+ if (!getAlignmentArgument(E->getArg(1), SrcTy, Info, Alignment))
+ return false;
+ // Even though we are evaluating integer expressions we could get a pointer
+ // argument for the __builtin_is_aligned() case.
+ if (SrcTy->isPointerType()) {
+ LValue Ptr;
+ if (!EvaluatePointer(E->getArg(0), Ptr, Info))
+ return false;
+ Ptr.moveInto(Val);
+ } else if (!SrcTy->isIntegralOrEnumerationType()) {
+ Info.FFDiag(E->getArg(0));
+ return false;
+ } else {
+ APSInt SrcInt;
+ if (!EvaluateInteger(E->getArg(0), SrcInt, Info))
+ return false;
+ assert(SrcInt.getBitWidth() >= Alignment.getBitWidth() &&
+ "Bit widths must be the same");
+ Val = APValue(SrcInt);
+ }
+ assert(Val.hasValue());
+ return true;
+}
+
bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) {
switch (unsigned BuiltinOp = E->getBuiltinCallee()) {
@@ -9495,6 +10700,66 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return Success(Layout.size().getQuantity(), E);
}
+ case Builtin::BI__builtin_is_aligned: {
+ APValue Src;
+ APSInt Alignment;
+ if (!getBuiltinAlignArguments(E, Info, Src, Alignment))
+ return false;
+ if (Src.isLValue()) {
+ // If we evaluated a pointer, check the minimum known alignment.
+ LValue Ptr;
+ Ptr.setFrom(Info.Ctx, Src);
+ CharUnits BaseAlignment = getBaseAlignment(Info, Ptr);
+ CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Ptr.Offset);
+ // We can return true if the known alignment at the computed offset is
+ // greater than the requested alignment.
+ assert(PtrAlign.isPowerOfTwo());
+ assert(Alignment.isPowerOf2());
+ if (PtrAlign.getQuantity() >= Alignment)
+ return Success(1, E);
+ // If the alignment is not known to be sufficient, some cases could still
+ // be aligned at run time. However, if the requested alignment is less or
+ // equal to the base alignment and the offset is not aligned, we know that
+ // the run-time value can never be aligned.
+ if (BaseAlignment.getQuantity() >= Alignment &&
+ PtrAlign.getQuantity() < Alignment)
+ return Success(0, E);
+ // Otherwise we can't infer whether the value is sufficiently aligned.
+ // TODO: __builtin_is_aligned(__builtin_align_{down,up{(expr, N), N)
+ // in cases where we can't fully evaluate the pointer.
+ Info.FFDiag(E->getArg(0), diag::note_constexpr_alignment_compute)
+ << Alignment;
+ return false;
+ }
+ assert(Src.isInt());
+ return Success((Src.getInt() & (Alignment - 1)) == 0 ? 1 : 0, E);
+ }
+ case Builtin::BI__builtin_align_up: {
+ APValue Src;
+ APSInt Alignment;
+ if (!getBuiltinAlignArguments(E, Info, Src, Alignment))
+ return false;
+ if (!Src.isInt())
+ return Error(E);
+ APSInt AlignedVal =
+ APSInt((Src.getInt() + (Alignment - 1)) & ~(Alignment - 1),
+ Src.getInt().isUnsigned());
+ assert(AlignedVal.getBitWidth() == Src.getInt().getBitWidth());
+ return Success(AlignedVal, E);
+ }
+ case Builtin::BI__builtin_align_down: {
+ APValue Src;
+ APSInt Alignment;
+ if (!getBuiltinAlignArguments(E, Info, Src, Alignment))
+ return false;
+ if (!Src.isInt())
+ return Error(E);
+ APSInt AlignedVal =
+ APSInt(Src.getInt() & ~(Alignment - 1), Src.getInt().isUnsigned());
+ assert(AlignedVal.getBitWidth() == Src.getInt().getBitWidth());
+ return Success(AlignedVal, E);
+ }
+
case Builtin::BI__builtin_bswap16:
case Builtin::BI__builtin_bswap32:
case Builtin::BI__builtin_bswap64: {
@@ -9545,8 +10810,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return false;
}
- case Builtin::BI__builtin_is_constant_evaluated:
+ case Builtin::BI__builtin_is_constant_evaluated: {
+ const auto *Callee = Info.CurrentCall->getCallee();
+ if (Info.InConstantContext && !Info.CheckingPotentialConstantExpression &&
+ (Info.CallStackDepth == 1 ||
+ (Info.CallStackDepth == 2 && Callee->isInStdNamespace() &&
+ Callee->getIdentifier() &&
+ Callee->getIdentifier()->isStr("is_constant_evaluated")))) {
+ // FIXME: Find a better way to avoid duplicated diagnostics.
+ if (Info.EvalStatus.Diag)
+ Info.report((Info.CallStackDepth == 1) ? E->getExprLoc()
+ : Info.CurrentCall->CallLoc,
+ diag::warn_is_constant_evaluated_always_true_constexpr)
+ << (Info.CallStackDepth == 1 ? "__builtin_is_constant_evaluated"
+ : "std::is_constant_evaluated");
+ }
+
return Success(Info.InConstantContext, E);
+ }
case Builtin::BI__builtin_ctz:
case Builtin::BI__builtin_ctzl:
@@ -10386,6 +11667,14 @@ public:
}
}
};
+
+enum class CmpResult {
+ Unequal,
+ Less,
+ Equal,
+ Greater,
+ Unordered,
+};
}
template <class SuccessCB, class AfterCB>
@@ -10401,15 +11690,8 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
return false;
};
- using CCR = ComparisonCategoryResult;
- bool IsRelational = E->isRelationalOp();
+ bool IsRelational = E->isRelationalOp() || E->getOpcode() == BO_Cmp;
bool IsEquality = E->isEqualityOp();
- if (E->getOpcode() == BO_Cmp) {
- const ComparisonCategoryInfo &CmpInfo =
- Info.Ctx.CompCategories.getInfoForType(E->getType());
- IsRelational = CmpInfo.isOrdered();
- IsEquality = CmpInfo.isEquality();
- }
QualType LHSTy = E->getLHS()->getType();
QualType RHSTy = E->getRHS()->getType();
@@ -10423,10 +11705,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (!EvaluateInteger(E->getRHS(), RHS, Info) || !LHSOK)
return false;
if (LHS < RHS)
- return Success(CCR::Less, E);
+ return Success(CmpResult::Less, E);
if (LHS > RHS)
- return Success(CCR::Greater, E);
- return Success(CCR::Equal, E);
+ return Success(CmpResult::Greater, E);
+ return Success(CmpResult::Equal, E);
}
if (LHSTy->isFixedPointType() || RHSTy->isFixedPointType()) {
@@ -10439,10 +11721,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (!EvaluateFixedPointOrInteger(E->getRHS(), RHSFX, Info) || !LHSOK)
return false;
if (LHSFX < RHSFX)
- return Success(CCR::Less, E);
+ return Success(CmpResult::Less, E);
if (LHSFX > RHSFX)
- return Success(CCR::Greater, E);
- return Success(CCR::Equal, E);
+ return Success(CmpResult::Greater, E);
+ return Success(CmpResult::Equal, E);
}
if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) {
@@ -10478,12 +11760,12 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
APFloat::cmpResult CR_i =
LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag());
bool IsEqual = CR_r == APFloat::cmpEqual && CR_i == APFloat::cmpEqual;
- return Success(IsEqual ? CCR::Equal : CCR::Nonequal, E);
+ return Success(IsEqual ? CmpResult::Equal : CmpResult::Unequal, E);
} else {
assert(IsEquality && "invalid complex comparison");
bool IsEqual = LHS.getComplexIntReal() == RHS.getComplexIntReal() &&
LHS.getComplexIntImag() == RHS.getComplexIntImag();
- return Success(IsEqual ? CCR::Equal : CCR::Nonequal, E);
+ return Success(IsEqual ? CmpResult::Equal : CmpResult::Unequal, E);
}
}
@@ -10502,13 +11784,13 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
auto GetCmpRes = [&]() {
switch (LHS.compare(RHS)) {
case APFloat::cmpEqual:
- return CCR::Equal;
+ return CmpResult::Equal;
case APFloat::cmpLessThan:
- return CCR::Less;
+ return CmpResult::Less;
case APFloat::cmpGreaterThan:
- return CCR::Greater;
+ return CmpResult::Greater;
case APFloat::cmpUnordered:
- return CCR::Unordered;
+ return CmpResult::Unordered;
}
llvm_unreachable("Unrecognised APFloat::cmpResult enum");
};
@@ -10530,8 +11812,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (!HasSameBase(LHSValue, RHSValue)) {
// Inequalities and subtractions between unrelated pointers have
// unspecified or undefined behavior.
- if (!IsEquality)
- return Error(E);
+ if (!IsEquality) {
+ Info.FFDiag(E, diag::note_constexpr_pointer_comparison_unspecified);
+ return false;
+ }
// A constant address may compare equal to the address of a symbol.
// The one exception is that address of an object cannot compare equal
// to a null pointer constant.
@@ -10561,7 +11845,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if ((RHSValue.Base && isZeroSized(LHSValue)) ||
(LHSValue.Base && isZeroSized(RHSValue)))
return Error(E);
- return Success(CCR::Nonequal, E);
+ return Success(CmpResult::Unequal, E);
}
const CharUnits &LHSOffset = LHSValue.getLValueOffset();
@@ -10645,10 +11929,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
}
if (CompareLHS < CompareRHS)
- return Success(CCR::Less, E);
+ return Success(CmpResult::Less, E);
if (CompareLHS > CompareRHS)
- return Success(CCR::Greater, E);
- return Success(CCR::Equal, E);
+ return Success(CmpResult::Greater, E);
+ return Success(CmpResult::Equal, E);
}
if (LHSTy->isMemberPointerType()) {
@@ -10669,7 +11953,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
// null, they compare unequal.
if (!LHSValue.getDecl() || !RHSValue.getDecl()) {
bool Equal = !LHSValue.getDecl() && !RHSValue.getDecl();
- return Success(Equal ? CCR::Equal : CCR::Nonequal, E);
+ return Success(Equal ? CmpResult::Equal : CmpResult::Unequal, E);
}
// Otherwise if either is a pointer to a virtual member function, the
@@ -10686,7 +11970,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
// they were dereferenced with a hypothetical object of the associated
// class type.
bool Equal = LHSValue == RHSValue;
- return Success(Equal ? CCR::Equal : CCR::Nonequal, E);
+ return Success(Equal ? CmpResult::Equal : CmpResult::Unequal, E);
}
if (LHSTy->isNullPtrType()) {
@@ -10695,7 +11979,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
// C++11 [expr.rel]p4, [expr.eq]p3: If two operands of type std::nullptr_t
// are compared, the result is true of the operator is <=, >= or ==, and
// false otherwise.
- return Success(CCR::Equal, E);
+ return Success(CmpResult::Equal, E);
}
return DoAfter();
@@ -10705,14 +11989,29 @@ bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) {
if (!CheckLiteralType(Info, E))
return false;
- auto OnSuccess = [&](ComparisonCategoryResult ResKind,
- const BinaryOperator *E) {
+ auto OnSuccess = [&](CmpResult CR, const BinaryOperator *E) {
+ ComparisonCategoryResult CCR;
+ switch (CR) {
+ case CmpResult::Unequal:
+ llvm_unreachable("should never produce Unequal for three-way comparison");
+ case CmpResult::Less:
+ CCR = ComparisonCategoryResult::Less;
+ break;
+ case CmpResult::Equal:
+ CCR = ComparisonCategoryResult::Equal;
+ break;
+ case CmpResult::Greater:
+ CCR = ComparisonCategoryResult::Greater;
+ break;
+ case CmpResult::Unordered:
+ CCR = ComparisonCategoryResult::Unordered;
+ break;
+ }
// Evaluation succeeded. Lookup the information for the comparison category
// type and fetch the VarDecl for the result.
const ComparisonCategoryInfo &CmpInfo =
Info.Ctx.CompCategories.getInfoForType(E->getType());
- const VarDecl *VD =
- CmpInfo.getValueInfo(CmpInfo.makeWeakResult(ResKind))->VD;
+ const VarDecl *VD = CmpInfo.getValueInfo(CmpInfo.makeWeakResult(CCR))->VD;
// Check and evaluate the result as a constant expression.
LValue LV;
LV.set(VD);
@@ -10740,14 +12039,14 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
"DataRecursiveIntBinOpEvaluator should have handled integral types");
if (E->isComparisonOp()) {
- // Evaluate builtin binary comparisons by evaluating them as C++2a three-way
+ // Evaluate builtin binary comparisons by evaluating them as three-way
// comparisons and then translating the result.
- auto OnSuccess = [&](ComparisonCategoryResult ResKind,
- const BinaryOperator *E) {
- using CCR = ComparisonCategoryResult;
- bool IsEqual = ResKind == CCR::Equal,
- IsLess = ResKind == CCR::Less,
- IsGreater = ResKind == CCR::Greater;
+ auto OnSuccess = [&](CmpResult CR, const BinaryOperator *E) {
+ assert((CR != CmpResult::Unequal || E->isEqualityOp()) &&
+ "should only produce Unequal for equality comparisons");
+ bool IsEqual = CR == CmpResult::Equal,
+ IsLess = CR == CmpResult::Less,
+ IsGreater = CR == CmpResult::Greater;
auto Op = E->getOpcode();
switch (Op) {
default:
@@ -10755,10 +12054,14 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
case BO_EQ:
case BO_NE:
return Success(IsEqual == (Op == BO_EQ), E);
- case BO_LT: return Success(IsLess, E);
- case BO_GT: return Success(IsGreater, E);
- case BO_LE: return Success(IsEqual || IsLess, E);
- case BO_GE: return Success(IsEqual || IsGreater, E);
+ case BO_LT:
+ return Success(IsLess, E);
+ case BO_GT:
+ return Success(IsGreater, E);
+ case BO_LE:
+ return Success(IsEqual || IsLess, E);
+ case BO_GE:
+ return Success(IsEqual || IsGreater, E);
}
};
return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() {
@@ -10816,7 +12119,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
Info.CCEDiag(E, diag::note_constexpr_pointer_subtraction_not_same_array);
QualType Type = E->getLHS()->getType();
- QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
+ QualType ElementType = Type->castAs<PointerType>()->getPointeeType();
CharUnits ElementSize;
if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize))
@@ -11224,6 +12527,15 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
return Success(E->getValue(), E);
}
+bool IntExprEvaluator::VisitConceptSpecializationExpr(
+ const ConceptSpecializationExpr *E) {
+ return Success(E->isSatisfied(), E);
+}
+
+bool IntExprEvaluator::VisitRequiresExpr(const RequiresExpr *E) {
+ return Success(E->isSatisfied(), E);
+}
+
bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
switch (E->getOpcode()) {
default:
@@ -11713,9 +13025,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
- QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType To = E->getType()->castAs<ComplexType>()->getElementType();
QualType From
- = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
return HandleFloatToFloatCast(Info, E, From, To, Result.FloatReal) &&
HandleFloatToFloatCast(Info, E, From, To, Result.FloatImag);
@@ -11725,9 +13037,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
- QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType To = E->getType()->castAs<ComplexType>()->getElementType();
QualType From
- = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.makeComplexInt();
return HandleFloatToIntCast(Info, E, From, Result.FloatReal,
To, Result.IntReal) &&
@@ -11749,9 +13061,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
- QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType To = E->getType()->castAs<ComplexType>()->getElementType();
QualType From
- = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.IntReal = HandleIntToIntCast(Info, E, To, From, Result.IntReal);
Result.IntImag = HandleIntToIntCast(Info, E, To, From, Result.IntImag);
@@ -12125,17 +13437,98 @@ public:
bool VisitCallExpr(const CallExpr *E) {
switch (E->getBuiltinCallee()) {
- default:
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
case Builtin::BI__assume:
case Builtin::BI__builtin_assume:
// The argument is not evaluated!
return true;
+
+ case Builtin::BI__builtin_operator_delete:
+ return HandleOperatorDeleteCall(Info, E);
+
+ default:
+ break;
}
+
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
+
+ bool VisitCXXDeleteExpr(const CXXDeleteExpr *E);
};
} // end anonymous namespace
+bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
+ // We cannot speculatively evaluate a delete expression.
+ if (Info.SpeculativeEvaluationDepth)
+ return false;
+
+ FunctionDecl *OperatorDelete = E->getOperatorDelete();
+ if (!OperatorDelete->isReplaceableGlobalAllocationFunction()) {
+ Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
+ << isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
+ return false;
+ }
+
+ const Expr *Arg = E->getArgument();
+
+ LValue Pointer;
+ if (!EvaluatePointer(Arg, Pointer, Info))
+ return false;
+ if (Pointer.Designator.Invalid)
+ return false;
+
+ // Deleting a null pointer has no effect.
+ if (Pointer.isNullPointer()) {
+ // This is the only case where we need to produce an extension warning:
+ // the only other way we can succeed is if we find a dynamic allocation,
+ // and we will have warned when we allocated it in that case.
+ if (!Info.getLangOpts().CPlusPlus2a)
+ Info.CCEDiag(E, diag::note_constexpr_new);
+ return true;
+ }
+
+ Optional<DynAlloc *> Alloc = CheckDeleteKind(
+ Info, E, Pointer, E->isArrayForm() ? DynAlloc::ArrayNew : DynAlloc::New);
+ if (!Alloc)
+ return false;
+ QualType AllocType = Pointer.Base.getDynamicAllocType();
+
+ // For the non-array case, the designator must be empty if the static type
+ // does not have a virtual destructor.
+ if (!E->isArrayForm() && Pointer.Designator.Entries.size() != 0 &&
+ !hasVirtualDestructor(Arg->getType()->getPointeeType())) {
+ Info.FFDiag(E, diag::note_constexpr_delete_base_nonvirt_dtor)
+ << Arg->getType()->getPointeeType() << AllocType;
+ return false;
+ }
+
+ // For a class type with a virtual destructor, the selected operator delete
+ // is the one looked up when building the destructor.
+ if (!E->isArrayForm() && !E->isGlobalDelete()) {
+ const FunctionDecl *VirtualDelete = getVirtualOperatorDelete(AllocType);
+ if (VirtualDelete &&
+ !VirtualDelete->isReplaceableGlobalAllocationFunction()) {
+ Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
+ << isa<CXXMethodDecl>(VirtualDelete) << VirtualDelete;
+ return false;
+ }
+ }
+
+ if (!HandleDestruction(Info, E->getExprLoc(), Pointer.getLValueBase(),
+ (*Alloc)->Value, AllocType))
+ return false;
+
+ if (!Info.HeapAllocs.erase(Pointer.Base.dyn_cast<DynamicAllocLValue>())) {
+ // The element was already erased. This means the destructor call also
+ // deleted the object.
+ // FIXME: This probably results in undefined behavior before we get this
+ // far, and should be diagnosed elsewhere first.
+ Info.FFDiag(E, diag::note_constexpr_double_delete);
+ return false;
+ }
+
+ return true;
+}
+
static bool EvaluateVoid(const Expr *E, EvalInfo &Info) {
assert(E->isRValue() && E->getType()->isVoidType());
return VoidExprEvaluator(Info).Visit(E);
@@ -12185,13 +13578,14 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
return true;
} else if (T->isArrayType()) {
LValue LV;
- APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall);
+ APValue &Value =
+ Info.CurrentCall->createTemporary(E, T, false, LV);
if (!EvaluateArray(E, LV, Value, Info))
return false;
Result = Value;
} else if (T->isRecordType()) {
LValue LV;
- APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall);
+ APValue &Value = Info.CurrentCall->createTemporary(E, T, false, LV);
if (!EvaluateRecord(E, LV, Value, Info))
return false;
Result = Value;
@@ -12205,7 +13599,7 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
QualType Unqual = T.getAtomicUnqualifiedType();
if (Unqual->isArrayType() || Unqual->isRecordType()) {
LValue LV;
- APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall);
+ APValue &Value = Info.CurrentCall->createTemporary(E, Unqual, false, LV);
if (!EvaluateAtomic(E, &LV, Value, Info))
return false;
} else {
@@ -12255,24 +13649,30 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
/// EvaluateAsRValue - Try to evaluate this expression, performing an implicit
/// lvalue-to-rvalue cast if it is an lvalue.
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
- if (E->getType().isNull())
- return false;
-
- if (!CheckLiteralType(Info, E))
- return false;
+ if (Info.EnableNewConstInterp) {
+ if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
+ return false;
+ } else {
+ if (E->getType().isNull())
+ return false;
- if (!::Evaluate(Result, Info, E))
- return false;
+ if (!CheckLiteralType(Info, E))
+ return false;
- if (E->isGLValue()) {
- LValue LV;
- LV.setFrom(Info.Ctx, Result);
- if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
+ if (!::Evaluate(Result, Info, E))
return false;
+
+ if (E->isGLValue()) {
+ LValue LV;
+ LV.setFrom(Info.Ctx, Result);
+ if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
+ return false;
+ }
}
// Check this core constant expression is a constant expression.
- return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result);
+ return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result) &&
+ CheckMemoryLeaks(Info);
}
static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result,
@@ -12421,10 +13821,12 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
Info.InConstantContext = InConstantContext;
LValue LV;
- if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects ||
+ CheckedTemporaries CheckedTemps;
+ if (!EvaluateLValue(this, LV, Info) || !Info.discardCleanups() ||
+ Result.HasSideEffects ||
!CheckLValueConstantExpression(Info, getExprLoc(),
Ctx.getLValueReferenceType(getType()), LV,
- Expr::EvaluateForCodeGen))
+ Expr::EvaluateForCodeGen, CheckedTemps))
return false;
LV.moveInto(Result.Val);
@@ -12440,11 +13842,15 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage,
EvalInfo Info(Ctx, Result, EM);
Info.InConstantContext = true;
- if (!::Evaluate(Result.Val, Info, this))
+ if (!::Evaluate(Result.Val, Info, this) || Result.HasSideEffects)
return false;
- return CheckConstantExpression(Info, getExprLoc(), getType(), Result.Val,
- Usage);
+ if (!Info.discardCleanups())
+ llvm_unreachable("Unhandled cleanup; missing full expression marker?");
+
+ return CheckConstantExpression(Info, getExprLoc(), getStorageType(Ctx, this),
+ Result.Val, Usage) &&
+ CheckMemoryLeaks(Info);
}
bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
@@ -12462,34 +13868,84 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
Expr::EvalStatus EStatus;
EStatus.Diag = &Notes;
- EvalInfo InitInfo(Ctx, EStatus, VD->isConstexpr()
+ EvalInfo Info(Ctx, EStatus, VD->isConstexpr()
? EvalInfo::EM_ConstantExpression
: EvalInfo::EM_ConstantFold);
- InitInfo.setEvaluatingDecl(VD, Value);
- InitInfo.InConstantContext = true;
+ Info.setEvaluatingDecl(VD, Value);
+ Info.InConstantContext = true;
- LValue LVal;
- LVal.set(VD);
+ SourceLocation DeclLoc = VD->getLocation();
+ QualType DeclTy = VD->getType();
+
+ if (Info.EnableNewConstInterp) {
+ auto &InterpCtx = const_cast<ASTContext &>(Ctx).getInterpContext();
+ if (!InterpCtx.evaluateAsInitializer(Info, VD, Value))
+ return false;
+ } else {
+ LValue LVal;
+ LVal.set(VD);
+
+ // C++11 [basic.start.init]p2:
+ // Variables with static storage duration or thread storage duration shall
+ // be zero-initialized before any other initialization takes place.
+ // This behavior is not present in C.
+ if (Ctx.getLangOpts().CPlusPlus && !VD->hasLocalStorage() &&
+ !DeclTy->isReferenceType()) {
+ ImplicitValueInitExpr VIE(DeclTy);
+ if (!EvaluateInPlace(Value, Info, LVal, &VIE,
+ /*AllowNonLiteralTypes=*/true))
+ return false;
+ }
- // C++11 [basic.start.init]p2:
- // Variables with static storage duration or thread storage duration shall be
- // zero-initialized before any other initialization takes place.
- // This behavior is not present in C.
- if (Ctx.getLangOpts().CPlusPlus && !VD->hasLocalStorage() &&
- !VD->getType()->isReferenceType()) {
- ImplicitValueInitExpr VIE(VD->getType());
- if (!EvaluateInPlace(Value, InitInfo, LVal, &VIE,
- /*AllowNonLiteralTypes=*/true))
+ if (!EvaluateInPlace(Value, Info, LVal, this,
+ /*AllowNonLiteralTypes=*/true) ||
+ EStatus.HasSideEffects)
return false;
+
+ // At this point, any lifetime-extended temporaries are completely
+ // initialized.
+ Info.performLifetimeExtension();
+
+ if (!Info.discardCleanups())
+ llvm_unreachable("Unhandled cleanup; missing full expression marker?");
}
+ return CheckConstantExpression(Info, DeclLoc, DeclTy, Value) &&
+ CheckMemoryLeaks(Info);
+}
+
+bool VarDecl::evaluateDestruction(
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ assert(getEvaluatedValue() && !getEvaluatedValue()->isAbsent() &&
+ "cannot evaluate destruction of non-constant-initialized variable");
+
+ Expr::EvalStatus EStatus;
+ EStatus.Diag = &Notes;
+
+ // Make a copy of the value for the destructor to mutate.
+ APValue DestroyedValue = *getEvaluatedValue();
+
+ EvalInfo Info(getASTContext(), EStatus, EvalInfo::EM_ConstantExpression);
+ Info.setEvaluatingDecl(this, DestroyedValue,
+ EvalInfo::EvaluatingDeclKind::Dtor);
+ Info.InConstantContext = true;
+
+ SourceLocation DeclLoc = getLocation();
+ QualType DeclTy = getType();
- if (!EvaluateInPlace(Value, InitInfo, LVal, this,
- /*AllowNonLiteralTypes=*/true) ||
+ LValue LVal;
+ LVal.set(this);
+
+ // FIXME: Consider storing whether this variable has constant destruction in
+ // the EvaluatedStmt so that CodeGen can query it.
+ if (!HandleDestruction(Info, DeclLoc, LVal.Base, DestroyedValue, DeclTy) ||
EStatus.HasSideEffects)
return false;
- return CheckConstantExpression(InitInfo, VD->getLocation(), VD->getType(),
- Value);
+ if (!Info.discardCleanups())
+ llvm_unreachable("Unhandled cleanup; missing full expression marker?");
+
+ ensureEvaluatedStmt()->HasConstantDestruction = true;
+ return true;
}
/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
@@ -12736,6 +14192,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXScalarValueInitExprClass:
case Expr::TypeTraitExprClass:
+ case Expr::ConceptSpecializationExprClass:
+ case Expr::RequiresExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::CXXNoexceptExprClass:
@@ -12750,6 +14208,9 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
return CheckEvalInICE(E, Ctx);
return ICEDiag(IK_NotICE, E->getBeginLoc());
}
+ case Expr::CXXRewrittenBinaryOperatorClass:
+ return CheckICE(cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm(),
+ Ctx);
case Expr::DeclRefExprClass: {
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
return NoDiag();
@@ -13095,7 +14556,11 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
APValue Scratch;
- bool IsConstExpr = ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch);
+ bool IsConstExpr =
+ ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch) &&
+ // FIXME: We don't produce a diagnostic for this, but the callers that
+ // call us on arbitrary full-expressions should generally not care.
+ Info.discardCleanups() && !Status.HasSideEffects;
if (!Diags.empty()) {
IsConstExpr = false;
@@ -13127,27 +14592,42 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
assert(MD && "Don't provide `this` for non-methods.");
assert(!MD->isStatic() && "Don't provide `this` for static methods.");
#endif
- if (EvaluateObjectArgument(Info, This, ThisVal))
+ if (!This->isValueDependent() &&
+ EvaluateObjectArgument(Info, This, ThisVal) &&
+ !Info.EvalStatus.HasSideEffects)
ThisPtr = &ThisVal;
- if (Info.EvalStatus.HasSideEffects)
- return false;
+
+ // Ignore any side-effects from a failed evaluation. This is safe because
+ // they can't interfere with any other argument evaluation.
+ Info.EvalStatus.HasSideEffects = false;
}
ArgVector ArgValues(Args.size());
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
if ((*I)->isValueDependent() ||
- !Evaluate(ArgValues[I - Args.begin()], Info, *I))
+ !Evaluate(ArgValues[I - Args.begin()], Info, *I) ||
+ Info.EvalStatus.HasSideEffects)
// If evaluation fails, throw away the argument entirely.
ArgValues[I - Args.begin()] = APValue();
- if (Info.EvalStatus.HasSideEffects)
- return false;
+
+ // Ignore any side-effects from a failed evaluation. This is safe because
+ // they can't interfere with any other argument evaluation.
+ Info.EvalStatus.HasSideEffects = false;
}
+ // Parameter cleanups happen in the caller and are not part of this
+ // evaluation.
+ Info.discardCleanups();
+ Info.EvalStatus.HasSideEffects = false;
+
// Build fake call to Callee.
CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr,
ArgValues.data());
- return Evaluate(Value, Info, this) && !Info.EvalStatus.HasSideEffects;
+ // FIXME: Missing ExprWithCleanups in enable_if conditions?
+ FullExpressionRAII Scope(Info);
+ return Evaluate(Value, Info, this) && Scope.destroy() &&
+ !Info.EvalStatus.HasSideEffects;
}
bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
@@ -13166,6 +14646,12 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
Info.InConstantContext = true;
Info.CheckingPotentialConstantExpression = true;
+ // The constexpr VM attempts to compile all methods to bytecode here.
+ if (Info.EnableNewConstInterp) {
+ Info.Ctx.getInterpContext().isPotentialConstantExpr(Info, FD);
+ return Diags.empty();
+ }
+
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
const CXXRecordDecl *RD = MD ? MD->getParent()->getCanonicalDecl() : nullptr;
diff --git a/contrib/llvm-project/clang/lib/AST/ExternalASTMerger.cpp b/contrib/llvm-project/clang/lib/AST/ExternalASTMerger.cpp
index 61e657da7c91..88bbe90a4e90 100644
--- a/contrib/llvm-project/clang/lib/AST/ExternalASTMerger.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ExternalASTMerger.cpp
@@ -101,21 +101,103 @@ private:
ExternalASTMerger &Parent;
ASTImporter Reverse;
const ExternalASTMerger::OriginMap &FromOrigins;
-
+ /// @see ExternalASTMerger::ImporterSource::Temporary
+ bool TemporarySource;
+ /// Map of imported declarations back to the declarations they originated
+ /// from.
+ llvm::DenseMap<Decl *, Decl *> ToOrigin;
+ /// @see ExternalASTMerger::ImporterSource::Merger
+ ExternalASTMerger *SourceMerger;
llvm::raw_ostream &logs() { return Parent.logs(); }
public:
LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext,
- FileManager &ToFileManager, ASTContext &FromContext,
- FileManager &FromFileManager,
- const ExternalASTMerger::OriginMap &_FromOrigins)
- : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
- /*MinimalImport=*/true),
- Parent(_Parent), Reverse(FromContext, FromFileManager, ToContext,
- ToFileManager, /*MinimalImport=*/true), FromOrigins(_FromOrigins) {}
+ FileManager &ToFileManager,
+ const ExternalASTMerger::ImporterSource &S,
+ std::shared_ptr<ASTImporterSharedState> SharedState)
+ : ASTImporter(ToContext, ToFileManager, S.getASTContext(),
+ S.getFileManager(),
+ /*MinimalImport=*/true, SharedState),
+ Parent(_Parent),
+ Reverse(S.getASTContext(), S.getFileManager(), ToContext, ToFileManager,
+ /*MinimalImport=*/true),
+ FromOrigins(S.getOriginMap()), TemporarySource(S.isTemporary()),
+ SourceMerger(S.getMerger()) {}
+
+ llvm::Expected<Decl *> ImportImpl(Decl *FromD) override {
+ if (!TemporarySource || !SourceMerger)
+ return ASTImporter::ImportImpl(FromD);
+
+ // If we get here, then this source is importing from a temporary ASTContext
+ // that also has another ExternalASTMerger attached. It could be
+ // possible that the current ExternalASTMerger and the temporary ASTContext
+ // share a common ImporterSource, which means that the temporary
+ // AST could contain declarations that were imported from a source
+ // that this ExternalASTMerger can access directly. Instead of importing
+ // such declarations from the temporary ASTContext, they should instead
+ // be directly imported by this ExternalASTMerger from the original
+ // source. This way the ExternalASTMerger can safely do a minimal import
+ // without creating incomplete declarations originated from a temporary
+ // ASTContext. If we would try to complete such declarations later on, we
+ // would fail to do so as their temporary AST could be deleted (which means
+ // that the missing parts of the minimally imported declaration in that
+ // ASTContext were also deleted).
+ //
+ // The following code tracks back any declaration that needs to be
+ // imported from the temporary ASTContext to a persistent ASTContext.
+ // Then the ExternalASTMerger tries to import from the persistent
+ // ASTContext directly by using the associated ASTImporter. If that
+ // succeeds, this ASTImporter just maps the declarations imported by
+ // the other (persistent) ASTImporter to this (temporary) ASTImporter.
+ // The steps can be visualized like this:
+ //
+ // Target AST <--- 3. Indirect import --- Persistent AST
+ // ^ of persistent decl ^
+ // | |
+ // 1. Current import 2. Tracking back to persistent decl
+ // 4. Map persistent decl |
+ // & pretend we imported. |
+ // | |
+ // Temporary AST -------------------------------'
+
+ // First, ask the ExternalASTMerger of the source where the temporary
+ // declaration originated from.
+ Decl *Persistent = SourceMerger->FindOriginalDecl(FromD);
+ // FromD isn't from a persistent AST, so just do a normal import.
+ if (!Persistent)
+ return ASTImporter::ImportImpl(FromD);
+ // Now ask the current ExternalASTMerger to try import the persistent
+ // declaration into the target.
+ ASTContext &PersistentCtx = Persistent->getASTContext();
+ ASTImporter &OtherImporter = Parent.ImporterForOrigin(PersistentCtx);
+ // Check that we never end up in the current Importer again.
+ assert((&PersistentCtx != &getFromContext()) && (&OtherImporter != this) &&
+ "Delegated to same Importer?");
+ auto DeclOrErr = OtherImporter.Import(Persistent);
+ // Errors when importing the persistent decl are treated as if we
+ // had errors with importing the temporary decl.
+ if (!DeclOrErr)
+ return DeclOrErr.takeError();
+ Decl *D = *DeclOrErr;
+ // Tell the current ASTImporter that this has already been imported
+ // to prevent any further queries for the temporary decl.
+ MapImported(FromD, D);
+ return D;
+ }
+
+ /// Implements the ASTImporter interface for tracking back a declaration
+ /// to its original declaration it came from.
+ Decl *GetOriginalDecl(Decl *To) override {
+ auto It = ToOrigin.find(To);
+ if (It != ToOrigin.end())
+ return It->second;
+ return nullptr;
+ }
/// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin
/// map is kept up to date. Also set the appropriate flags.
void Imported(Decl *From, Decl *To) override {
+ ToOrigin[To] = From;
+
if (auto *ToDC = dyn_cast<DeclContext>(To)) {
const bool LoggingEnabled = Parent.LoggingEnabled();
if (LoggingEnabled)
@@ -314,28 +396,40 @@ void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origi
ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target,
llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) {
+ SharedState = std::make_shared<ASTImporterSharedState>(
+ *Target.AST.getTranslationUnitDecl());
AddSources(Sources);
}
+Decl *ExternalASTMerger::FindOriginalDecl(Decl *D) {
+ assert(&D->getASTContext() == &Target.AST);
+ for (const auto &I : Importers)
+ if (auto Result = I->GetOriginalDecl(D))
+ return Result;
+ return nullptr;
+}
+
void ExternalASTMerger::AddSources(llvm::ArrayRef<ImporterSource> Sources) {
for (const ImporterSource &S : Sources) {
- assert(&S.AST != &Target.AST);
- Importers.push_back(llvm::make_unique<LazyASTImporter>(
- *this, Target.AST, Target.FM, S.AST, S.FM, S.OM));
+ assert(&S.getASTContext() != &Target.AST);
+ // Check that the associated merger actually imports into the source AST.
+ assert(!S.getMerger() || &S.getMerger()->Target.AST == &S.getASTContext());
+ Importers.push_back(std::make_unique<LazyASTImporter>(
+ *this, Target.AST, Target.FM, S, SharedState));
}
}
void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) {
if (LoggingEnabled())
for (const ImporterSource &S : Sources)
- logs() << "(ExternalASTMerger*)" << (void*)this
- << " removing source (ASTContext*)" << (void*)&S.AST
+ logs() << "(ExternalASTMerger*)" << (void *)this
+ << " removing source (ASTContext*)" << (void *)&S.getASTContext()
<< "\n";
Importers.erase(
std::remove_if(Importers.begin(), Importers.end(),
[&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool {
for (const ImporterSource &S : Sources) {
- if (&Importer->getFromContext() == &S.AST)
+ if (&Importer->getFromContext() == &S.getASTContext())
return true;
}
return false;
@@ -345,7 +439,7 @@ void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) {
std::pair<const DeclContext *, DCOrigin> Origin = *OI;
bool Erase = false;
for (const ImporterSource &S : Sources) {
- if (&S.AST == Origin.second.AST) {
+ if (&S.getASTContext() == Origin.second.AST) {
Erase = true;
break;
}
@@ -416,9 +510,7 @@ bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
Decl *LookupRes = C.first.get();
ASTImporter *Importer = C.second;
auto NDOrErr = Importer->Import(LookupRes);
- assert(NDOrErr);
- (void)static_cast<bool>(NDOrErr);
- NamedDecl *ND = cast_or_null<NamedDecl>(*NDOrErr);
+ NamedDecl *ND = cast<NamedDecl>(llvm::cantFail(std::move(NDOrErr)));
assert(ND);
// If we don't import specialization, they are not available via lookup
// because the lookup result is imported TemplateDecl and it does not
diff --git a/contrib/llvm-project/clang/lib/AST/ExternalASTSource.cpp b/contrib/llvm-project/clang/lib/AST/ExternalASTSource.cpp
index 730102757440..837be5527fce 100644
--- a/contrib/llvm-project/clang/lib/AST/ExternalASTSource.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ExternalASTSource.cpp
@@ -24,6 +24,8 @@
using namespace clang;
+char ExternalASTSource::ID;
+
ExternalASTSource::~ExternalASTSource() = default;
llvm::Optional<ExternalASTSource::ASTSourceDescriptor>
diff --git a/contrib/llvm-project/clang/lib/AST/FormatString.cpp b/contrib/llvm-project/clang/lib/AST/FormatString.cpp
index 578d5bc56733..fcc0b3b11e25 100644
--- a/contrib/llvm-project/clang/lib/AST/FormatString.cpp
+++ b/contrib/llvm-project/clang/lib/AST/FormatString.cpp
@@ -359,6 +359,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
case BuiltinType::SChar:
case BuiltinType::UChar:
case BuiltinType::Char_U:
+ case BuiltinType::Bool:
return Match;
}
return NoMatch;
@@ -386,6 +387,9 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
case BuiltinType::SChar:
case BuiltinType::Char_U:
case BuiltinType::UChar:
+ case BuiltinType::Bool:
+ if (T == C.UnsignedShortTy || T == C.ShortTy)
+ return NoMatchTypeConfusion;
return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
: NoMatch;
case BuiltinType::Short:
diff --git a/contrib/llvm-project/clang/lib/AST/FormatStringParsing.h b/contrib/llvm-project/clang/lib/AST/FormatStringParsing.h
index 9da829adcb49..764e5d46394d 100644
--- a/contrib/llvm-project/clang/lib/AST/FormatStringParsing.h
+++ b/contrib/llvm-project/clang/lib/AST/FormatStringParsing.h
@@ -1,3 +1,16 @@
+//===----- FormatStringParsing.h - Format String Parsing --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides some shared functions between printf and scanf format string
+// parsing code.
+//
+//===----------------------------------------------------------------------===//
+
#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
diff --git a/contrib/llvm-project/clang/lib/AST/InheritViz.cpp b/contrib/llvm-project/clang/lib/AST/InheritViz.cpp
index 4b3d5bee5631..2ed0ce1c79c5 100644
--- a/contrib/llvm-project/clang/lib/AST/InheritViz.cpp
+++ b/contrib/llvm-project/clang/lib/AST/InheritViz.cpp
@@ -90,8 +90,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
Out << " \"];\n";
// Display the base classes.
- const CXXRecordDecl *Decl
- = static_cast<const CXXRecordDecl *>(Type->getAs<RecordType>()->getDecl());
+ const auto *Decl =
+ static_cast<const CXXRecordDecl *>(Type->castAs<RecordType>()->getDecl());
for (const auto &Base : Decl->bases()) {
QualType CanonBaseType = Context.getCanonicalType(Base.getType());
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Block.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Block.cpp
new file mode 100644
index 000000000000..5fc93eb39f4e
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Block.cpp
@@ -0,0 +1,87 @@
+//===--- Block.cpp - Allocated blocks for the interpreter -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the classes describing allocated blocks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Block.h"
+#include "Pointer.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+
+
+void Block::addPointer(Pointer *P) {
+ if (IsStatic)
+ return;
+ if (Pointers)
+ Pointers->Prev = P;
+ P->Next = Pointers;
+ P->Prev = nullptr;
+ Pointers = P;
+}
+
+void Block::removePointer(Pointer *P) {
+ if (IsStatic)
+ return;
+ if (Pointers == P)
+ Pointers = P->Next;
+ if (P->Prev)
+ P->Prev->Next = P->Next;
+ if (P->Next)
+ P->Next->Prev = P->Prev;
+}
+
+void Block::cleanup() {
+ if (Pointers == nullptr && IsDead)
+ (reinterpret_cast<DeadBlock *>(this + 1) - 1)->free();
+}
+
+void Block::movePointer(Pointer *From, Pointer *To) {
+ if (IsStatic)
+ return;
+ To->Prev = From->Prev;
+ if (To->Prev)
+ To->Prev->Next = To;
+ To->Next = From->Next;
+ if (To->Next)
+ To->Next->Prev = To;
+ if (Pointers == From)
+ Pointers = To;
+
+ From->Prev = nullptr;
+ From->Next = nullptr;
+}
+
+DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
+ : Root(Root), B(Blk->Desc, Blk->IsStatic, Blk->IsExtern, /*isDead=*/true) {
+ // Add the block to the chain of dead blocks.
+ if (Root)
+ Root->Prev = this;
+
+ Next = Root;
+ Prev = nullptr;
+ Root = this;
+
+ // Transfer pointers.
+ B.Pointers = Blk->Pointers;
+ for (Pointer *P = Blk->Pointers; P; P = P->Next)
+ P->Pointee = &B;
+}
+
+void DeadBlock::free() {
+ if (Prev)
+ Prev->Next = Next;
+ if (Next)
+ Next->Prev = Prev;
+ if (Root == this)
+ Root = Next;
+ ::free(this);
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Block.h b/contrib/llvm-project/clang/lib/AST/Interp/Block.h
new file mode 100644
index 000000000000..97fb9a3ca096
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Block.h
@@ -0,0 +1,140 @@
+//===--- Block.h - Allocated blocks for the interpreter ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the classes describing allocated blocks.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_BLOCK_H
+#define LLVM_CLANG_AST_INTERP_BLOCK_H
+
+#include "Descriptor.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ComparisonCategories.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace interp {
+class Block;
+class DeadBlock;
+class Context;
+class InterpState;
+class Pointer;
+class Function;
+enum PrimType : unsigned;
+
+/// A memory block, either on the stack or in the heap.
+///
+/// The storage described by the block immediately follows it in memory.
+class Block {
+public:
+ // Creates a new block.
+ Block(const llvm::Optional<unsigned> &DeclID, Descriptor *Desc,
+ bool IsStatic = false, bool IsExtern = false)
+ : DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {}
+
+ Block(Descriptor *Desc, bool IsStatic = false, bool IsExtern = false)
+ : DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern),
+ Desc(Desc) {}
+
+ /// Returns the block's descriptor.
+ Descriptor *getDescriptor() const { return Desc; }
+ /// Checks if the block has any live pointers.
+ bool hasPointers() const { return Pointers; }
+ /// Checks if the block is extern.
+ bool isExtern() const { return IsExtern; }
+ /// Checks if the block has static storage duration.
+ bool isStatic() const { return IsStatic; }
+ /// Checks if the block is temporary.
+ bool isTemporary() const { return Desc->IsTemporary; }
+ /// Returns the size of the block.
+ InterpSize getSize() const { return Desc->getAllocSize(); }
+ /// Returns the declaration ID.
+ llvm::Optional<unsigned> getDeclID() const { return DeclID; }
+
+ /// Returns a pointer to the stored data.
+ char *data() { return reinterpret_cast<char *>(this + 1); }
+
+ /// Returns a view over the data.
+ template <typename T>
+ T &deref() { return *reinterpret_cast<T *>(data()); }
+
+ /// Invokes the constructor.
+ void invokeCtor() {
+ std::memset(data(), 0, getSize());
+ if (Desc->CtorFn)
+ Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
+ /*isActive=*/true, Desc);
+ }
+
+protected:
+ friend class Pointer;
+ friend class DeadBlock;
+ friend class InterpState;
+
+ Block(Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead)
+ : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {}
+
+ // Deletes a dead block at the end of its lifetime.
+ void cleanup();
+
+ // Pointer chain management.
+ void addPointer(Pointer *P);
+ void removePointer(Pointer *P);
+ void movePointer(Pointer *From, Pointer *To);
+
+ /// Start of the chain of pointers.
+ Pointer *Pointers = nullptr;
+ /// Unique identifier of the declaration.
+ llvm::Optional<unsigned> DeclID;
+ /// Flag indicating if the block has static storage duration.
+ bool IsStatic = false;
+ /// Flag indicating if the block is an extern.
+ bool IsExtern = false;
+ /// Flag indicating if the pointer is dead.
+ bool IsDead = false;
+ /// Pointer to the stack slot descriptor.
+ Descriptor *Desc;
+};
+
+/// Descriptor for a dead block.
+///
+/// Dead blocks are chained in a double-linked list to deallocate them
+/// whenever pointers become dead.
+class DeadBlock {
+public:
+ /// Copies the block.
+ DeadBlock(DeadBlock *&Root, Block *Blk);
+
+ /// Returns a pointer to the stored data.
+ char *data() { return B.data(); }
+
+private:
+ friend class Block;
+ friend class InterpState;
+
+ void free();
+
+ /// Root pointer of the list.
+ DeadBlock *&Root;
+ /// Previous block in the list.
+ DeadBlock *Prev;
+ /// Next block in the list.
+ DeadBlock *Next;
+
+ /// Actual block storing data and tracking pointers.
+ Block B;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Boolean.h b/contrib/llvm-project/clang/lib/AST/Interp/Boolean.h
new file mode 100644
index 000000000000..3e6c8b5da9f0
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Boolean.h
@@ -0,0 +1,148 @@
+//===--- Boolean.h - Wrapper for boolean types for the VM -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_BOOLEAN_H
+#define LLVM_CLANG_AST_INTERP_BOOLEAN_H
+
+#include <cstddef>
+#include <cstdint>
+#include "Integral.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ComparisonCategories.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace interp {
+
+/// Wrapper around boolean types.
+class Boolean {
+ private:
+ /// Underlying boolean.
+ bool V;
+
+ /// Construct a wrapper from a boolean.
+ explicit Boolean(bool V) : V(V) {}
+
+ public:
+ /// Zero-initializes a boolean.
+ Boolean() : V(false) {}
+
+ bool operator<(Boolean RHS) const { return V < RHS.V; }
+ bool operator>(Boolean RHS) const { return V > RHS.V; }
+ bool operator<=(Boolean RHS) const { return V <= RHS.V; }
+ bool operator>=(Boolean RHS) const { return V >= RHS.V; }
+ bool operator==(Boolean RHS) const { return V == RHS.V; }
+ bool operator!=(Boolean RHS) const { return V != RHS.V; }
+
+ bool operator>(unsigned RHS) const { return static_cast<unsigned>(V) > RHS; }
+
+ Boolean operator-() const { return Boolean(V); }
+ Boolean operator~() const { return Boolean(true); }
+
+ explicit operator unsigned() const { return V; }
+ explicit operator int64_t() const { return V; }
+ explicit operator uint64_t() const { return V; }
+
+ APSInt toAPSInt() const {
+ return APSInt(APInt(1, static_cast<uint64_t>(V), false), true);
+ }
+ APSInt toAPSInt(unsigned NumBits) const {
+ return APSInt(toAPSInt().zextOrTrunc(NumBits), true);
+ }
+ APValue toAPValue() const { return APValue(toAPSInt()); }
+
+ Boolean toUnsigned() const { return *this; }
+
+ constexpr static unsigned bitWidth() { return true; }
+ bool isZero() const { return !V; }
+ bool isMin() const { return isZero(); }
+
+ constexpr static bool isMinusOne() { return false; }
+
+ constexpr static bool isSigned() { return false; }
+
+ constexpr static bool isNegative() { return false; }
+ constexpr static bool isPositive() { return !isNegative(); }
+
+ ComparisonCategoryResult compare(const Boolean &RHS) const {
+ return Compare(V, RHS.V);
+ }
+
+ unsigned countLeadingZeros() const { return V ? 0 : 1; }
+
+ Boolean truncate(unsigned TruncBits) const { return *this; }
+
+ void print(llvm::raw_ostream &OS) const { OS << (V ? "true" : "false"); }
+
+ static Boolean min(unsigned NumBits) { return Boolean(false); }
+ static Boolean max(unsigned NumBits) { return Boolean(true); }
+
+ template <typename T>
+ static typename std::enable_if<std::is_integral<T>::value, Boolean>::type
+ from(T Value) {
+ return Boolean(Value != 0);
+ }
+
+ template <unsigned SrcBits, bool SrcSign>
+ static typename std::enable_if<SrcBits != 0, Boolean>::type from(
+ Integral<SrcBits, SrcSign> Value) {
+ return Boolean(!Value.isZero());
+ }
+
+ template <bool SrcSign>
+ static Boolean from(Integral<0, SrcSign> Value) {
+ return Boolean(!Value.isZero());
+ }
+
+ static Boolean zero() { return from(false); }
+
+ template <typename T>
+ static Boolean from(T Value, unsigned NumBits) {
+ return Boolean(Value);
+ }
+
+ static bool inRange(int64_t Value, unsigned NumBits) {
+ return Value == 0 || Value == 1;
+ }
+
+ static bool increment(Boolean A, Boolean *R) {
+ *R = Boolean(true);
+ return false;
+ }
+
+ static bool decrement(Boolean A, Boolean *R) {
+ llvm_unreachable("Cannot decrement booleans");
+ }
+
+ static bool add(Boolean A, Boolean B, unsigned OpBits, Boolean *R) {
+ *R = Boolean(A.V || B.V);
+ return false;
+ }
+
+ static bool sub(Boolean A, Boolean B, unsigned OpBits, Boolean *R) {
+ *R = Boolean(A.V ^ B.V);
+ return false;
+ }
+
+ static bool mul(Boolean A, Boolean B, unsigned OpBits, Boolean *R) {
+ *R = Boolean(A.V && B.V);
+ return false;
+ }
+};
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Boolean &B) {
+ B.print(OS);
+ return OS;
+}
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeEmitter.cpp
new file mode 100644
index 000000000000..7a4569820a1d
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -0,0 +1,175 @@
+//===--- ByteCodeEmitter.cpp - Instruction emitter for the VM ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ByteCodeEmitter.h"
+#include "Context.h"
+#include "Opcode.h"
+#include "Program.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+using APSInt = llvm::APSInt;
+using Error = llvm::Error;
+
+Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
+ // Do not try to compile undefined functions.
+ if (!F->isDefined(F) || (!F->hasBody() && F->willHaveBody()))
+ return nullptr;
+
+ // Set up argument indices.
+ unsigned ParamOffset = 0;
+ SmallVector<PrimType, 8> ParamTypes;
+ llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
+
+ // If the return is not a primitive, a pointer to the storage where the value
+ // is initialized in is passed as the first argument.
+ QualType Ty = F->getReturnType();
+ if (!Ty->isVoidType() && !Ctx.classify(Ty)) {
+ ParamTypes.push_back(PT_Ptr);
+ ParamOffset += align(primSize(PT_Ptr));
+ }
+
+ // Assign descriptors to all parameters.
+ // Composite objects are lowered to pointers.
+ for (const ParmVarDecl *PD : F->parameters()) {
+ PrimType Ty;
+ if (llvm::Optional<PrimType> T = Ctx.classify(PD->getType())) {
+ Ty = *T;
+ } else {
+ Ty = PT_Ptr;
+ }
+
+ Descriptor *Desc = P.createDescriptor(PD, Ty);
+ ParamDescriptors.insert({ParamOffset, {Ty, Desc}});
+ Params.insert({PD, ParamOffset});
+ ParamOffset += align(primSize(Ty));
+ ParamTypes.push_back(Ty);
+ }
+
+ // Create a handle over the emitted code.
+ Function *Func = P.createFunction(F, ParamOffset, std::move(ParamTypes),
+ std::move(ParamDescriptors));
+ // Compile the function body.
+ if (!F->isConstexpr() || !visitFunc(F)) {
+ // Return a dummy function if compilation failed.
+ if (BailLocation)
+ return llvm::make_error<ByteCodeGenError>(*BailLocation);
+ else
+ return Func;
+ } else {
+ // Create scopes from descriptors.
+ llvm::SmallVector<Scope, 2> Scopes;
+ for (auto &DS : Descriptors) {
+ Scopes.emplace_back(std::move(DS));
+ }
+
+ // Set the function's code.
+ Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
+ std::move(Scopes));
+ return Func;
+ }
+}
+
+Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) {
+ NextLocalOffset += sizeof(Block);
+ unsigned Location = NextLocalOffset;
+ NextLocalOffset += align(D->getAllocSize());
+ return {Location, D};
+}
+
+void ByteCodeEmitter::emitLabel(LabelTy Label) {
+ const size_t Target = Code.size();
+ LabelOffsets.insert({Label, Target});
+ auto It = LabelRelocs.find(Label);
+ if (It != LabelRelocs.end()) {
+ for (unsigned Reloc : It->second) {
+ using namespace llvm::support;
+
+ /// Rewrite the operand of all jumps to this label.
+ void *Location = Code.data() + Reloc - sizeof(int32_t);
+ const int32_t Offset = Target - static_cast<int64_t>(Reloc);
+ endian::write<int32_t, endianness::native, 1>(Location, Offset);
+ }
+ LabelRelocs.erase(It);
+ }
+}
+
+int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
+ // Compute the PC offset which the jump is relative to.
+ const int64_t Position = Code.size() + sizeof(Opcode) + sizeof(int32_t);
+
+ // If target is known, compute jump offset.
+ auto It = LabelOffsets.find(Label);
+ if (It != LabelOffsets.end()) {
+ return It->second - Position;
+ }
+
+ // Otherwise, record relocation and return dummy offset.
+ LabelRelocs[Label].push_back(Position);
+ return 0ull;
+}
+
+bool ByteCodeEmitter::bail(const SourceLocation &Loc) {
+ if (!BailLocation)
+ BailLocation = Loc;
+ return false;
+}
+
+template <typename... Tys>
+bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
+ bool Success = true;
+
+ /// Helper to write bytecode and bail out if 32-bit offsets become invalid.
+ auto emit = [this, &Success](const char *Data, size_t Size) {
+ if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
+ Success = false;
+ return;
+ }
+ Code.insert(Code.end(), Data, Data + Size);
+ };
+
+ /// The opcode is followed by arguments. The source info is
+ /// attached to the address after the opcode.
+ emit(reinterpret_cast<const char *>(&Op), sizeof(Opcode));
+ if (SI)
+ SrcMap.emplace_back(Code.size(), SI);
+
+ /// The initializer list forces the expression to be evaluated
+ /// for each argument in the variadic template, in order.
+ (void)std::initializer_list<int>{
+ (emit(reinterpret_cast<const char *>(&Args), sizeof(Args)), 0)...};
+
+ return Success;
+}
+
+bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) {
+ return emitJt(getOffset(Label), SourceInfo{});
+}
+
+bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) {
+ return emitJf(getOffset(Label), SourceInfo{});
+}
+
+bool ByteCodeEmitter::jump(const LabelTy &Label) {
+ return emitJmp(getOffset(Label), SourceInfo{});
+}
+
+bool ByteCodeEmitter::fallthrough(const LabelTy &Label) {
+ emitLabel(Label);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Opcode emitters
+//===----------------------------------------------------------------------===//
+
+#define GET_LINK_IMPL
+#include "Opcodes.inc"
+#undef GET_LINK_IMPL
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeEmitter.h b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeEmitter.h
new file mode 100644
index 000000000000..03452a350c96
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeEmitter.h
@@ -0,0 +1,112 @@
+//===--- ByteCodeEmitter.h - Instruction emitter for the VM ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the instruction emitters.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_LINKEMITTER_H
+#define LLVM_CLANG_AST_INTERP_LINKEMITTER_H
+
+#include "ByteCodeGenError.h"
+#include "Context.h"
+#include "InterpStack.h"
+#include "InterpState.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "Source.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace interp {
+class Context;
+class SourceInfo;
+enum Opcode : uint32_t;
+
+/// An emitter which links the program to bytecode for later use.
+class ByteCodeEmitter {
+protected:
+ using LabelTy = uint32_t;
+ using AddrTy = uintptr_t;
+ using Local = Scope::Local;
+
+public:
+ /// Compiles the function into the module.
+ llvm::Expected<Function *> compileFunc(const FunctionDecl *F);
+
+protected:
+ ByteCodeEmitter(Context &Ctx, Program &P) : Ctx(Ctx), P(P) {}
+
+ virtual ~ByteCodeEmitter() {}
+
+ /// Define a label.
+ void emitLabel(LabelTy Label);
+ /// Create a label.
+ LabelTy getLabel() { return ++NextLabel; }
+
+ /// Methods implemented by the compiler.
+ virtual bool visitFunc(const FunctionDecl *E) = 0;
+ virtual bool visitExpr(const Expr *E) = 0;
+ virtual bool visitDecl(const VarDecl *E) = 0;
+
+ /// Bails out if a given node cannot be compiled.
+ bool bail(const Stmt *S) { return bail(S->getBeginLoc()); }
+ bool bail(const Decl *D) { return bail(D->getBeginLoc()); }
+ bool bail(const SourceLocation &Loc);
+
+ /// Emits jumps.
+ bool jumpTrue(const LabelTy &Label);
+ bool jumpFalse(const LabelTy &Label);
+ bool jump(const LabelTy &Label);
+ bool fallthrough(const LabelTy &Label);
+
+ /// Callback for local registration.
+ Local createLocal(Descriptor *D);
+
+ /// Parameter indices.
+ llvm::DenseMap<const ParmVarDecl *, unsigned> Params;
+ /// Local descriptors.
+ llvm::SmallVector<SmallVector<Local, 8>, 2> Descriptors;
+
+private:
+ /// Current compilation context.
+ Context &Ctx;
+ /// Program to link to.
+ Program &P;
+ /// Index of the next available label.
+ LabelTy NextLabel = 0;
+ /// Offset of the next local variable.
+ unsigned NextLocalOffset = 0;
+ /// Location of a failure.
+ llvm::Optional<SourceLocation> BailLocation;
+ /// Label information for linker.
+ llvm::DenseMap<LabelTy, unsigned> LabelOffsets;
+ /// Location of label relocations.
+ llvm::DenseMap<LabelTy, llvm::SmallVector<unsigned, 5>> LabelRelocs;
+ /// Program code.
+ std::vector<char> Code;
+ /// Opcode to expression mapping.
+ SourceMap SrcMap;
+
+ /// Returns the offset for a jump or records a relocation.
+ int32_t getOffset(LabelTy Label);
+
+ /// Emits an opcode.
+ template <typename... Tys>
+ bool emitOp(Opcode Op, const Tys &... Args, const SourceInfo &L);
+
+protected:
+#define GET_LINK_PROTO
+#include "Opcodes.inc"
+#undef GET_LINK_PROTO
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.cpp
new file mode 100644
index 000000000000..5c8cb4274260
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -0,0 +1,580 @@
+//===--- ByteCodeExprGen.cpp - Code generator for expressions ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ByteCodeExprGen.h"
+#include "ByteCodeEmitter.h"
+#include "ByteCodeGenError.h"
+#include "Context.h"
+#include "Function.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "State.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+using APSInt = llvm::APSInt;
+template <typename T> using Expected = llvm::Expected<T>;
+template <typename T> using Optional = llvm::Optional<T>;
+
+namespace clang {
+namespace interp {
+
+/// Scope used to handle temporaries in toplevel variable declarations.
+template <class Emitter> class DeclScope final : public LocalScope<Emitter> {
+public:
+ DeclScope(ByteCodeExprGen<Emitter> *Ctx, const VarDecl *VD)
+ : LocalScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
+
+ void addExtended(const Scope::Local &Local) override {
+ return this->addLocal(Local);
+ }
+
+private:
+ Program::DeclScope Scope;
+};
+
+/// Scope used to handle initialization methods.
+template <class Emitter> class OptionScope {
+public:
+ using InitFnRef = typename ByteCodeExprGen<Emitter>::InitFnRef;
+ using ChainedInitFnRef = std::function<bool(InitFnRef)>;
+
+ /// Root constructor, compiling or discarding primitives.
+ OptionScope(ByteCodeExprGen<Emitter> *Ctx, bool NewDiscardResult)
+ : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
+ OldInitFn(std::move(Ctx->InitFn)) {
+ Ctx->DiscardResult = NewDiscardResult;
+ Ctx->InitFn = llvm::Optional<InitFnRef>{};
+ }
+
+ /// Root constructor, setting up compilation state.
+ OptionScope(ByteCodeExprGen<Emitter> *Ctx, InitFnRef NewInitFn)
+ : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
+ OldInitFn(std::move(Ctx->InitFn)) {
+ Ctx->DiscardResult = true;
+ Ctx->InitFn = NewInitFn;
+ }
+
+ /// Extends the chain of initialisation pointers.
+ OptionScope(ByteCodeExprGen<Emitter> *Ctx, ChainedInitFnRef NewInitFn)
+ : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
+ OldInitFn(std::move(Ctx->InitFn)) {
+ assert(OldInitFn && "missing initializer");
+ Ctx->InitFn = [this, NewInitFn] { return NewInitFn(*OldInitFn); };
+ }
+
+ ~OptionScope() {
+ Ctx->DiscardResult = OldDiscardResult;
+ Ctx->InitFn = std::move(OldInitFn);
+ }
+
+private:
+ /// Parent context.
+ ByteCodeExprGen<Emitter> *Ctx;
+ /// Old discard flag to restore.
+ bool OldDiscardResult;
+ /// Old pointer emitter to restore.
+ llvm::Optional<InitFnRef> OldInitFn;
+};
+
+} // namespace interp
+} // namespace clang
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
+ auto *SubExpr = CE->getSubExpr();
+ switch (CE->getCastKind()) {
+
+ case CK_LValueToRValue: {
+ return dereference(
+ CE->getSubExpr(), DerefKind::Read,
+ [](PrimType) {
+ // Value loaded - nothing to do here.
+ return true;
+ },
+ [this, CE](PrimType T) {
+ // Pointer on stack - dereference it.
+ if (!this->emitLoadPop(T, CE))
+ return false;
+ return DiscardResult ? this->emitPop(T, CE) : true;
+ });
+ }
+
+ case CK_ArrayToPointerDecay:
+ case CK_AtomicToNonAtomic:
+ case CK_ConstructorConversion:
+ case CK_FunctionToPointerDecay:
+ case CK_NonAtomicToAtomic:
+ case CK_NoOp:
+ case CK_UserDefinedConversion:
+ return this->Visit(SubExpr);
+
+ case CK_ToVoid:
+ return discard(SubExpr);
+
+ default: {
+ // TODO: implement other casts.
+ return this->bail(CE);
+ }
+ }
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitIntegerLiteral(const IntegerLiteral *LE) {
+ if (DiscardResult)
+ return true;
+
+ auto Val = LE->getValue();
+ QualType LitTy = LE->getType();
+ if (Optional<PrimType> T = classify(LitTy))
+ return emitConst(*T, getIntWidth(LitTy), LE->getValue(), LE);
+ return this->bail(LE);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitParenExpr(const ParenExpr *PE) {
+ return this->Visit(PE->getSubExpr());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
+ const Expr *LHS = BO->getLHS();
+ const Expr *RHS = BO->getRHS();
+
+ // Deal with operations which have composite or void types.
+ switch (BO->getOpcode()) {
+ case BO_Comma:
+ if (!discard(LHS))
+ return false;
+ if (!this->Visit(RHS))
+ return false;
+ return true;
+ default:
+ break;
+ }
+
+ // Typecheck the args.
+ Optional<PrimType> LT = classify(LHS->getType());
+ Optional<PrimType> RT = classify(RHS->getType());
+ if (!LT || !RT) {
+ return this->bail(BO);
+ }
+
+ if (Optional<PrimType> T = classify(BO->getType())) {
+ if (!visit(LHS))
+ return false;
+ if (!visit(RHS))
+ return false;
+
+ auto Discard = [this, T, BO](bool Result) {
+ if (!Result)
+ return false;
+ return DiscardResult ? this->emitPop(*T, BO) : true;
+ };
+
+ switch (BO->getOpcode()) {
+ case BO_EQ:
+ return Discard(this->emitEQ(*LT, BO));
+ case BO_NE:
+ return Discard(this->emitNE(*LT, BO));
+ case BO_LT:
+ return Discard(this->emitLT(*LT, BO));
+ case BO_LE:
+ return Discard(this->emitLE(*LT, BO));
+ case BO_GT:
+ return Discard(this->emitGT(*LT, BO));
+ case BO_GE:
+ return Discard(this->emitGE(*LT, BO));
+ case BO_Sub:
+ return Discard(this->emitSub(*T, BO));
+ case BO_Add:
+ return Discard(this->emitAdd(*T, BO));
+ case BO_Mul:
+ return Discard(this->emitMul(*T, BO));
+ default:
+ return this->bail(BO);
+ }
+ }
+
+ return this->bail(BO);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
+ OptionScope<Emitter> Scope(this, /*discardResult=*/true);
+ return this->Visit(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
+ OptionScope<Emitter> Scope(this, /*discardResult=*/false);
+ return this->Visit(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {
+ if (Optional<PrimType> T = classify(E->getType())) {
+ return visit(E);
+ } else {
+ return this->bail(E);
+ }
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, const Expr *E) {
+ switch (T) {
+ case PT_Bool:
+ return this->emitZeroBool(E);
+ case PT_Sint8:
+ return this->emitZeroSint8(E);
+ case PT_Uint8:
+ return this->emitZeroUint8(E);
+ case PT_Sint16:
+ return this->emitZeroSint16(E);
+ case PT_Uint16:
+ return this->emitZeroUint16(E);
+ case PT_Sint32:
+ return this->emitZeroSint32(E);
+ case PT_Uint32:
+ return this->emitZeroUint32(E);
+ case PT_Sint64:
+ return this->emitZeroSint64(E);
+ case PT_Uint64:
+ return this->emitZeroUint64(E);
+ case PT_Ptr:
+ return this->emitNullPtr(E);
+ }
+ llvm_unreachable("unknown primitive type");
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::dereference(
+ const Expr *LV, DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect) {
+ if (Optional<PrimType> T = classify(LV->getType())) {
+ if (!LV->refersToBitField()) {
+ // Only primitive, non bit-field types can be dereferenced directly.
+ if (auto *DE = dyn_cast<DeclRefExpr>(LV)) {
+ if (!DE->getDecl()->getType()->isReferenceType()) {
+ if (auto *PD = dyn_cast<ParmVarDecl>(DE->getDecl()))
+ return dereferenceParam(LV, *T, PD, AK, Direct, Indirect);
+ if (auto *VD = dyn_cast<VarDecl>(DE->getDecl()))
+ return dereferenceVar(LV, *T, VD, AK, Direct, Indirect);
+ }
+ }
+ }
+
+ if (!visit(LV))
+ return false;
+ return Indirect(*T);
+ }
+
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::dereferenceParam(
+ const Expr *LV, PrimType T, const ParmVarDecl *PD, DerefKind AK,
+ llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect) {
+ auto It = this->Params.find(PD);
+ if (It != this->Params.end()) {
+ unsigned Idx = It->second;
+ switch (AK) {
+ case DerefKind::Read:
+ return DiscardResult ? true : this->emitGetParam(T, Idx, LV);
+
+ case DerefKind::Write:
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetParam(T, Idx, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrParam(Idx, LV);
+
+ case DerefKind::ReadWrite:
+ if (!this->emitGetParam(T, Idx, LV))
+ return false;
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetParam(T, Idx, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrParam(Idx, LV);
+ }
+ return true;
+ }
+
+ // If the param is a pointer, we can dereference a dummy value.
+ if (!DiscardResult && T == PT_Ptr && AK == DerefKind::Read) {
+ if (auto Idx = P.getOrCreateDummy(PD))
+ return this->emitGetPtrGlobal(*Idx, PD);
+ return false;
+ }
+
+ // Value cannot be produced - try to emit pointer and do stuff with it.
+ return visit(LV) && Indirect(T);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::dereferenceVar(
+ const Expr *LV, PrimType T, const VarDecl *VD, DerefKind AK,
+ llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect) {
+ auto It = Locals.find(VD);
+ if (It != Locals.end()) {
+ const auto &L = It->second;
+ switch (AK) {
+ case DerefKind::Read:
+ if (!this->emitGetLocal(T, L.Offset, LV))
+ return false;
+ return DiscardResult ? this->emitPop(T, LV) : true;
+
+ case DerefKind::Write:
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetLocal(T, L.Offset, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
+
+ case DerefKind::ReadWrite:
+ if (!this->emitGetLocal(T, L.Offset, LV))
+ return false;
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetLocal(T, L.Offset, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
+ }
+ } else if (auto Idx = getGlobalIdx(VD)) {
+ switch (AK) {
+ case DerefKind::Read:
+ if (!this->emitGetGlobal(T, *Idx, LV))
+ return false;
+ return DiscardResult ? this->emitPop(T, LV) : true;
+
+ case DerefKind::Write:
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetGlobal(T, *Idx, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrGlobal(*Idx, LV);
+
+ case DerefKind::ReadWrite:
+ if (!this->emitGetGlobal(T, *Idx, LV))
+ return false;
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetGlobal(T, *Idx, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrGlobal(*Idx, LV);
+ }
+ }
+
+ // If the declaration is a constant value, emit it here even
+ // though the declaration was not evaluated in the current scope.
+ // The access mode can only be read in this case.
+ if (!DiscardResult && AK == DerefKind::Read) {
+ if (VD->hasLocalStorage() && VD->hasInit() && !VD->isConstexpr()) {
+ QualType VT = VD->getType();
+ if (VT.isConstQualified() && VT->isFundamentalType())
+ return this->Visit(VD->getInit());
+ }
+ }
+
+ // Value cannot be produced - try to emit pointer.
+ return visit(LV) && Indirect(T);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::emitConst(PrimType T, unsigned NumBits,
+ const APInt &Value, const Expr *E) {
+ switch (T) {
+ case PT_Sint8:
+ return this->emitConstSint8(Value.getSExtValue(), E);
+ case PT_Uint8:
+ return this->emitConstUint8(Value.getZExtValue(), E);
+ case PT_Sint16:
+ return this->emitConstSint16(Value.getSExtValue(), E);
+ case PT_Uint16:
+ return this->emitConstUint16(Value.getZExtValue(), E);
+ case PT_Sint32:
+ return this->emitConstSint32(Value.getSExtValue(), E);
+ case PT_Uint32:
+ return this->emitConstUint32(Value.getZExtValue(), E);
+ case PT_Sint64:
+ return this->emitConstSint64(Value.getSExtValue(), E);
+ case PT_Uint64:
+ return this->emitConstUint64(Value.getZExtValue(), E);
+ case PT_Bool:
+ return this->emitConstBool(Value.getBoolValue(), E);
+ case PT_Ptr:
+ llvm_unreachable("Invalid integral type");
+ break;
+ }
+ llvm_unreachable("unknown primitive type");
+}
+
+template <class Emitter>
+unsigned ByteCodeExprGen<Emitter>::allocateLocalPrimitive(DeclTy &&Src,
+ PrimType Ty,
+ bool IsConst,
+ bool IsExtended) {
+ Descriptor *D = P.createDescriptor(Src, Ty, IsConst, Src.is<const Expr *>());
+ Scope::Local Local = this->createLocal(D);
+ if (auto *VD = dyn_cast_or_null<ValueDecl>(Src.dyn_cast<const Decl *>()))
+ Locals.insert({VD, Local});
+ VarScope->add(Local, IsExtended);
+ return Local.Offset;
+}
+
+template <class Emitter>
+llvm::Optional<unsigned>
+ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src, bool IsExtended) {
+ QualType Ty;
+
+ const ValueDecl *Key = nullptr;
+ bool IsTemporary = false;
+ if (auto *VD = dyn_cast_or_null<ValueDecl>(Src.dyn_cast<const Decl *>())) {
+ Key = VD;
+ Ty = VD->getType();
+ }
+ if (auto *E = Src.dyn_cast<const Expr *>()) {
+ IsTemporary = true;
+ Ty = E->getType();
+ }
+
+ Descriptor *D = P.createDescriptor(Src, Ty.getTypePtr(),
+ Ty.isConstQualified(), IsTemporary);
+ if (!D)
+ return {};
+
+ Scope::Local Local = this->createLocal(D);
+ if (Key)
+ Locals.insert({Key, Local});
+ VarScope->add(Local, IsExtended);
+ return Local.Offset;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitInitializer(
+ const Expr *Init, InitFnRef InitFn) {
+ OptionScope<Emitter> Scope(this, InitFn);
+ return this->Visit(Init);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::getPtrVarDecl(const VarDecl *VD, const Expr *E) {
+ // Generate a pointer to the local, loading refs.
+ if (Optional<unsigned> Idx = getGlobalIdx(VD)) {
+ if (VD->getType()->isReferenceType())
+ return this->emitGetGlobalPtr(*Idx, E);
+ else
+ return this->emitGetPtrGlobal(*Idx, E);
+ }
+ return this->bail(VD);
+}
+
+template <class Emitter>
+llvm::Optional<unsigned>
+ByteCodeExprGen<Emitter>::getGlobalIdx(const VarDecl *VD) {
+ if (VD->isConstexpr()) {
+ // Constexpr decl - it must have already been defined.
+ return P.getGlobal(VD);
+ }
+ if (!VD->hasLocalStorage()) {
+ // Not constexpr, but a global var - can have pointer taken.
+ Program::DeclScope Scope(P, VD);
+ return P.getOrCreateGlobal(VD);
+ }
+ return {};
+}
+
+template <class Emitter>
+const RecordType *ByteCodeExprGen<Emitter>::getRecordTy(QualType Ty) {
+ if (auto *PT = dyn_cast<PointerType>(Ty))
+ return PT->getPointeeType()->getAs<RecordType>();
+ else
+ return Ty->getAs<RecordType>();
+}
+
+template <class Emitter>
+Record *ByteCodeExprGen<Emitter>::getRecord(QualType Ty) {
+ if (auto *RecordTy = getRecordTy(Ty)) {
+ return getRecord(RecordTy->getDecl());
+ }
+ return nullptr;
+}
+
+template <class Emitter>
+Record *ByteCodeExprGen<Emitter>::getRecord(const RecordDecl *RD) {
+ return P.getOrCreateRecord(RD);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *Exp) {
+ ExprScope<Emitter> RootScope(this);
+ if (!visit(Exp))
+ return false;
+
+ if (Optional<PrimType> T = classify(Exp))
+ return this->emitRet(*T, Exp);
+ else
+ return this->emitRetValue(Exp);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
+ const Expr *Init = VD->getInit();
+
+ if (Optional<unsigned> I = P.createGlobal(VD)) {
+ if (Optional<PrimType> T = classify(VD->getType())) {
+ {
+ // Primitive declarations - compute the value and set it.
+ DeclScope<Emitter> LocalScope(this, VD);
+ if (!visit(Init))
+ return false;
+ }
+
+ // If the declaration is global, save the value for later use.
+ if (!this->emitDup(*T, VD))
+ return false;
+ if (!this->emitInitGlobal(*T, *I, VD))
+ return false;
+ return this->emitRet(*T, VD);
+ } else {
+ {
+ // Composite declarations - allocate storage and initialize it.
+ DeclScope<Emitter> LocalScope(this, VD);
+ if (!visitGlobalInitializer(Init, *I))
+ return false;
+ }
+
+ // Return a pointer to the global.
+ if (!this->emitGetPtrGlobal(*I, VD))
+ return false;
+ return this->emitRetValue(VD);
+ }
+ }
+
+ return this->bail(VD);
+}
+
+template <class Emitter>
+void ByteCodeExprGen<Emitter>::emitCleanup() {
+ for (VariableScope<Emitter> *C = VarScope; C; C = C->getParent())
+ C->emitDestruction();
+}
+
+namespace clang {
+namespace interp {
+
+template class ByteCodeExprGen<ByteCodeEmitter>;
+template class ByteCodeExprGen<EvalEmitter>;
+
+} // namespace interp
+} // namespace clang
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.h b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.h
new file mode 100644
index 000000000000..1d0e34fc991f
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -0,0 +1,331 @@
+//===--- ByteCodeExprGen.h - Code generator for expressions -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the constexpr bytecode compiler.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
+#define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
+
+#include "ByteCodeEmitter.h"
+#include "EvalEmitter.h"
+#include "Pointer.h"
+#include "PrimType.h"
+#include "Record.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+class QualType;
+
+namespace interp {
+class Function;
+class State;
+
+template <class Emitter> class LocalScope;
+template <class Emitter> class RecordScope;
+template <class Emitter> class VariableScope;
+template <class Emitter> class DeclScope;
+template <class Emitter> class OptionScope;
+
+/// Compilation context for expressions.
+template <class Emitter>
+class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
+ public Emitter {
+protected:
+ // Emitters for opcodes of various arities.
+ using NullaryFn = bool (ByteCodeExprGen::*)(const SourceInfo &);
+ using UnaryFn = bool (ByteCodeExprGen::*)(PrimType, const SourceInfo &);
+ using BinaryFn = bool (ByteCodeExprGen::*)(PrimType, PrimType,
+ const SourceInfo &);
+
+ // Aliases for types defined in the emitter.
+ using LabelTy = typename Emitter::LabelTy;
+ using AddrTy = typename Emitter::AddrTy;
+
+ // Reference to a function generating the pointer of an initialized object.s
+ using InitFnRef = std::function<bool()>;
+
+ /// Current compilation context.
+ Context &Ctx;
+ /// Program to link to.
+ Program &P;
+
+public:
+ /// Initializes the compiler and the backend emitter.
+ template <typename... Tys>
+ ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
+ : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
+
+ // Expression visitors - result returned on stack.
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitIntegerLiteral(const IntegerLiteral *E);
+ bool VisitParenExpr(const ParenExpr *E);
+ bool VisitBinaryOperator(const BinaryOperator *E);
+
+protected:
+ bool visitExpr(const Expr *E) override;
+ bool visitDecl(const VarDecl *VD) override;
+
+protected:
+ /// Emits scope cleanup instructions.
+ void emitCleanup();
+
+ /// Returns a record type from a record or pointer type.
+ const RecordType *getRecordTy(QualType Ty);
+
+ /// Returns a record from a record or pointer type.
+ Record *getRecord(QualType Ty);
+ Record *getRecord(const RecordDecl *RD);
+
+ /// Returns the size int bits of an integer.
+ unsigned getIntWidth(QualType Ty) {
+ auto &ASTContext = Ctx.getASTContext();
+ return ASTContext.getIntWidth(Ty);
+ }
+
+ /// Returns the value of CHAR_BIT.
+ unsigned getCharBit() const {
+ auto &ASTContext = Ctx.getASTContext();
+ return ASTContext.getTargetInfo().getCharWidth();
+ }
+
+ /// Classifies a type.
+ llvm::Optional<PrimType> classify(const Expr *E) const {
+ return E->isGLValue() ? PT_Ptr : classify(E->getType());
+ }
+ llvm::Optional<PrimType> classify(QualType Ty) const {
+ return Ctx.classify(Ty);
+ }
+
+ /// Checks if a pointer needs adjustment.
+ bool needsAdjust(QualType Ty) const {
+ return true;
+ }
+
+ /// Classifies a known primitive type
+ PrimType classifyPrim(QualType Ty) const {
+ if (auto T = classify(Ty)) {
+ return *T;
+ }
+ llvm_unreachable("not a primitive type");
+ }
+
+ /// Evaluates an expression for side effects and discards the result.
+ bool discard(const Expr *E);
+ /// Evaluates an expression and places result on stack.
+ bool visit(const Expr *E);
+ /// Compiles an initializer for a local.
+ bool visitInitializer(const Expr *E, InitFnRef GenPtr);
+
+ /// Visits an expression and converts it to a boolean.
+ bool visitBool(const Expr *E);
+
+ /// Visits an initializer for a local.
+ bool visitLocalInitializer(const Expr *Init, unsigned I) {
+ return visitInitializer(Init, [this, I, Init] {
+ return this->emitGetPtrLocal(I, Init);
+ });
+ }
+
+ /// Visits an initializer for a global.
+ bool visitGlobalInitializer(const Expr *Init, unsigned I) {
+ return visitInitializer(Init, [this, I, Init] {
+ return this->emitGetPtrGlobal(I, Init);
+ });
+ }
+
+ /// Visits a delegated initializer.
+ bool visitThisInitializer(const Expr *I) {
+ return visitInitializer(I, [this, I] { return this->emitThis(I); });
+ }
+
+ /// Creates a local primitive value.
+ unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable,
+ bool IsExtended = false);
+
+ /// Allocates a space storing a local given its type.
+ llvm::Optional<unsigned> allocateLocal(DeclTy &&Decl,
+ bool IsExtended = false);
+
+private:
+ friend class VariableScope<Emitter>;
+ friend class LocalScope<Emitter>;
+ friend class RecordScope<Emitter>;
+ friend class DeclScope<Emitter>;
+ friend class OptionScope<Emitter>;
+
+ /// Emits a zero initializer.
+ bool visitZeroInitializer(PrimType T, const Expr *E);
+
+ enum class DerefKind {
+ /// Value is read and pushed to stack.
+ Read,
+ /// Direct method generates a value which is written. Returns pointer.
+ Write,
+ /// Direct method receives the value, pushes mutated value. Returns pointer.
+ ReadWrite,
+ };
+
+ /// Method to directly load a value. If the value can be fetched directly,
+ /// the direct handler is called. Otherwise, a pointer is left on the stack
+ /// and the indirect handler is expected to operate on that.
+ bool dereference(const Expr *LV, DerefKind AK,
+ llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect);
+ bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD,
+ DerefKind AK,
+ llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect);
+ bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
+ DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect);
+
+ /// Emits an APInt constant.
+ bool emitConst(PrimType T, unsigned NumBits, const llvm::APInt &Value,
+ const Expr *E);
+
+ /// Emits an integer constant.
+ template <typename T> bool emitConst(const Expr *E, T Value) {
+ QualType Ty = E->getType();
+ unsigned NumBits = getIntWidth(Ty);
+ APInt WrappedValue(NumBits, Value, std::is_signed<T>::value);
+ return emitConst(*Ctx.classify(Ty), NumBits, WrappedValue, E);
+ }
+
+ /// Returns a pointer to a variable declaration.
+ bool getPtrVarDecl(const VarDecl *VD, const Expr *E);
+
+ /// Returns the index of a global.
+ llvm::Optional<unsigned> getGlobalIdx(const VarDecl *VD);
+
+ /// Emits the initialized pointer.
+ bool emitInitFn() {
+ assert(InitFn && "missing initializer");
+ return (*InitFn)();
+ }
+
+protected:
+ /// Variable to storage mapping.
+ llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
+
+ /// OpaqueValueExpr to location mapping.
+ llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
+
+ /// Current scope.
+ VariableScope<Emitter> *VarScope = nullptr;
+
+ /// Current argument index.
+ llvm::Optional<uint64_t> ArrayIndex;
+
+ /// Flag indicating if return value is to be discarded.
+ bool DiscardResult = false;
+
+ /// Expression being initialized.
+ llvm::Optional<InitFnRef> InitFn = {};
+};
+
+extern template class ByteCodeExprGen<ByteCodeEmitter>;
+extern template class ByteCodeExprGen<EvalEmitter>;
+
+/// Scope chain managing the variable lifetimes.
+template <class Emitter> class VariableScope {
+public:
+ virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
+
+ void add(const Scope::Local &Local, bool IsExtended) {
+ if (IsExtended)
+ this->addExtended(Local);
+ else
+ this->addLocal(Local);
+ }
+
+ virtual void addLocal(const Scope::Local &Local) {
+ if (this->Parent)
+ this->Parent->addLocal(Local);
+ }
+
+ virtual void addExtended(const Scope::Local &Local) {
+ if (this->Parent)
+ this->Parent->addExtended(Local);
+ }
+
+ virtual void emitDestruction() {}
+
+ VariableScope *getParent() { return Parent; }
+
+protected:
+ VariableScope(ByteCodeExprGen<Emitter> *Ctx)
+ : Ctx(Ctx), Parent(Ctx->VarScope) {
+ Ctx->VarScope = this;
+ }
+
+ /// ByteCodeExprGen instance.
+ ByteCodeExprGen<Emitter> *Ctx;
+ /// Link to the parent scope.
+ VariableScope *Parent;
+};
+
+/// Scope for local variables.
+///
+/// When the scope is destroyed, instructions are emitted to tear down
+/// all variables declared in this scope.
+template <class Emitter> class LocalScope : public VariableScope<Emitter> {
+public:
+ LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
+
+ ~LocalScope() override { this->emitDestruction(); }
+
+ void addLocal(const Scope::Local &Local) override {
+ if (!Idx.hasValue()) {
+ Idx = this->Ctx->Descriptors.size();
+ this->Ctx->Descriptors.emplace_back();
+ }
+
+ this->Ctx->Descriptors[*Idx].emplace_back(Local);
+ }
+
+ void emitDestruction() override {
+ if (!Idx.hasValue())
+ return;
+ this->Ctx->emitDestroy(*Idx, SourceInfo{});
+ }
+
+protected:
+ /// Index of the scope in the chain.
+ Optional<unsigned> Idx;
+};
+
+/// Scope for storage declared in a compound statement.
+template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
+public:
+ BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
+
+ void addExtended(const Scope::Local &Local) override {
+ llvm_unreachable("Cannot create temporaries in full scopes");
+ }
+};
+
+/// Expression scope which tracks potentially lifetime extended
+/// temporaries which are hoisted to the parent scope on exit.
+template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
+public:
+ ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
+
+ void addExtended(const Scope::Local &Local) override {
+ this->Parent->addLocal(Local);
+ }
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeGenError.cpp b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeGenError.cpp
new file mode 100644
index 000000000000..5fd3d77c3842
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeGenError.cpp
@@ -0,0 +1,14 @@
+//===--- ByteCodeGenError.h - Byte code generation error --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ByteCodeGenError.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+char ByteCodeGenError::ID;
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeGenError.h b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeGenError.h
new file mode 100644
index 000000000000..a4fa4917705d
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeGenError.h
@@ -0,0 +1,46 @@
+//===--- ByteCodeGenError.h - Byte code generation error ----------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_BYTECODEGENERROR_H
+#define LLVM_CLANG_AST_INTERP_BYTECODEGENERROR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace interp {
+
+/// Error thrown by the compiler.
+struct ByteCodeGenError : public llvm::ErrorInfo<ByteCodeGenError> {
+public:
+ ByteCodeGenError(SourceLocation Loc) : Loc(Loc) {}
+ ByteCodeGenError(const Stmt *S) : ByteCodeGenError(S->getBeginLoc()) {}
+ ByteCodeGenError(const Decl *D) : ByteCodeGenError(D->getBeginLoc()) {}
+
+ void log(raw_ostream &OS) const override { OS << "unimplemented feature"; }
+
+ const SourceLocation &getLoc() const { return Loc; }
+
+ static char ID;
+
+private:
+ // Start of the item where the error occurred.
+ SourceLocation Loc;
+
+ // Users are not expected to use error_code.
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
new file mode 100644
index 000000000000..5b47489e65e0
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -0,0 +1,263 @@
+//===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ByteCodeStmtGen.h"
+#include "ByteCodeEmitter.h"
+#include "ByteCodeGenError.h"
+#include "Context.h"
+#include "Function.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "State.h"
+#include "clang/Basic/LLVM.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+namespace clang {
+namespace interp {
+
+/// Scope managing label targets.
+template <class Emitter> class LabelScope {
+public:
+ virtual ~LabelScope() { }
+
+protected:
+ LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {}
+ /// ByteCodeStmtGen instance.
+ ByteCodeStmtGen<Emitter> *Ctx;
+};
+
+/// Sets the context for break/continue statements.
+template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
+public:
+ using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
+ using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
+
+ LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel,
+ LabelTy ContinueLabel)
+ : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
+ OldContinueLabel(Ctx->ContinueLabel) {
+ this->Ctx->BreakLabel = BreakLabel;
+ this->Ctx->ContinueLabel = ContinueLabel;
+ }
+
+ ~LoopScope() {
+ this->Ctx->BreakLabel = OldBreakLabel;
+ this->Ctx->ContinueLabel = OldContinueLabel;
+ }
+
+private:
+ OptLabelTy OldBreakLabel;
+ OptLabelTy OldContinueLabel;
+};
+
+// Sets the context for a switch scope, mapping labels.
+template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
+public:
+ using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
+ using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
+ using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap;
+
+ SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels,
+ LabelTy BreakLabel, OptLabelTy DefaultLabel)
+ : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
+ OldDefaultLabel(this->Ctx->DefaultLabel),
+ OldCaseLabels(std::move(this->Ctx->CaseLabels)) {
+ this->Ctx->BreakLabel = BreakLabel;
+ this->Ctx->DefaultLabel = DefaultLabel;
+ this->Ctx->CaseLabels = std::move(CaseLabels);
+ }
+
+ ~SwitchScope() {
+ this->Ctx->BreakLabel = OldBreakLabel;
+ this->Ctx->DefaultLabel = OldDefaultLabel;
+ this->Ctx->CaseLabels = std::move(OldCaseLabels);
+ }
+
+private:
+ OptLabelTy OldBreakLabel;
+ OptLabelTy OldDefaultLabel;
+ CaseMap OldCaseLabels;
+};
+
+} // namespace interp
+} // namespace clang
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
+ // Classify the return type.
+ ReturnType = this->classify(F->getReturnType());
+
+ // Set up fields and context if a constructor.
+ if (auto *MD = dyn_cast<CXXMethodDecl>(F))
+ return this->bail(MD);
+
+ if (auto *Body = F->getBody())
+ if (!visitStmt(Body))
+ return false;
+
+ // Emit a guard return to protect against a code path missing one.
+ if (F->getReturnType()->isVoidType())
+ return this->emitRetVoid(SourceInfo{});
+ else
+ return this->emitNoRet(SourceInfo{});
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
+ switch (S->getStmtClass()) {
+ case Stmt::CompoundStmtClass:
+ return visitCompoundStmt(cast<CompoundStmt>(S));
+ case Stmt::DeclStmtClass:
+ return visitDeclStmt(cast<DeclStmt>(S));
+ case Stmt::ReturnStmtClass:
+ return visitReturnStmt(cast<ReturnStmt>(S));
+ case Stmt::IfStmtClass:
+ return visitIfStmt(cast<IfStmt>(S));
+ case Stmt::NullStmtClass:
+ return true;
+ default: {
+ if (auto *Exp = dyn_cast<Expr>(S))
+ return this->discard(Exp);
+ return this->bail(S);
+ }
+ }
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
+ const CompoundStmt *CompoundStmt) {
+ BlockScope<Emitter> Scope(this);
+ for (auto *InnerStmt : CompoundStmt->body())
+ if (!visitStmt(InnerStmt))
+ return false;
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
+ for (auto *D : DS->decls()) {
+ // Variable declarator.
+ if (auto *VD = dyn_cast<VarDecl>(D)) {
+ if (!visitVarDecl(VD))
+ return false;
+ continue;
+ }
+
+ // Decomposition declarator.
+ if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
+ return this->bail(DD);
+ }
+ }
+
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
+ if (const Expr *RE = RS->getRetValue()) {
+ ExprScope<Emitter> RetScope(this);
+ if (ReturnType) {
+ // Primitive types are simply returned.
+ if (!this->visit(RE))
+ return false;
+ this->emitCleanup();
+ return this->emitRet(*ReturnType, RS);
+ } else {
+ // RVO - construct the value in the return location.
+ auto ReturnLocation = [this, RE] { return this->emitGetParamPtr(0, RE); };
+ if (!this->visitInitializer(RE, ReturnLocation))
+ return false;
+ this->emitCleanup();
+ return this->emitRetVoid(RS);
+ }
+ } else {
+ this->emitCleanup();
+ if (!this->emitRetVoid(RS))
+ return false;
+ return true;
+ }
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
+ BlockScope<Emitter> IfScope(this);
+ if (auto *CondInit = IS->getInit())
+ if (!visitStmt(IS->getInit()))
+ return false;
+
+ if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
+ if (!visitDeclStmt(CondDecl))
+ return false;
+
+ if (!this->visitBool(IS->getCond()))
+ return false;
+
+ if (const Stmt *Else = IS->getElse()) {
+ LabelTy LabelElse = this->getLabel();
+ LabelTy LabelEnd = this->getLabel();
+ if (!this->jumpFalse(LabelElse))
+ return false;
+ if (!visitStmt(IS->getThen()))
+ return false;
+ if (!this->jump(LabelEnd))
+ return false;
+ this->emitLabel(LabelElse);
+ if (!visitStmt(Else))
+ return false;
+ this->emitLabel(LabelEnd);
+ } else {
+ LabelTy LabelEnd = this->getLabel();
+ if (!this->jumpFalse(LabelEnd))
+ return false;
+ if (!visitStmt(IS->getThen()))
+ return false;
+ this->emitLabel(LabelEnd);
+ }
+
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
+ auto DT = VD->getType();
+
+ if (!VD->hasLocalStorage()) {
+ // No code generation required.
+ return true;
+ }
+
+ // Integers, pointers, primitives.
+ if (Optional<PrimType> T = this->classify(DT)) {
+ auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
+ // Compile the initialiser in its own scope.
+ {
+ ExprScope<Emitter> Scope(this);
+ if (!this->visit(VD->getInit()))
+ return false;
+ }
+ // Set the value.
+ return this->emitSetLocal(*T, Off, VD);
+ } else {
+ // Composite types - allocate storage and initialize it.
+ if (auto Off = this->allocateLocal(VD)) {
+ return this->visitLocalInitializer(VD->getInit(), *Off);
+ } else {
+ return this->bail(VD);
+ }
+ }
+}
+
+namespace clang {
+namespace interp {
+
+template class ByteCodeStmtGen<ByteCodeEmitter>;
+
+} // namespace interp
+} // namespace clang
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeStmtGen.h b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeStmtGen.h
new file mode 100644
index 000000000000..d9c0b64ed4b8
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeStmtGen.h
@@ -0,0 +1,89 @@
+//===--- ByteCodeStmtGen.h - Code generator for expressions -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the constexpr bytecode compiler.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_BYTECODESTMTGEN_H
+#define LLVM_CLANG_AST_INTERP_BYTECODESTMTGEN_H
+
+#include "ByteCodeEmitter.h"
+#include "ByteCodeExprGen.h"
+#include "EvalEmitter.h"
+#include "Pointer.h"
+#include "PrimType.h"
+#include "Record.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+class QualType;
+
+namespace interp {
+class Function;
+class State;
+
+template <class Emitter> class LoopScope;
+template <class Emitter> class SwitchScope;
+template <class Emitter> class LabelScope;
+
+/// Compilation context for statements.
+template <class Emitter>
+class ByteCodeStmtGen : public ByteCodeExprGen<Emitter> {
+ using LabelTy = typename Emitter::LabelTy;
+ using AddrTy = typename Emitter::AddrTy;
+ using OptLabelTy = llvm::Optional<LabelTy>;
+ using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;
+
+public:
+ template<typename... Tys>
+ ByteCodeStmtGen(Tys&&... Args)
+ : ByteCodeExprGen<Emitter>(std::forward<Tys>(Args)...) {}
+
+protected:
+ bool visitFunc(const FunctionDecl *F) override;
+
+private:
+ friend class LabelScope<Emitter>;
+ friend class LoopScope<Emitter>;
+ friend class SwitchScope<Emitter>;
+
+ // Statement visitors.
+ bool visitStmt(const Stmt *S);
+ bool visitCompoundStmt(const CompoundStmt *S);
+ bool visitDeclStmt(const DeclStmt *DS);
+ bool visitReturnStmt(const ReturnStmt *RS);
+ bool visitIfStmt(const IfStmt *IS);
+
+ /// Compiles a variable declaration.
+ bool visitVarDecl(const VarDecl *VD);
+
+private:
+ /// Type of the expression returned by the function.
+ llvm::Optional<PrimType> ReturnType;
+
+ /// Switch case mapping.
+ CaseMap CaseLabels;
+
+ /// Point to break to.
+ OptLabelTy BreakLabel;
+ /// Point to continue to.
+ OptLabelTy ContinueLabel;
+ /// Default case label.
+ OptLabelTy DefaultLabel;
+};
+
+extern template class ByteCodeExprGen<EvalEmitter>;
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Context.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Context.cpp
new file mode 100644
index 000000000000..e7f9ba0f010a
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Context.cpp
@@ -0,0 +1,128 @@
+//===--- Context.cpp - Context for the constexpr VM -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Context.h"
+#include "ByteCodeEmitter.h"
+#include "ByteCodeExprGen.h"
+#include "ByteCodeStmtGen.h"
+#include "EvalEmitter.h"
+#include "Interp.h"
+#include "InterpFrame.h"
+#include "InterpStack.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "clang/AST/Expr.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {}
+
+Context::~Context() {}
+
+bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
+ Function *Func = P->getFunction(FD);
+ if (!Func) {
+ if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) {
+ Func = *R;
+ } else {
+ handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) {
+ Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
+ });
+ return false;
+ }
+ }
+
+ if (!Func->isConstexpr())
+ return false;
+
+ APValue Dummy;
+ return Run(Parent, Func, Dummy);
+}
+
+bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
+ ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
+ return Check(Parent, C.interpretExpr(E));
+}
+
+bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
+ APValue &Result) {
+ ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
+ return Check(Parent, C.interpretDecl(VD));
+}
+
+const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
+
+llvm::Optional<PrimType> Context::classify(QualType T) {
+ if (T->isReferenceType() || T->isPointerType()) {
+ return PT_Ptr;
+ }
+
+ if (T->isBooleanType())
+ return PT_Bool;
+
+ if (T->isSignedIntegerOrEnumerationType()) {
+ switch (Ctx.getIntWidth(T)) {
+ case 64:
+ return PT_Sint64;
+ case 32:
+ return PT_Sint32;
+ case 16:
+ return PT_Sint16;
+ case 8:
+ return PT_Sint8;
+ default:
+ return {};
+ }
+ }
+
+ if (T->isUnsignedIntegerOrEnumerationType()) {
+ switch (Ctx.getIntWidth(T)) {
+ case 64:
+ return PT_Uint64;
+ case 32:
+ return PT_Uint32;
+ case 16:
+ return PT_Uint16;
+ case 8:
+ return PT_Uint8;
+ default:
+ return {};
+ }
+ }
+
+ if (T->isNullPtrType())
+ return PT_Ptr;
+
+ if (auto *AT = dyn_cast<AtomicType>(T))
+ return classify(AT->getValueType());
+
+ return {};
+}
+
+unsigned Context::getCharBit() const {
+ return Ctx.getTargetInfo().getCharWidth();
+}
+
+bool Context::Run(State &Parent, Function *Func, APValue &Result) {
+ InterpState State(Parent, *P, Stk, *this);
+ State.Current = new InterpFrame(State, Func, nullptr, {}, {});
+ if (Interpret(State, Result))
+ return true;
+ Stk.clear();
+ return false;
+}
+
+bool Context::Check(State &Parent, llvm::Expected<bool> &&Flag) {
+ if (Flag)
+ return *Flag;
+ handleAllErrors(Flag.takeError(), [&Parent](ByteCodeGenError &Err) {
+ Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
+ });
+ return false;
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Context.h b/contrib/llvm-project/clang/lib/AST/Interp/Context.h
new file mode 100644
index 000000000000..e4d831cbb991
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Context.h
@@ -0,0 +1,86 @@
+//===--- Context.h - Context for the constexpr VM ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the constexpr execution context.
+//
+// The execution context manages cached bytecode and the global context.
+// It invokes the compiler and interpreter, propagating errors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_CONTEXT_H
+#define LLVM_CLANG_AST_INTERP_CONTEXT_H
+
+#include "Context.h"
+#include "InterpStack.h"
+#include "clang/AST/APValue.h"
+#include "llvm/ADT/PointerIntPair.h"
+
+namespace clang {
+class ASTContext;
+class LangOptions;
+class Stmt;
+class FunctionDecl;
+class VarDecl;
+
+namespace interp {
+class Function;
+class Program;
+class State;
+enum PrimType : unsigned;
+
+/// Holds all information required to evaluate constexpr code in a module.
+class Context {
+public:
+ /// Initialises the constexpr VM.
+ Context(ASTContext &Ctx);
+
+ /// Cleans up the constexpr VM.
+ ~Context();
+
+ /// Checks if a function is a potential constant expression.
+ bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FnDecl);
+
+ /// Evaluates a toplevel expression as an rvalue.
+ bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result);
+
+ /// Evaluates a toplevel initializer.
+ bool evaluateAsInitializer(State &Parent, const VarDecl *VD, APValue &Result);
+
+ /// Returns the AST context.
+ ASTContext &getASTContext() const { return Ctx; }
+ /// Returns the language options.
+ const LangOptions &getLangOpts() const;
+ /// Returns the interpreter stack.
+ InterpStack &getStack() { return Stk; }
+ /// Returns CHAR_BIT.
+ unsigned getCharBit() const;
+
+ /// Classifies an expression.
+ llvm::Optional<PrimType> classify(QualType T);
+
+private:
+ /// Runs a function.
+ bool Run(State &Parent, Function *Func, APValue &Result);
+
+ /// Checks a result fromt the interpreter.
+ bool Check(State &Parent, llvm::Expected<bool> &&R);
+
+private:
+ /// Current compilation context.
+ ASTContext &Ctx;
+ /// Interpreter stack, shared across invocations.
+ InterpStack Stk;
+ /// Constexpr program.
+ std::unique_ptr<Program> P;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.cpp
new file mode 100644
index 000000000000..5c1a8a9cf306
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.cpp
@@ -0,0 +1,292 @@
+//===--- Descriptor.cpp - Types for the constexpr VM ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Descriptor.h"
+#include "Pointer.h"
+#include "PrimType.h"
+#include "Record.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+template <typename T>
+static void ctorTy(Block *, char *Ptr, bool, bool, bool, Descriptor *) {
+ new (Ptr) T();
+}
+
+template <typename T> static void dtorTy(Block *, char *Ptr, Descriptor *) {
+ reinterpret_cast<T *>(Ptr)->~T();
+}
+
+template <typename T>
+static void moveTy(Block *, char *Src, char *Dst, Descriptor *) {
+ auto *SrcPtr = reinterpret_cast<T *>(Src);
+ auto *DstPtr = reinterpret_cast<T *>(Dst);
+ new (DstPtr) T(std::move(*SrcPtr));
+}
+
+template <typename T>
+static void ctorArrayTy(Block *, char *Ptr, bool, bool, bool, Descriptor *D) {
+ for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
+ new (&reinterpret_cast<T *>(Ptr)[I]) T();
+ }
+}
+
+template <typename T>
+static void dtorArrayTy(Block *, char *Ptr, Descriptor *D) {
+ for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
+ reinterpret_cast<T *>(Ptr)[I].~T();
+ }
+}
+
+template <typename T>
+static void moveArrayTy(Block *, char *Src, char *Dst, Descriptor *D) {
+ for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
+ auto *SrcPtr = &reinterpret_cast<T *>(Src)[I];
+ auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
+ new (DstPtr) T(std::move(*SrcPtr));
+ }
+}
+
+static void ctorArrayDesc(Block *B, char *Ptr, bool IsConst, bool IsMutable,
+ bool IsActive, Descriptor *D) {
+ const unsigned NumElems = D->getNumElems();
+ const unsigned ElemSize =
+ D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
+
+ unsigned ElemOffset = 0;
+ for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
+ auto *ElemPtr = Ptr + ElemOffset;
+ auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
+ auto *ElemLoc = reinterpret_cast<char *>(Desc + 1);
+ auto *SD = D->ElemDesc;
+
+ Desc->Offset = ElemOffset + sizeof(InlineDescriptor);
+ Desc->Desc = SD;
+ Desc->IsInitialized = true;
+ Desc->IsBase = false;
+ Desc->IsActive = IsActive;
+ Desc->IsConst = IsConst || D->IsConst;
+ Desc->IsMutable = IsMutable || D->IsMutable;
+ if (auto Fn = D->ElemDesc->CtorFn)
+ Fn(B, ElemLoc, Desc->IsConst, Desc->IsMutable, IsActive, D->ElemDesc);
+ }
+}
+
+static void dtorArrayDesc(Block *B, char *Ptr, Descriptor *D) {
+ const unsigned NumElems = D->getNumElems();
+ const unsigned ElemSize =
+ D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
+
+ unsigned ElemOffset = 0;
+ for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
+ auto *ElemPtr = Ptr + ElemOffset;
+ auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
+ auto *ElemLoc = reinterpret_cast<char *>(Desc + 1);
+ if (auto Fn = D->ElemDesc->DtorFn)
+ Fn(B, ElemLoc, D->ElemDesc);
+ }
+}
+
+static void moveArrayDesc(Block *B, char *Src, char *Dst, Descriptor *D) {
+ const unsigned NumElems = D->getNumElems();
+ const unsigned ElemSize =
+ D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
+
+ unsigned ElemOffset = 0;
+ for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
+ auto *SrcPtr = Src + ElemOffset;
+ auto *DstPtr = Dst + ElemOffset;
+
+ auto *SrcDesc = reinterpret_cast<InlineDescriptor *>(SrcPtr);
+ auto *SrcElemLoc = reinterpret_cast<char *>(SrcDesc + 1);
+ auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr);
+ auto *DstElemLoc = reinterpret_cast<char *>(DstDesc + 1);
+
+ *DstDesc = *SrcDesc;
+ if (auto Fn = D->ElemDesc->MoveFn)
+ Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc);
+ }
+}
+
+static void ctorRecord(Block *B, char *Ptr, bool IsConst, bool IsMutable,
+ bool IsActive, Descriptor *D) {
+ const bool IsUnion = D->ElemRecord->isUnion();
+ auto CtorSub = [=](unsigned SubOff, Descriptor *F, bool IsBase) {
+ auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1;
+ Desc->Offset = SubOff;
+ Desc->Desc = F;
+ Desc->IsInitialized = (B->isStatic() || F->IsArray) && !IsBase;
+ Desc->IsBase = IsBase;
+ Desc->IsActive = IsActive && !IsUnion;
+ Desc->IsConst = IsConst || F->IsConst;
+ Desc->IsMutable = IsMutable || F->IsMutable;
+ if (auto Fn = F->CtorFn)
+ Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsMutable, Desc->IsActive, F);
+ };
+ for (const auto &B : D->ElemRecord->bases())
+ CtorSub(B.Offset, B.Desc, /*isBase=*/true);
+ for (const auto &F : D->ElemRecord->fields())
+ CtorSub(F.Offset, F.Desc, /*isBase=*/false);
+ for (const auto &V : D->ElemRecord->virtual_bases())
+ CtorSub(V.Offset, V.Desc, /*isBase=*/true);
+}
+
+static void dtorRecord(Block *B, char *Ptr, Descriptor *D) {
+ auto DtorSub = [=](unsigned SubOff, Descriptor *F) {
+ if (auto Fn = F->DtorFn)
+ Fn(B, Ptr + SubOff, F);
+ };
+ for (const auto &F : D->ElemRecord->bases())
+ DtorSub(F.Offset, F.Desc);
+ for (const auto &F : D->ElemRecord->fields())
+ DtorSub(F.Offset, F.Desc);
+ for (const auto &F : D->ElemRecord->virtual_bases())
+ DtorSub(F.Offset, F.Desc);
+}
+
+static void moveRecord(Block *B, char *Src, char *Dst, Descriptor *D) {
+ for (const auto &F : D->ElemRecord->fields()) {
+ auto FieldOff = F.Offset;
+ auto FieldDesc = F.Desc;
+
+ *(reinterpret_cast<Descriptor **>(Dst + FieldOff) - 1) = FieldDesc;
+ if (auto Fn = FieldDesc->MoveFn)
+ Fn(B, Src + FieldOff, Dst + FieldOff, FieldDesc);
+ }
+}
+
+static BlockCtorFn getCtorPrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
+}
+
+static BlockDtorFn getDtorPrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
+}
+
+static BlockMoveFn getMovePrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr);
+}
+
+static BlockCtorFn getCtorArrayPrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return ctorArrayTy<T>, return nullptr);
+}
+
+static BlockDtorFn getDtorArrayPrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return dtorArrayTy<T>, return nullptr);
+}
+
+static BlockMoveFn getMoveArrayPrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return moveArrayTy<T>, return nullptr);
+}
+
+Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsConst,
+ bool IsTemporary, bool IsMutable)
+ : Source(D), ElemSize(primSize(Type)), Size(ElemSize), AllocSize(Size),
+ IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
+ CtorFn(getCtorPrim(Type)), DtorFn(getDtorPrim(Type)),
+ MoveFn(getMovePrim(Type)) {
+ assert(Source && "Missing source");
+}
+
+Descriptor::Descriptor(const DeclTy &D, PrimType Type, size_t NumElems,
+ bool IsConst, bool IsTemporary, bool IsMutable)
+ : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
+ AllocSize(align(Size) + sizeof(InitMap *)), IsConst(IsConst),
+ IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true),
+ CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),
+ MoveFn(getMoveArrayPrim(Type)) {
+ assert(Source && "Missing source");
+}
+
+Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary,
+ UnknownSize)
+ : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
+ AllocSize(alignof(void *)), IsConst(true), IsMutable(false),
+ IsTemporary(IsTemporary), IsArray(true), CtorFn(getCtorArrayPrim(Type)),
+ DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
+ assert(Source && "Missing source");
+}
+
+Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, unsigned NumElems,
+ bool IsConst, bool IsTemporary, bool IsMutable)
+ : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
+ Size(ElemSize * NumElems),
+ AllocSize(std::max<size_t>(alignof(void *), Size)), ElemDesc(Elem),
+ IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
+ IsArray(true), CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc),
+ MoveFn(moveArrayDesc) {
+ assert(Source && "Missing source");
+}
+
+Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary,
+ UnknownSize)
+ : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
+ Size(UnknownSizeMark), AllocSize(alignof(void *)), ElemDesc(Elem),
+ IsConst(true), IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
+ CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
+ assert(Source && "Missing source");
+}
+
+Descriptor::Descriptor(const DeclTy &D, Record *R, bool IsConst,
+ bool IsTemporary, bool IsMutable)
+ : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
+ Size(ElemSize), AllocSize(Size), ElemRecord(R), IsConst(IsConst),
+ IsMutable(IsMutable), IsTemporary(IsTemporary), CtorFn(ctorRecord),
+ DtorFn(dtorRecord), MoveFn(moveRecord) {
+ assert(Source && "Missing source");
+}
+
+QualType Descriptor::getType() const {
+ if (auto *E = asExpr())
+ return E->getType();
+ if (auto *D = asValueDecl())
+ return D->getType();
+ llvm_unreachable("Invalid descriptor type");
+}
+
+SourceLocation Descriptor::getLocation() const {
+ if (auto *D = Source.dyn_cast<const Decl *>())
+ return D->getLocation();
+ if (auto *E = Source.dyn_cast<const Expr *>())
+ return E->getExprLoc();
+ llvm_unreachable("Invalid descriptor type");
+}
+
+InitMap::InitMap(unsigned N) : UninitFields(N) {
+ for (unsigned I = 0; I < N / PER_FIELD; ++I) {
+ data()[I] = 0;
+ }
+}
+
+InitMap::T *InitMap::data() {
+ auto *Start = reinterpret_cast<char *>(this) + align(sizeof(InitMap));
+ return reinterpret_cast<T *>(Start);
+}
+
+bool InitMap::initialize(unsigned I) {
+ unsigned Bucket = I / PER_FIELD;
+ unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD);
+ if (!(data()[Bucket] & Mask)) {
+ data()[Bucket] |= Mask;
+ UninitFields -= 1;
+ }
+ return UninitFields == 0;
+}
+
+bool InitMap::isInitialized(unsigned I) {
+ unsigned Bucket = I / PER_FIELD;
+ unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD);
+ return data()[Bucket] & Mask;
+}
+
+InitMap *InitMap::allocate(unsigned N) {
+ const size_t NumFields = ((N + PER_FIELD - 1) / PER_FIELD);
+ const size_t Size = align(sizeof(InitMap)) + NumFields * PER_FIELD;
+ return new (malloc(Size)) InitMap(N);
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.h b/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.h
new file mode 100644
index 000000000000..b260b7600974
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.h
@@ -0,0 +1,220 @@
+//===--- Descriptor.h - Types for the constexpr VM --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines descriptors which characterise allocations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
+#define LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+namespace interp {
+class Block;
+class Record;
+struct Descriptor;
+enum PrimType : unsigned;
+
+using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
+
+/// Invoked whenever a block is created. The constructor method fills in the
+/// inline descriptors of all fields and array elements. It also initializes
+/// all the fields which contain non-trivial types.
+using BlockCtorFn = void (*)(Block *Storage, char *FieldPtr, bool IsConst,
+ bool IsMutable, bool IsActive,
+ Descriptor *FieldDesc);
+
+/// Invoked when a block is destroyed. Invokes the destructors of all
+/// non-trivial nested fields of arrays and records.
+using BlockDtorFn = void (*)(Block *Storage, char *FieldPtr,
+ Descriptor *FieldDesc);
+
+/// Invoked when a block with pointers referencing it goes out of scope. Such
+/// blocks are persisted: the move function copies all inline descriptors and
+/// non-trivial fields, as existing pointers might need to reference those
+/// descriptors. Data is not copied since it cannot be legally read.
+using BlockMoveFn = void (*)(Block *Storage, char *SrcFieldPtr,
+ char *DstFieldPtr, Descriptor *FieldDesc);
+
+/// Object size as used by the interpreter.
+using InterpSize = unsigned;
+
+/// Describes a memory block created by an allocation site.
+struct Descriptor {
+private:
+ /// Original declaration, used to emit the error message.
+ const DeclTy Source;
+ /// Size of an element, in host bytes.
+ const InterpSize ElemSize;
+ /// Size of the storage, in host bytes.
+ const InterpSize Size;
+ /// Size of the allocation (storage + metadata), in host bytes.
+ const InterpSize AllocSize;
+
+ /// Value to denote arrays of unknown size.
+ static constexpr unsigned UnknownSizeMark = (unsigned)-1;
+
+public:
+ /// Token to denote structures of unknown size.
+ struct UnknownSize {};
+
+ /// Pointer to the record, if block contains records.
+ Record *const ElemRecord = nullptr;
+ /// Descriptor of the array element.
+ Descriptor *const ElemDesc = nullptr;
+ /// Flag indicating if the block is mutable.
+ const bool IsConst = false;
+ /// Flag indicating if a field is mutable.
+ const bool IsMutable = false;
+ /// Flag indicating if the block is a temporary.
+ const bool IsTemporary = false;
+ /// Flag indicating if the block is an array.
+ const bool IsArray = false;
+
+ /// Storage management methods.
+ const BlockCtorFn CtorFn = nullptr;
+ const BlockDtorFn DtorFn = nullptr;
+ const BlockMoveFn MoveFn = nullptr;
+
+ /// Allocates a descriptor for a primitive.
+ Descriptor(const DeclTy &D, PrimType Type, bool IsConst, bool IsTemporary,
+ bool IsMutable);
+
+ /// Allocates a descriptor for an array of primitives.
+ Descriptor(const DeclTy &D, PrimType Type, size_t NumElems, bool IsConst,
+ bool IsTemporary, bool IsMutable);
+
+ /// Allocates a descriptor for an array of primitives of unknown size.
+ Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary, UnknownSize);
+
+ /// Allocates a descriptor for an array of composites.
+ Descriptor(const DeclTy &D, Descriptor *Elem, unsigned NumElems, bool IsConst,
+ bool IsTemporary, bool IsMutable);
+
+ /// Allocates a descriptor for an array of composites of unknown size.
+ Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary, UnknownSize);
+
+ /// Allocates a descriptor for a record.
+ Descriptor(const DeclTy &D, Record *R, bool IsConst, bool IsTemporary,
+ bool IsMutable);
+
+ QualType getType() const;
+ SourceLocation getLocation() const;
+
+ const Decl *asDecl() const { return Source.dyn_cast<const Decl *>(); }
+ const Expr *asExpr() const { return Source.dyn_cast<const Expr *>(); }
+
+ const ValueDecl *asValueDecl() const {
+ return dyn_cast_or_null<ValueDecl>(asDecl());
+ }
+
+ const FieldDecl *asFieldDecl() const {
+ return dyn_cast_or_null<FieldDecl>(asDecl());
+ }
+
+ const RecordDecl *asRecordDecl() const {
+ return dyn_cast_or_null<RecordDecl>(asDecl());
+ }
+
+ /// Returns the size of the object without metadata.
+ unsigned getSize() const {
+ assert(!isUnknownSizeArray() && "Array of unknown size");
+ return Size;
+ }
+
+ /// Returns the allocated size, including metadata.
+ unsigned getAllocSize() const { return AllocSize; }
+ /// returns the size of an element when the structure is viewed as an array.
+ unsigned getElemSize() const { return ElemSize; }
+
+ /// Returns the number of elements stored in the block.
+ unsigned getNumElems() const {
+ return Size == UnknownSizeMark ? 0 : (getSize() / getElemSize());
+ }
+
+ /// Checks if the descriptor is of an array of primitives.
+ bool isPrimitiveArray() const { return IsArray && !ElemDesc; }
+ /// Checks if the descriptor is of an array of zero size.
+ bool isZeroSizeArray() const { return Size == 0; }
+ /// Checks if the descriptor is of an array of unknown size.
+ bool isUnknownSizeArray() const { return Size == UnknownSizeMark; }
+
+ /// Checks if the descriptor is of a primitive.
+ bool isPrimitive() const { return !IsArray && !ElemRecord; }
+
+ /// Checks if the descriptor is of an array.
+ bool isArray() const { return IsArray; }
+};
+
+/// Inline descriptor embedded in structures and arrays.
+///
+/// Such descriptors precede all composite array elements and structure fields.
+/// If the base of a pointer is not zero, the base points to the end of this
+/// structure. The offset field is used to traverse the pointer chain up
+/// to the root structure which allocated the object.
+struct InlineDescriptor {
+ /// Offset inside the structure/array.
+ unsigned Offset;
+
+ /// Flag indicating if the storage is constant or not.
+ /// Relevant for primitive fields.
+ unsigned IsConst : 1;
+ /// For primitive fields, it indicates if the field was initialized.
+ /// Primitive fields in static storage are always initialized.
+ /// Arrays are always initialized, even though their elements might not be.
+ /// Base classes are initialized after the constructor is invoked.
+ unsigned IsInitialized : 1;
+ /// Flag indicating if the field is an embedded base class.
+ unsigned IsBase : 1;
+ /// Flag indicating if the field is the active member of a union.
+ unsigned IsActive : 1;
+ /// Flag indicating if the field is mutable (if in a record).
+ unsigned IsMutable : 1;
+
+ Descriptor *Desc;
+};
+
+/// Bitfield tracking the initialisation status of elements of primitive arrays.
+/// A pointer to this is embedded at the end of all primitive arrays.
+/// If the map was not yet created and nothing was initialied, the pointer to
+/// this structure is 0. If the object was fully initialized, the pointer is -1.
+struct InitMap {
+private:
+ /// Type packing bits.
+ using T = uint64_t;
+ /// Bits stored in a single field.
+ static constexpr uint64_t PER_FIELD = sizeof(T) * CHAR_BIT;
+
+ /// Initializes the map with no fields set.
+ InitMap(unsigned N);
+
+ /// Returns a pointer to storage.
+ T *data();
+
+public:
+ /// Initializes an element. Returns true when object if fully initialized.
+ bool initialize(unsigned I);
+
+ /// Checks if an element was initialized.
+ bool isInitialized(unsigned I);
+
+ /// Allocates a map holding N elements.
+ static InitMap *allocate(unsigned N);
+
+private:
+ /// Number of fields initialized.
+ unsigned UninitFields;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Disasm.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Disasm.cpp
new file mode 100644
index 000000000000..e77a825eb1f2
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Disasm.cpp
@@ -0,0 +1,69 @@
+//===--- Disasm.cpp - Disassembler for bytecode functions -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Dump method for Function which disassembles the bytecode.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Function.h"
+#include "Opcode.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "clang/AST/DeclCXX.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
+
+LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
+ if (F) {
+ if (auto *Cons = dyn_cast<CXXConstructorDecl>(F)) {
+ const std::string &Name = Cons->getParent()->getNameAsString();
+ OS << Name << "::" << Name << ":\n";
+ } else {
+ OS << F->getNameAsString() << ":\n";
+ }
+ } else {
+ OS << "<<expr>>\n";
+ }
+
+ OS << "frame size: " << getFrameSize() << "\n";
+ OS << "arg size: " << getArgSize() << "\n";
+ OS << "rvo: " << hasRVO() << "\n";
+
+ auto PrintName = [&OS](const char *Name) {
+ OS << Name;
+ for (long I = 0, N = strlen(Name); I < 30 - N; ++I) {
+ OS << ' ';
+ }
+ };
+
+ for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
+ size_t Addr = PC - Start;
+ auto Op = PC.read<Opcode>();
+ OS << llvm::format("%8d", Addr) << " ";
+ switch (Op) {
+#define GET_DISASM
+#include "Opcodes.inc"
+#undef GET_DISASM
+ }
+ }
+}
+
+LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
+
+LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
+ for (auto &Func : Funcs) {
+ Func.second->dump();
+ }
+ for (auto &Anon : AnonFuncs) {
+ Anon->dump();
+ }
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.cpp b/contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.cpp
new file mode 100644
index 000000000000..22e8695b9211
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -0,0 +1,253 @@
+//===--- EvalEmitter.cpp - Instruction emitter for the VM -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "EvalEmitter.h"
+#include "Context.h"
+#include "Interp.h"
+#include "Opcode.h"
+#include "Program.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+using APSInt = llvm::APSInt;
+template <typename T> using Expected = llvm::Expected<T>;
+
+EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
+ InterpStack &Stk, APValue &Result)
+ : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), Result(Result) {
+ // Create a dummy frame for the interpreter which does not have locals.
+ S.Current = new InterpFrame(S, nullptr, nullptr, CodePtr(), Pointer());
+}
+
+llvm::Expected<bool> EvalEmitter::interpretExpr(const Expr *E) {
+ if (this->visitExpr(E))
+ return true;
+ if (BailLocation)
+ return llvm::make_error<ByteCodeGenError>(*BailLocation);
+ return false;
+}
+
+llvm::Expected<bool> EvalEmitter::interpretDecl(const VarDecl *VD) {
+ if (this->visitDecl(VD))
+ return true;
+ if (BailLocation)
+ return llvm::make_error<ByteCodeGenError>(*BailLocation);
+ return false;
+}
+
+void EvalEmitter::emitLabel(LabelTy Label) {
+ CurrentLabel = Label;
+}
+
+EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }
+
+Scope::Local EvalEmitter::createLocal(Descriptor *D) {
+ // Allocate memory for a local.
+ auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize());
+ auto *B = new (Memory.get()) Block(D, /*isStatic=*/false);
+ B->invokeCtor();
+
+ // Register the local.
+ unsigned Off = Locals.size();
+ Locals.insert({Off, std::move(Memory)});
+ return {Off, D};
+}
+
+bool EvalEmitter::bail(const SourceLocation &Loc) {
+ if (!BailLocation)
+ BailLocation = Loc;
+ return false;
+}
+
+bool EvalEmitter::jumpTrue(const LabelTy &Label) {
+ if (isActive()) {
+ if (S.Stk.pop<bool>())
+ ActiveLabel = Label;
+ }
+ return true;
+}
+
+bool EvalEmitter::jumpFalse(const LabelTy &Label) {
+ if (isActive()) {
+ if (!S.Stk.pop<bool>())
+ ActiveLabel = Label;
+ }
+ return true;
+}
+
+bool EvalEmitter::jump(const LabelTy &Label) {
+ if (isActive())
+ CurrentLabel = ActiveLabel = Label;
+ return true;
+}
+
+bool EvalEmitter::fallthrough(const LabelTy &Label) {
+ if (isActive())
+ ActiveLabel = Label;
+ CurrentLabel = Label;
+ return true;
+}
+
+template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
+ if (!isActive())
+ return true;
+ using T = typename PrimConv<OpType>::T;
+ return ReturnValue<T>(S.Stk.pop<T>(), Result);
+}
+
+bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { return true; }
+
+bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
+ // Method to recursively traverse composites.
+ std::function<bool(QualType, const Pointer &, APValue &)> Composite;
+ Composite = [this, &Composite](QualType Ty, const Pointer &Ptr, APValue &R) {
+ if (auto *AT = Ty->getAs<AtomicType>())
+ Ty = AT->getValueType();
+
+ if (auto *RT = Ty->getAs<RecordType>()) {
+ auto *Record = Ptr.getRecord();
+ assert(Record && "Missing record descriptor");
+
+ bool Ok = true;
+ if (RT->getDecl()->isUnion()) {
+ const FieldDecl *ActiveField = nullptr;
+ APValue Value;
+ for (auto &F : Record->fields()) {
+ const Pointer &FP = Ptr.atField(F.Offset);
+ QualType FieldTy = F.Decl->getType();
+ if (FP.isActive()) {
+ if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
+ TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
+ } else {
+ Ok &= Composite(FieldTy, FP, Value);
+ }
+ break;
+ }
+ }
+ R = APValue(ActiveField, Value);
+ } else {
+ unsigned NF = Record->getNumFields();
+ unsigned NB = Record->getNumBases();
+ unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
+
+ R = APValue(APValue::UninitStruct(), NB, NF);
+
+ for (unsigned I = 0; I < NF; ++I) {
+ const Record::Field *FD = Record->getField(I);
+ QualType FieldTy = FD->Decl->getType();
+ const Pointer &FP = Ptr.atField(FD->Offset);
+ APValue &Value = R.getStructField(I);
+
+ if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
+ TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
+ } else {
+ Ok &= Composite(FieldTy, FP, Value);
+ }
+ }
+
+ for (unsigned I = 0; I < NB; ++I) {
+ const Record::Base *BD = Record->getBase(I);
+ QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
+ const Pointer &BP = Ptr.atField(BD->Offset);
+ Ok &= Composite(BaseTy, BP, R.getStructBase(I));
+ }
+
+ for (unsigned I = 0; I < NV; ++I) {
+ const Record::Base *VD = Record->getVirtualBase(I);
+ QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
+ const Pointer &VP = Ptr.atField(VD->Offset);
+ Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
+ }
+ }
+ return Ok;
+ }
+ if (auto *AT = Ty->getAsArrayTypeUnsafe()) {
+ const size_t NumElems = Ptr.getNumElems();
+ QualType ElemTy = AT->getElementType();
+ R = APValue(APValue::UninitArray{}, NumElems, NumElems);
+
+ bool Ok = true;
+ for (unsigned I = 0; I < NumElems; ++I) {
+ APValue &Slot = R.getArrayInitializedElt(I);
+ const Pointer &EP = Ptr.atIndex(I);
+ if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
+ TYPE_SWITCH(*T, Ok &= ReturnValue<T>(EP.deref<T>(), Slot));
+ } else {
+ Ok &= Composite(ElemTy, EP.narrow(), Slot);
+ }
+ }
+ return Ok;
+ }
+ llvm_unreachable("invalid value to return");
+ };
+
+ // Return the composite type.
+ const auto &Ptr = S.Stk.pop<Pointer>();
+ return Composite(Ptr.getType(), Ptr, Result);
+}
+
+bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) {
+ if (!isActive())
+ return true;
+
+ auto It = Locals.find(I);
+ assert(It != Locals.end() && "Missing local variable");
+ S.Stk.push<Pointer>(reinterpret_cast<Block *>(It->second.get()));
+ return true;
+}
+
+template <PrimType OpType>
+bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
+ if (!isActive())
+ return true;
+
+ using T = typename PrimConv<OpType>::T;
+
+ auto It = Locals.find(I);
+ assert(It != Locals.end() && "Missing local variable");
+ auto *B = reinterpret_cast<Block *>(It->second.get());
+ S.Stk.push<T>(*reinterpret_cast<T *>(B + 1));
+ return true;
+}
+
+template <PrimType OpType>
+bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) {
+ if (!isActive())
+ return true;
+
+ using T = typename PrimConv<OpType>::T;
+
+ auto It = Locals.find(I);
+ assert(It != Locals.end() && "Missing local variable");
+ auto *B = reinterpret_cast<Block *>(It->second.get());
+ *reinterpret_cast<T *>(B + 1) = S.Stk.pop<T>();
+ return true;
+}
+
+bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) {
+ if (!isActive())
+ return true;
+
+ for (auto &Local : Descriptors[I]) {
+ auto It = Locals.find(Local.Offset);
+ assert(It != Locals.end() && "Missing local variable");
+ S.deallocate(reinterpret_cast<Block *>(It->second.get()));
+ }
+
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Opcode evaluators
+//===----------------------------------------------------------------------===//
+
+#define GET_EVAL_IMPL
+#include "Opcodes.inc"
+#undef GET_EVAL_IMPL
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.h b/contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.h
new file mode 100644
index 000000000000..eec2ff8ee753
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.h
@@ -0,0 +1,129 @@
+//===--- EvalEmitter.h - Instruction emitter for the VM ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the instruction emitters.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_EVALEMITTER_H
+#define LLVM_CLANG_AST_INTERP_EVALEMITTER_H
+
+#include "ByteCodeGenError.h"
+#include "Context.h"
+#include "InterpStack.h"
+#include "InterpState.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "Source.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+class FunctionDecl;
+namespace interp {
+class Context;
+class Function;
+class InterpState;
+class Program;
+class SourceInfo;
+enum Opcode : uint32_t;
+
+/// An emitter which evaluates opcodes as they are emitted.
+class EvalEmitter : public SourceMapper {
+public:
+ using LabelTy = uint32_t;
+ using AddrTy = uintptr_t;
+ using Local = Scope::Local;
+
+ llvm::Expected<bool> interpretExpr(const Expr *E);
+ llvm::Expected<bool> interpretDecl(const VarDecl *VD);
+
+protected:
+ EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk,
+ APValue &Result);
+
+ virtual ~EvalEmitter() {}
+
+ /// Define a label.
+ void emitLabel(LabelTy Label);
+ /// Create a label.
+ LabelTy getLabel();
+
+ /// Methods implemented by the compiler.
+ virtual bool visitExpr(const Expr *E) = 0;
+ virtual bool visitDecl(const VarDecl *VD) = 0;
+
+ bool bail(const Stmt *S) { return bail(S->getBeginLoc()); }
+ bool bail(const Decl *D) { return bail(D->getBeginLoc()); }
+ bool bail(const SourceLocation &Loc);
+
+ /// Emits jumps.
+ bool jumpTrue(const LabelTy &Label);
+ bool jumpFalse(const LabelTy &Label);
+ bool jump(const LabelTy &Label);
+ bool fallthrough(const LabelTy &Label);
+
+ /// Callback for registering a local.
+ Local createLocal(Descriptor *D);
+
+ /// Returns the source location of the current opcode.
+ SourceInfo getSource(Function *F, CodePtr PC) const override {
+ return F ? F->getSource(PC) : CurrentSource;
+ }
+
+ /// Parameter indices.
+ llvm::DenseMap<const ParmVarDecl *, unsigned> Params;
+ /// Local descriptors.
+ llvm::SmallVector<SmallVector<Local, 8>, 2> Descriptors;
+
+private:
+ /// Current compilation context.
+ Context &Ctx;
+ /// Current program.
+ Program &P;
+ /// Callee evaluation state.
+ InterpState S;
+ /// Location to write the result to.
+ APValue &Result;
+
+ /// Temporaries which require storage.
+ llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Locals;
+
+ // The emitter always tracks the current instruction and sets OpPC to a token
+ // value which is mapped to the location of the opcode being evaluated.
+ CodePtr OpPC;
+ /// Location of a failure.
+ llvm::Optional<SourceLocation> BailLocation;
+ /// Location of the current instruction.
+ SourceInfo CurrentSource;
+
+ /// Next label ID to generate - first label is 1.
+ LabelTy NextLabel = 1;
+ /// Label being executed - 0 is the entry label.
+ LabelTy CurrentLabel = 0;
+ /// Active block which should be executed.
+ LabelTy ActiveLabel = 0;
+
+ /// Since expressions can only jump forward, predicated execution is
+ /// used to deal with if-else statements.
+ bool isActive() { return CurrentLabel == ActiveLabel; }
+
+ /// Helper to invoke a method.
+ bool ExecuteCall(Function *F, Pointer &&This, const SourceInfo &Info);
+ /// Helper to emit a diagnostic on a missing method.
+ bool ExecuteNoCall(const FunctionDecl *F, const SourceInfo &Info);
+
+protected:
+#define GET_EVAL_PROTO
+#include "Opcodes.inc"
+#undef GET_EVAL_PROTO
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Frame.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Frame.cpp
new file mode 100644
index 000000000000..16134aa1db36
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Frame.cpp
@@ -0,0 +1,14 @@
+//===--- Frame.cpp - Call frame for the VM and AST Walker -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Frame.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+Frame::~Frame() {}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Frame.h b/contrib/llvm-project/clang/lib/AST/Interp/Frame.h
new file mode 100644
index 000000000000..b9a0ea9412f8
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Frame.h
@@ -0,0 +1,45 @@
+//===--- Frame.h - Call frame for the VM and AST Walker ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the base class of interpreter and evaluator stack frames.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_FRAME_H
+#define LLVM_CLANG_AST_INTERP_FRAME_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+class FunctionDecl;
+
+namespace interp {
+
+/// Base class for stack frames, shared between VM and walker.
+class Frame {
+public:
+ virtual ~Frame();
+
+ /// Generates a human-readable description of the call site.
+ virtual void describe(llvm::raw_ostream &OS) = 0;
+
+ /// Returns a pointer to the caller frame.
+ virtual Frame *getCaller() const = 0;
+
+ /// Returns the location of the call site.
+ virtual SourceLocation getCallLocation() const = 0;
+
+ /// Returns the called function's declaration.
+ virtual const FunctionDecl *getCallee() const = 0;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Function.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Function.cpp
new file mode 100644
index 000000000000..0ed13a92aa38
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Function.cpp
@@ -0,0 +1,48 @@
+//===--- Function.h - Bytecode function for the VM --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Function.h"
+#include "Program.h"
+#include "Opcode.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+Function::Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
+ llvm::SmallVector<PrimType, 8> &&ParamTypes,
+ llvm::DenseMap<unsigned, ParamDescriptor> &&Params)
+ : P(P), Loc(F->getBeginLoc()), F(F), ArgSize(ArgSize),
+ ParamTypes(std::move(ParamTypes)), Params(std::move(Params)) {}
+
+CodePtr Function::getCodeBegin() const { return Code.data(); }
+
+CodePtr Function::getCodeEnd() const { return Code.data() + Code.size(); }
+
+Function::ParamDescriptor Function::getParamDescriptor(unsigned Offset) const {
+ auto It = Params.find(Offset);
+ assert(It != Params.end() && "Invalid parameter offset");
+ return It->second;
+}
+
+SourceInfo Function::getSource(CodePtr PC) const {
+ unsigned Offset = PC - getCodeBegin();
+ using Elem = std::pair<unsigned, SourceInfo>;
+ auto It = std::lower_bound(SrcMap.begin(), SrcMap.end(), Elem{Offset, {}},
+ [](Elem A, Elem B) { return A.first < B.first; });
+ if (It == SrcMap.end() || It->first != Offset)
+ llvm::report_fatal_error("missing source location");
+ return It->second;
+}
+
+bool Function::isVirtual() const {
+ if (auto *M = dyn_cast<CXXMethodDecl>(F))
+ return M->isVirtual();
+ return false;
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Function.h b/contrib/llvm-project/clang/lib/AST/Interp/Function.h
new file mode 100644
index 000000000000..28531f04b6e9
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Function.h
@@ -0,0 +1,163 @@
+//===--- Function.h - Bytecode function for the VM --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the Function class which holds all bytecode function-specific data.
+//
+// The scope class which describes local variables is also defined here.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_FUNCTION_H
+#define LLVM_CLANG_AST_INTERP_FUNCTION_H
+
+#include "Pointer.h"
+#include "Source.h"
+#include "clang/AST/Decl.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace interp {
+class Program;
+class ByteCodeEmitter;
+enum PrimType : uint32_t;
+
+/// Describes a scope block.
+///
+/// The block gathers all the descriptors of the locals defined in this block.
+class Scope {
+public:
+ /// Information about a local's storage.
+ struct Local {
+ /// Offset of the local in frame.
+ unsigned Offset;
+ /// Descriptor of the local.
+ Descriptor *Desc;
+ };
+
+ using LocalVectorTy = llvm::SmallVector<Local, 8>;
+
+ Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
+
+ llvm::iterator_range<LocalVectorTy::iterator> locals() {
+ return llvm::make_range(Descriptors.begin(), Descriptors.end());
+ }
+
+private:
+ /// Object descriptors in this block.
+ LocalVectorTy Descriptors;
+};
+
+/// Bytecode function.
+///
+/// Contains links to the bytecode of the function, as well as metadata
+/// describing all arguments and stack-local variables.
+class Function {
+public:
+ using ParamDescriptor = std::pair<PrimType, Descriptor *>;
+
+ /// Returns the size of the function's local stack.
+ unsigned getFrameSize() const { return FrameSize; }
+ /// Returns the size of the argument stackx
+ unsigned getArgSize() const { return ArgSize; }
+
+ /// Returns a pointer to the start of the code.
+ CodePtr getCodeBegin() const;
+ /// Returns a pointer to the end of the code.
+ CodePtr getCodeEnd() const;
+
+ /// Returns the original FunctionDecl.
+ const FunctionDecl *getDecl() const { return F; }
+
+ /// Returns the lcoation.
+ SourceLocation getLoc() const { return Loc; }
+
+ /// Returns a parameter descriptor.
+ ParamDescriptor getParamDescriptor(unsigned Offset) const;
+
+ /// Checks if the first argument is a RVO pointer.
+ bool hasRVO() const { return ParamTypes.size() != Params.size(); }
+
+ /// Range over the scope blocks.
+ llvm::iterator_range<llvm::SmallVector<Scope, 2>::iterator> scopes() {
+ return llvm::make_range(Scopes.begin(), Scopes.end());
+ }
+
+ /// Range over argument types.
+ using arg_reverse_iterator = SmallVectorImpl<PrimType>::reverse_iterator;
+ llvm::iterator_range<arg_reverse_iterator> args_reverse() {
+ return llvm::make_range(ParamTypes.rbegin(), ParamTypes.rend());
+ }
+
+ /// Returns a specific scope.
+ Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
+
+ /// Returns the source information at a given PC.
+ SourceInfo getSource(CodePtr PC) const;
+
+ /// Checks if the function is valid to call in constexpr.
+ bool isConstexpr() const { return IsValid; }
+
+ /// Checks if the function is virtual.
+ bool isVirtual() const;
+
+ /// Checks if the function is a constructor.
+ bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
+
+private:
+ /// Construct a function representing an actual function.
+ Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
+ llvm::SmallVector<PrimType, 8> &&ParamTypes,
+ llvm::DenseMap<unsigned, ParamDescriptor> &&Params);
+
+ /// Sets the code of a function.
+ void setCode(unsigned NewFrameSize, std::vector<char> &&NewCode, SourceMap &&NewSrcMap,
+ llvm::SmallVector<Scope, 2> &&NewScopes) {
+ FrameSize = NewFrameSize;
+ Code = std::move(NewCode);
+ SrcMap = std::move(NewSrcMap);
+ Scopes = std::move(NewScopes);
+ IsValid = true;
+ }
+
+private:
+ friend class Program;
+ friend class ByteCodeEmitter;
+
+ /// Program reference.
+ Program &P;
+ /// Location of the executed code.
+ SourceLocation Loc;
+ /// Declaration this function was compiled from.
+ const FunctionDecl *F;
+ /// Local area size: storage + metadata.
+ unsigned FrameSize;
+ /// Size of the argument stack.
+ unsigned ArgSize;
+ /// Program code.
+ std::vector<char> Code;
+ /// Opcode-to-expression mapping.
+ SourceMap SrcMap;
+ /// List of block descriptors.
+ llvm::SmallVector<Scope, 2> Scopes;
+ /// List of argument types.
+ llvm::SmallVector<PrimType, 8> ParamTypes;
+ /// Map from byte offset to parameter descriptor.
+ llvm::DenseMap<unsigned, ParamDescriptor> Params;
+ /// Flag to indicate if the function is valid.
+ bool IsValid = false;
+
+public:
+ /// Dumps the disassembled bytecode to \c llvm::errs().
+ void dump() const;
+ void dump(llvm::raw_ostream &OS) const;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Integral.h b/contrib/llvm-project/clang/lib/AST/Interp/Integral.h
new file mode 100644
index 000000000000..7cc788070de8
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Integral.h
@@ -0,0 +1,269 @@
+//===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the VM types and helpers operating on types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_H
+#define LLVM_CLANG_AST_INTERP_INTEGRAL_H
+
+#include "clang/AST/ComparisonCategories.h"
+#include "clang/AST/APValue.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+
+namespace clang {
+namespace interp {
+
+using APInt = llvm::APInt;
+using APSInt = llvm::APSInt;
+
+/// Helper to compare two comparable types.
+template <typename T>
+ComparisonCategoryResult Compare(const T &X, const T &Y) {
+ if (X < Y)
+ return ComparisonCategoryResult::Less;
+ if (X > Y)
+ return ComparisonCategoryResult::Greater;
+ return ComparisonCategoryResult::Equal;
+}
+
+// Helper structure to select the representation.
+template <unsigned Bits, bool Signed> struct Repr;
+template <> struct Repr<8, false> { using Type = uint8_t; };
+template <> struct Repr<16, false> { using Type = uint16_t; };
+template <> struct Repr<32, false> { using Type = uint32_t; };
+template <> struct Repr<64, false> { using Type = uint64_t; };
+template <> struct Repr<8, true> { using Type = int8_t; };
+template <> struct Repr<16, true> { using Type = int16_t; };
+template <> struct Repr<32, true> { using Type = int32_t; };
+template <> struct Repr<64, true> { using Type = int64_t; };
+
+/// Wrapper around numeric types.
+///
+/// These wrappers are required to shared an interface between APSint and
+/// builtin primitive numeral types, while optimising for storage and
+/// allowing methods operating on primitive type to compile to fast code.
+template <unsigned Bits, bool Signed> class Integral {
+private:
+ template <unsigned OtherBits, bool OtherSigned> friend class Integral;
+
+ // The primitive representing the integral.
+ using T = typename Repr<Bits, Signed>::Type;
+ T V;
+
+ /// Primitive representing limits.
+ static const auto Min = std::numeric_limits<T>::min();
+ static const auto Max = std::numeric_limits<T>::max();
+
+ /// Construct an integral from anything that is convertible to storage.
+ template <typename T> explicit Integral(T V) : V(V) {}
+
+public:
+ /// Zero-initializes an integral.
+ Integral() : V(0) {}
+
+ /// Constructs an integral from another integral.
+ template <unsigned SrcBits, bool SrcSign>
+ explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}
+
+ /// Construct an integral from a value based on signedness.
+ explicit Integral(const APSInt &V)
+ : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
+
+ bool operator<(Integral RHS) const { return V < RHS.V; }
+ bool operator>(Integral RHS) const { return V > RHS.V; }
+ bool operator<=(Integral RHS) const { return V <= RHS.V; }
+ bool operator>=(Integral RHS) const { return V >= RHS.V; }
+ bool operator==(Integral RHS) const { return V == RHS.V; }
+ bool operator!=(Integral RHS) const { return V != RHS.V; }
+
+ bool operator>(unsigned RHS) const {
+ return V >= 0 && static_cast<unsigned>(V) > RHS;
+ }
+
+ Integral operator-() const { return Integral(-V); }
+ Integral operator~() const { return Integral(~V); }
+
+ template <unsigned DstBits, bool DstSign>
+ explicit operator Integral<DstBits, DstSign>() const {
+ return Integral<DstBits, DstSign>(V);
+ }
+
+ explicit operator unsigned() const { return V; }
+ explicit operator int64_t() const { return V; }
+ explicit operator uint64_t() const { return V; }
+
+ APSInt toAPSInt() const {
+ return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
+ }
+ APSInt toAPSInt(unsigned NumBits) const {
+ if (Signed)
+ return APSInt(toAPSInt().sextOrTrunc(NumBits), !Signed);
+ else
+ return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed);
+ }
+ APValue toAPValue() const { return APValue(toAPSInt()); }
+
+ Integral<Bits, false> toUnsigned() const {
+ return Integral<Bits, false>(*this);
+ }
+
+ constexpr static unsigned bitWidth() { return Bits; }
+
+ bool isZero() const { return !V; }
+
+ bool isMin() const { return *this == min(bitWidth()); }
+
+ bool isMinusOne() const { return Signed && V == T(-1); }
+
+ constexpr static bool isSigned() { return Signed; }
+
+ bool isNegative() const { return V < T(0); }
+ bool isPositive() const { return !isNegative(); }
+
+ ComparisonCategoryResult compare(const Integral &RHS) const {
+ return Compare(V, RHS.V);
+ }
+
+ unsigned countLeadingZeros() const { return llvm::countLeadingZeros<T>(V); }
+
+ Integral truncate(unsigned TruncBits) const {
+ if (TruncBits >= Bits)
+ return *this;
+ const T BitMask = (T(1) << T(TruncBits)) - 1;
+ const T SignBit = T(1) << (TruncBits - 1);
+ const T ExtMask = ~BitMask;
+ return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
+ }
+
+ void print(llvm::raw_ostream &OS) const { OS << V; }
+
+ static Integral min(unsigned NumBits) {
+ return Integral(Min);
+ }
+ static Integral max(unsigned NumBits) {
+ return Integral(Max);
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_integral<T>::value, Integral>::type
+ from(T Value) {
+ return Integral(Value);
+ }
+
+ template <unsigned SrcBits, bool SrcSign>
+ static typename std::enable_if<SrcBits != 0, Integral>::type
+ from(Integral<SrcBits, SrcSign> Value) {
+ return Integral(Value.V);
+ }
+
+ template <bool SrcSign> static Integral from(Integral<0, SrcSign> Value) {
+ if (SrcSign)
+ return Integral(Value.V.getSExtValue());
+ else
+ return Integral(Value.V.getZExtValue());
+ }
+
+ static Integral zero() { return from(0); }
+
+ template <typename T> static Integral from(T Value, unsigned NumBits) {
+ return Integral(Value);
+ }
+
+ static bool inRange(int64_t Value, unsigned NumBits) {
+ return CheckRange<T, Min, Max>(Value);
+ }
+
+ static bool increment(Integral A, Integral *R) {
+ return add(A, Integral(T(1)), A.bitWidth(), R);
+ }
+
+ static bool decrement(Integral A, Integral *R) {
+ return sub(A, Integral(T(1)), A.bitWidth(), R);
+ }
+
+ static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ return CheckAddUB(A.V, B.V, R->V);
+ }
+
+ static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ return CheckSubUB(A.V, B.V, R->V);
+ }
+
+ static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ return CheckMulUB(A.V, B.V, R->V);
+ }
+
+private:
+ template <typename T>
+ static typename std::enable_if<std::is_signed<T>::value, bool>::type
+ CheckAddUB(T A, T B, T &R) {
+ return llvm::AddOverflow<T>(A, B, R);
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+ CheckAddUB(T A, T B, T &R) {
+ R = A + B;
+ return false;
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_signed<T>::value, bool>::type
+ CheckSubUB(T A, T B, T &R) {
+ return llvm::SubOverflow<T>(A, B, R);
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+ CheckSubUB(T A, T B, T &R) {
+ R = A - B;
+ return false;
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_signed<T>::value, bool>::type
+ CheckMulUB(T A, T B, T &R) {
+ return llvm::MulOverflow<T>(A, B, R);
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+ CheckMulUB(T A, T B, T &R) {
+ R = A * B;
+ return false;
+ }
+
+ template <typename T, T Min, T Max>
+ static typename std::enable_if<std::is_signed<T>::value, bool>::type
+ CheckRange(int64_t V) {
+ return Min <= V && V <= Max;
+ }
+
+ template <typename T, T Min, T Max>
+ static typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+ CheckRange(int64_t V) {
+ return V >= 0 && static_cast<uint64_t>(V) <= Max;
+ }
+};
+
+template <unsigned Bits, bool Signed>
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
+ I.print(OS);
+ return OS;
+}
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Interp.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Interp.cpp
new file mode 100644
index 000000000000..1a8109cedf76
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Interp.cpp
@@ -0,0 +1,417 @@
+//===--- InterpState.cpp - Interpreter for the constexpr VM -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Interp.h"
+#include <limits>
+#include <vector>
+#include "Function.h"
+#include "InterpFrame.h"
+#include "InterpStack.h"
+#include "Opcode.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "State.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/APSInt.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+//===----------------------------------------------------------------------===//
+// Ret
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+static bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
+ S.CallStackDepth--;
+ const T &Ret = S.Stk.pop<T>();
+
+ assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
+ if (!S.checkingPotentialConstantExpression())
+ S.Current->popArgs();
+
+ if (InterpFrame *Caller = S.Current->Caller) {
+ PC = S.Current->getRetPC();
+ delete S.Current;
+ S.Current = Caller;
+ S.Stk.push<T>(Ret);
+ } else {
+ delete S.Current;
+ S.Current = nullptr;
+ if (!ReturnValue<T>(Ret, Result))
+ return false;
+ }
+ return true;
+}
+
+static bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
+ S.CallStackDepth--;
+
+ assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
+ if (!S.checkingPotentialConstantExpression())
+ S.Current->popArgs();
+
+ if (InterpFrame *Caller = S.Current->Caller) {
+ PC = S.Current->getRetPC();
+ delete S.Current;
+ S.Current = Caller;
+ } else {
+ delete S.Current;
+ S.Current = nullptr;
+ }
+ return true;
+}
+
+static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
+ llvm::report_fatal_error("Interpreter cannot return values");
+}
+
+//===----------------------------------------------------------------------===//
+// Jmp, Jt, Jf
+//===----------------------------------------------------------------------===//
+
+static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
+ PC += Offset;
+ return true;
+}
+
+static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
+ if (S.Stk.pop<bool>()) {
+ PC += Offset;
+ }
+ return true;
+}
+
+static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
+ if (!S.Stk.pop<bool>()) {
+ PC += Offset;
+ }
+ return true;
+}
+
+static bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ if (Ptr.isInitialized())
+ return true;
+ if (!S.checkingPotentialConstantExpression()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_access_uninit) << AK << false;
+ }
+ return false;
+}
+
+static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ if (Ptr.isActive())
+ return true;
+
+ // Get the inactive field descriptor.
+ const FieldDecl *InactiveField = Ptr.getField();
+
+ // Walk up the pointer chain to find the union which is not active.
+ Pointer U = Ptr.getBase();
+ while (!U.isActive()) {
+ U = U.getBase();
+ }
+
+ // Find the active field of the union.
+ Record *R = U.getRecord();
+ assert(R && R->isUnion() && "Not a union");
+ const FieldDecl *ActiveField = nullptr;
+ for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
+ const Pointer &Field = U.atField(R->getField(I)->Offset);
+ if (Field.isActive()) {
+ ActiveField = Field.getField();
+ break;
+ }
+ }
+
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
+ << AK << InactiveField << !ActiveField << ActiveField;
+ return false;
+}
+
+static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ if (auto ID = Ptr.getDeclID()) {
+ if (!Ptr.isStaticTemporary())
+ return true;
+
+ if (Ptr.getDeclDesc()->getType().isConstQualified())
+ return true;
+
+ if (S.P.getCurrentDecl() == ID)
+ return true;
+
+ const SourceInfo &E = S.Current->getSource(OpPC);
+ S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
+ S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
+ return false;
+ }
+ return true;
+}
+
+static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (auto ID = Ptr.getDeclID()) {
+ if (!Ptr.isStatic())
+ return true;
+
+ if (S.P.getCurrentDecl() == ID)
+ return true;
+
+ S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
+ return false;
+ }
+ return true;
+}
+
+namespace clang {
+namespace interp {
+
+bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!Ptr.isExtern())
+ return true;
+
+ if (!S.checkingPotentialConstantExpression()) {
+ auto *VD = Ptr.getDeclDesc()->asValueDecl();
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
+ S.Note(VD->getLocation(), diag::note_declared_at);
+ }
+ return false;
+}
+
+bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!Ptr.isUnknownSizeArray())
+ return true;
+ const SourceInfo &E = S.Current->getSource(OpPC);
+ S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
+ return false;
+}
+
+bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ const auto &Src = S.Current->getSource(OpPC);
+ if (Ptr.isZero()) {
+
+ if (Ptr.isField())
+ S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
+ else
+ S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
+
+ return false;
+ }
+
+ if (!Ptr.isLive()) {
+ bool IsTemp = Ptr.isTemporary();
+
+ S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
+
+ if (IsTemp)
+ S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
+ else
+ S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ CheckSubobjectKind CSK) {
+ if (!Ptr.isZero())
+ return true;
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK;
+ return false;
+}
+
+bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ if (!Ptr.isOnePastEnd())
+ return true;
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK;
+ return false;
+}
+
+bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ CheckSubobjectKind CSK) {
+ if (!Ptr.isElementPastEnd())
+ return true;
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
+ return false;
+}
+
+bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ assert(Ptr.isLive() && "Pointer is not live");
+ if (!Ptr.isConst()) {
+ return true;
+ }
+
+ const QualType Ty = Ptr.getType();
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
+ return false;
+}
+
+bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ assert(Ptr.isLive() && "Pointer is not live");
+ if (!Ptr.isMutable()) {
+ return true;
+ }
+
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ const FieldDecl *Field = Ptr.getField();
+ S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
+ S.Note(Field->getLocation(), diag::note_declared_at);
+ return false;
+}
+
+bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!CheckLive(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckActive(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckMutable(S, OpPC, Ptr))
+ return false;
+ return true;
+}
+
+bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!CheckLive(S, OpPC, Ptr, AK_Assign))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, AK_Assign))
+ return false;
+ if (!CheckGlobal(S, OpPC, Ptr))
+ return false;
+ if (!CheckConst(S, OpPC, Ptr))
+ return false;
+ return true;
+}
+
+bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
+ return false;
+ return true;
+}
+
+bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!CheckLive(S, OpPC, Ptr, AK_Assign))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, AK_Assign))
+ return false;
+ return true;
+}
+
+bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F) {
+ const SourceLocation &Loc = S.Current->getLocation(OpPC);
+
+ if (F->isVirtual()) {
+ if (!S.getLangOpts().CPlusPlus2a) {
+ S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
+ return false;
+ }
+ }
+
+ if (!F->isConstexpr()) {
+ if (S.getLangOpts().CPlusPlus11) {
+ const FunctionDecl *DiagDecl = F->getDecl();
+
+ // If this function is not constexpr because it is an inherited
+ // non-constexpr constructor, diagnose that directly.
+ auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
+ if (CD && CD->isInheritingConstructor()) {
+ auto *Inherited = CD->getInheritedConstructor().getConstructor();
+ if (!Inherited->isConstexpr())
+ DiagDecl = CD = Inherited;
+ }
+
+ // FIXME: If DiagDecl is an implicitly-declared special member function
+ // or an inheriting constructor, we should be much more explicit about why
+ // it's not constexpr.
+ if (CD && CD->isInheritingConstructor())
+ S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
+ << CD->getInheritedConstructor().getConstructor()->getParent();
+ else
+ S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
+ << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
+ S.Note(DiagDecl->getLocation(), diag::note_declared_at);
+ } else {
+ S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
+ if (!This.isZero())
+ return true;
+
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+
+ bool IsImplicit = false;
+ if (auto *E = dyn_cast_or_null<CXXThisExpr>(Loc.asExpr()))
+ IsImplicit = E->isImplicit();
+
+ if (S.getLangOpts().CPlusPlus11)
+ S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
+ else
+ S.FFDiag(Loc);
+
+ return false;
+}
+
+bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
+ if (!MD->isPure())
+ return true;
+ const SourceInfo &E = S.Current->getSource(OpPC);
+ S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
+ S.Note(MD->getLocation(), diag::note_declared_at);
+ return false;
+}
+bool Interpret(InterpState &S, APValue &Result) {
+ CodePtr PC = S.Current->getPC();
+
+ for (;;) {
+ auto Op = PC.read<Opcode>();
+ CodePtr OpPC = PC;
+
+ switch (Op) {
+#define GET_INTERP
+#include "Opcodes.inc"
+#undef GET_INTERP
+ }
+ }
+}
+
+} // namespace interp
+} // namespace clang
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Interp.h b/contrib/llvm-project/clang/lib/AST/Interp/Interp.h
new file mode 100644
index 000000000000..c12caa639da7
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Interp.h
@@ -0,0 +1,957 @@
+//===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Definition of the interpreter state and entry point.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
+#define LLVM_CLANG_AST_INTERP_INTERP_H
+
+#include <limits>
+#include <vector>
+#include "Function.h"
+#include "InterpFrame.h"
+#include "InterpStack.h"
+#include "InterpState.h"
+#include "Opcode.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "State.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/Expr.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/Endian.h"
+
+namespace clang {
+namespace interp {
+
+using APInt = llvm::APInt;
+using APSInt = llvm::APSInt;
+
+/// Convers a value to an APValue.
+template <typename T> bool ReturnValue(const T &V, APValue &R) {
+ R = V.toAPValue();
+ return true;
+}
+
+/// Checks if the variable has externally defined storage.
+bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if the array is offsetable.
+bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a pointer is live and accesible.
+bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK);
+/// Checks if a pointer is null.
+bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ CheckSubobjectKind CSK);
+
+/// Checks if a pointer is in range.
+bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK);
+
+/// Checks if a field from which a pointer is going to be derived is valid.
+bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ CheckSubobjectKind CSK);
+
+/// Checks if a pointer points to const storage.
+bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a pointer points to a mutable field.
+bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a value can be loaded from a block.
+bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a value can be stored in a block.
+bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a method can be invoked on an object.
+bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a value can be initialized.
+bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a method can be called.
+bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F);
+
+/// Checks the 'this' pointer.
+bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
+
+/// Checks if a method is pure virtual.
+bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
+
+template <typename T> inline bool IsTrue(const T &V) { return !V.isZero(); }
+
+//===----------------------------------------------------------------------===//
+// Add, Sub, Mul
+//===----------------------------------------------------------------------===//
+
+template <typename T, bool (*OpFW)(T, T, unsigned, T *),
+ template <typename U> class OpAP>
+bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
+ const T &RHS) {
+ // Fast path - add the numbers with fixed width.
+ T Result;
+ if (!OpFW(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+
+ // If for some reason evaluation continues, use the truncated results.
+ S.Stk.push<T>(Result);
+
+ // Slow path - compute the result using another bit of precision.
+ APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
+
+ // Report undefined behaviour, stopping if required.
+ const Expr *E = S.Current->getExpr(OpPC);
+ QualType Type = E->getType();
+ if (S.checkingForUndefinedBehavior()) {
+ auto Trunc = Value.trunc(Result.bitWidth()).toString(10);
+ auto Loc = E->getExprLoc();
+ S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
+ return true;
+ } else {
+ S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
+ return S.noteUndefinedBehavior();
+ }
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Add(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+ const unsigned Bits = RHS.bitWidth() + 1;
+ return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Sub(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+ const unsigned Bits = RHS.bitWidth() + 1;
+ return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Mul(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+ const unsigned Bits = RHS.bitWidth() * 2;
+ return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
+}
+
+//===----------------------------------------------------------------------===//
+// EQ, NE, GT, GE, LT, LE
+//===----------------------------------------------------------------------===//
+
+using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
+
+template <typename T>
+bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
+ using BoolT = PrimConv<PT_Bool>::T;
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+ S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
+ return true;
+}
+
+template <typename T>
+bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
+ return CmpHelper<T>(S, OpPC, Fn);
+}
+
+template <>
+inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
+ using BoolT = PrimConv<PT_Bool>::T;
+ const Pointer &RHS = S.Stk.pop<Pointer>();
+ const Pointer &LHS = S.Stk.pop<Pointer>();
+
+ if (!Pointer::hasSameBase(LHS, RHS)) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ } else {
+ unsigned VL = LHS.getByteOffset();
+ unsigned VR = RHS.getByteOffset();
+ S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
+ return true;
+ }
+}
+
+template <>
+inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
+ using BoolT = PrimConv<PT_Bool>::T;
+ const Pointer &RHS = S.Stk.pop<Pointer>();
+ const Pointer &LHS = S.Stk.pop<Pointer>();
+
+ if (LHS.isZero() && RHS.isZero()) {
+ S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
+ return true;
+ }
+
+ if (!Pointer::hasSameBase(LHS, RHS)) {
+ S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
+ return true;
+ } else {
+ unsigned VL = LHS.getByteOffset();
+ unsigned VR = RHS.getByteOffset();
+ S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
+ return true;
+ }
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool EQ(InterpState &S, CodePtr OpPC) {
+ return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R == ComparisonCategoryResult::Equal;
+ });
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool NE(InterpState &S, CodePtr OpPC) {
+ return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R != ComparisonCategoryResult::Equal;
+ });
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool LT(InterpState &S, CodePtr OpPC) {
+ return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R == ComparisonCategoryResult::Less;
+ });
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool LE(InterpState &S, CodePtr OpPC) {
+ return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R == ComparisonCategoryResult::Less ||
+ R == ComparisonCategoryResult::Equal;
+ });
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GT(InterpState &S, CodePtr OpPC) {
+ return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R == ComparisonCategoryResult::Greater;
+ });
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GE(InterpState &S, CodePtr OpPC) {
+ return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R == ComparisonCategoryResult::Greater ||
+ R == ComparisonCategoryResult::Equal;
+ });
+}
+
+//===----------------------------------------------------------------------===//
+// InRange
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InRange(InterpState &S, CodePtr OpPC) {
+ const T RHS = S.Stk.pop<T>();
+ const T LHS = S.Stk.pop<T>();
+ const T Value = S.Stk.pop<T>();
+
+ S.Stk.push<bool>(LHS <= Value && Value <= RHS);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Dup, Pop, Test
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Dup(InterpState &S, CodePtr OpPC) {
+ S.Stk.push<T>(S.Stk.peek<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Pop(InterpState &S, CodePtr OpPC) {
+ S.Stk.pop<T>();
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Const
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
+ S.Stk.push<T>(Arg);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Get/Set Local/Param/Global/This
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Stk.push<T>(S.Current->getLocal<T>(I));
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Current->setLocal<T>(I, S.Stk.pop<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression()) {
+ return false;
+ }
+ S.Stk.push<T>(S.Current->getParam<T>(I));
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Current->setParam<T>(I, S.Stk.pop<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ const Pointer &Obj = S.Stk.peek<Pointer>();
+ if (!CheckNull(S, OpPC, Obj, CSK_Field))
+ return false;
+ if (!CheckRange(S, OpPC, Obj, CSK_Field))
+ return false;
+ const Pointer &Field = Obj.atField(I);
+ if (!CheckLoad(S, OpPC, Field))
+ return false;
+ S.Stk.push<T>(Field.deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Obj = S.Stk.peek<Pointer>();
+ if (!CheckNull(S, OpPC, Obj, CSK_Field))
+ return false;
+ if (!CheckRange(S, OpPC, Obj, CSK_Field))
+ return false;
+ const Pointer &Field = Obj.atField(I);
+ if (!CheckStore(S, OpPC, Field))
+ return false;
+ Field.deref<T>() = Value;
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
+ const Pointer &Obj = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Obj, CSK_Field))
+ return false;
+ if (!CheckRange(S, OpPC, Obj, CSK_Field))
+ return false;
+ const Pointer &Field = Obj.atField(I);
+ if (!CheckLoad(S, OpPC, Field))
+ return false;
+ S.Stk.push<T>(Field.deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ const Pointer &Field = This.atField(I);
+ if (!CheckLoad(S, OpPC, Field))
+ return false;
+ S.Stk.push<T>(Field.deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ const Pointer &Field = This.atField(I);
+ if (!CheckStore(S, OpPC, Field))
+ return false;
+ Field.deref<T>() = Value;
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ auto *B = S.P.getGlobal(I);
+ if (B->isExtern())
+ return false;
+ S.Stk.push<T>(B->deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ // TODO: emit warning.
+ return false;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ const Pointer &Field = This.atField(I);
+ Field.deref<T>() = S.Stk.pop<T>();
+ Field.initialize();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ const Pointer &Field = This.atField(F->Offset);
+ const auto &Value = S.Stk.pop<T>();
+ Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
+ Field.initialize();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ const Pointer &Field = This.atField(I);
+ Field.deref<T>() = S.Stk.pop<T>();
+ Field.activate();
+ Field.initialize();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Field = S.Stk.pop<Pointer>().atField(I);
+ Field.deref<T>() = Value;
+ Field.activate();
+ Field.initialize();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
+ Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
+ Field.activate();
+ Field.initialize();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ const Pointer &Field = Ptr.atField(I);
+ Field.deref<T>() = Value;
+ Field.activate();
+ Field.initialize();
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// GetPtr Local/Param/Global/Field/This
+//===----------------------------------------------------------------------===//
+
+inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
+ return true;
+}
+
+inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression()) {
+ return false;
+ }
+ S.Stk.push<Pointer>(S.Current->getParamPointer(I));
+ return true;
+}
+
+inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
+ return true;
+}
+
+inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Ptr, CSK_Field))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, CSK_Field))
+ return false;
+ S.Stk.push<Pointer>(Ptr.atField(Off));
+ return true;
+}
+
+inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ S.Stk.push<Pointer>(This.atField(Off));
+ return true;
+}
+
+inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Ptr, CSK_Field))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, CSK_Field))
+ return false;
+ Pointer Field = Ptr.atField(Off);
+ Ptr.deactivate();
+ Field.activate();
+ S.Stk.push<Pointer>(std::move(Field));
+ return true;
+}
+
+inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ Pointer Field = This.atField(Off);
+ This.deactivate();
+ Field.activate();
+ S.Stk.push<Pointer>(std::move(Field));
+ return true;
+}
+
+inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Ptr, CSK_Base))
+ return false;
+ S.Stk.push<Pointer>(Ptr.atField(Off));
+ return true;
+}
+
+inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ S.Stk.push<Pointer>(This.atField(Off));
+ return true;
+}
+
+inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
+ const Pointer &Ptr) {
+ Pointer Base = Ptr;
+ while (Base.isBaseClass())
+ Base = Base.getBase();
+
+ auto *Field = Base.getRecord()->getVirtualBase(Decl);
+ S.Stk.push<Pointer>(Base.atField(Field->Offset));
+ return true;
+}
+
+inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Ptr, CSK_Base))
+ return false;
+ return VirtBaseHelper(S, OpPC, D, Ptr);
+}
+
+inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
+ const RecordDecl *D) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
+}
+
+//===----------------------------------------------------------------------===//
+// Load, Store, Init
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Load(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ if (!CheckLoad(S, OpPC, Ptr))
+ return false;
+ S.Stk.push<T>(Ptr.deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool LoadPop(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckLoad(S, OpPC, Ptr))
+ return false;
+ S.Stk.push<T>(Ptr.deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Store(InterpState &S, CodePtr OpPC) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ if (!CheckStore(S, OpPC, Ptr))
+ return false;
+ Ptr.deref<T>() = Value;
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool StorePop(InterpState &S, CodePtr OpPC) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckStore(S, OpPC, Ptr))
+ return false;
+ Ptr.deref<T>() = Value;
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool StoreBitField(InterpState &S, CodePtr OpPC) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ if (!CheckStore(S, OpPC, Ptr))
+ return false;
+ if (auto *FD = Ptr.getField()) {
+ Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
+ } else {
+ Ptr.deref<T>() = Value;
+ }
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckStore(S, OpPC, Ptr))
+ return false;
+ if (auto *FD = Ptr.getField()) {
+ Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
+ } else {
+ Ptr.deref<T>() = Value;
+ }
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitPop(InterpState &S, CodePtr OpPC) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckInit(S, OpPC, Ptr))
+ return false;
+ Ptr.initialize();
+ new (&Ptr.deref<T>()) T(Value);
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
+ if (!CheckInit(S, OpPC, Ptr))
+ return false;
+ Ptr.initialize();
+ new (&Ptr.deref<T>()) T(Value);
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
+ if (!CheckInit(S, OpPC, Ptr))
+ return false;
+ Ptr.initialize();
+ new (&Ptr.deref<T>()) T(Value);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// AddOffset, SubOffset
+//===----------------------------------------------------------------------===//
+
+template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
+ // Fetch the pointer and the offset.
+ const T &Offset = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
+ return false;
+
+ // Get a version of the index comparable to the type.
+ T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
+ // A zero offset does not change the pointer, but in the case of an array
+ // it has to be adjusted to point to the first element instead of the array.
+ if (Offset.isZero()) {
+ S.Stk.push<Pointer>(Index.isZero() ? Ptr.atIndex(0) : Ptr);
+ return true;
+ }
+ // Arrays of unknown bounds cannot have pointers into them.
+ if (!CheckArray(S, OpPC, Ptr))
+ return false;
+
+ // Compute the largest index into the array.
+ unsigned MaxIndex = Ptr.getNumElems();
+
+ // Helper to report an invalid offset, computed as APSInt.
+ auto InvalidOffset = [&]() {
+ const unsigned Bits = Offset.bitWidth();
+ APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
+ APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
+ APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset);
+ S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
+ << NewIndex
+ << /*array*/ static_cast<int>(!Ptr.inArray())
+ << static_cast<unsigned>(MaxIndex);
+ return false;
+ };
+
+ // If the new offset would be negative, bail out.
+ if (Add && Offset.isNegative() && (Offset.isMin() || -Offset > Index))
+ return InvalidOffset();
+ if (!Add && Offset.isPositive() && Index < Offset)
+ return InvalidOffset();
+
+ // If the new offset would be out of bounds, bail out.
+ unsigned MaxOffset = MaxIndex - Ptr.getIndex();
+ if (Add && Offset.isPositive() && Offset > MaxOffset)
+ return InvalidOffset();
+ if (!Add && Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
+ return InvalidOffset();
+
+ // Offset is valid - compute it on unsigned.
+ int64_t WideIndex = static_cast<int64_t>(Index);
+ int64_t WideOffset = static_cast<int64_t>(Offset);
+ int64_t Result = Add ? (WideIndex + WideOffset) : (WideIndex - WideOffset);
+ S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool AddOffset(InterpState &S, CodePtr OpPC) {
+ return OffsetHelper<T, true>(S, OpPC);
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SubOffset(InterpState &S, CodePtr OpPC) {
+ return OffsetHelper<T, false>(S, OpPC);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Destroy
+//===----------------------------------------------------------------------===//
+
+inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Current->destroy(I);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Cast, CastFP
+//===----------------------------------------------------------------------===//
+
+template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
+ using T = typename PrimConv<TIn>::T;
+ using U = typename PrimConv<TOut>::T;
+ S.Stk.push<U>(U::from(S.Stk.pop<T>()));
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Zero, Nullptr
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Zero(InterpState &S, CodePtr OpPC) {
+ S.Stk.push<T>(T::zero());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+inline bool Null(InterpState &S, CodePtr OpPC) {
+ S.Stk.push<T>();
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// This, ImplicitThis
+//===----------------------------------------------------------------------===//
+
+inline bool This(InterpState &S, CodePtr OpPC) {
+ // Cannot read 'this' in this mode.
+ if (S.checkingPotentialConstantExpression()) {
+ return false;
+ }
+
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+
+ S.Stk.push<Pointer>(This);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Shr, Shl
+//===----------------------------------------------------------------------===//
+
+template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T>
+unsigned Trunc(InterpState &S, CodePtr OpPC, unsigned Bits, const T &V) {
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of
+ // the shifted type.
+ if (Bits > 1 && V >= T::from(Bits, V.bitWidth())) {
+ const Expr *E = S.Current->getExpr(OpPC);
+ const APSInt Val = V.toAPSInt();
+ QualType Ty = E->getType();
+ S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
+ return Bits;
+ } else {
+ return static_cast<unsigned>(V);
+ }
+}
+
+template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
+inline bool ShiftRight(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
+ if (RHS >= V.bitWidth()) {
+ S.Stk.push<T>(T::from(0, V.bitWidth()));
+ } else {
+ S.Stk.push<T>(T::from(V >> RHS, V.bitWidth()));
+ }
+ return true;
+}
+
+template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
+inline bool ShiftLeft(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
+ if (V.isSigned() && !S.getLangOpts().CPlusPlus2a) {
+ // C++11 [expr.shift]p2: A signed left shift must have a non-negative
+ // operand, and must not overflow the corresponding unsigned type.
+ // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
+ // E1 x 2^E2 module 2^N.
+ if (V.isNegative()) {
+ const Expr *E = S.Current->getExpr(OpPC);
+ S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << V.toAPSInt();
+ } else if (V.countLeadingZeros() < RHS) {
+ S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_discards);
+ }
+ }
+
+ if (V.bitWidth() == 1) {
+ S.Stk.push<T>(V);
+ } else if (RHS >= V.bitWidth()) {
+ S.Stk.push<T>(T::from(0, V.bitWidth()));
+ } else {
+ S.Stk.push<T>(T::from(V.toUnsigned() << RHS, V.bitWidth()));
+ }
+ return true;
+}
+
+template <PrimType TL, PrimType TR>
+inline bool Shr(InterpState &S, CodePtr OpPC) {
+ const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
+ const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
+ const unsigned Bits = LHS.bitWidth();
+
+ if (RHS.isSigned() && RHS.isNegative()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
+ return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
+ } else {
+ return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
+ }
+}
+
+template <PrimType TL, PrimType TR>
+inline bool Shl(InterpState &S, CodePtr OpPC) {
+ const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
+ const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
+ const unsigned Bits = LHS.bitWidth();
+
+ if (RHS.isSigned() && RHS.isNegative()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
+ return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
+ } else {
+ return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// NoRet
+//===----------------------------------------------------------------------===//
+
+inline bool NoRet(InterpState &S, CodePtr OpPC) {
+ SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
+ S.FFDiag(EndLoc, diag::note_constexpr_no_return);
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// NarrowPtr, ExpandPtr
+//===----------------------------------------------------------------------===//
+
+inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ S.Stk.push<Pointer>(Ptr.narrow());
+ return true;
+}
+
+inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ S.Stk.push<Pointer>(Ptr.expand());
+ return true;
+}
+
+/// Interpreter entry point.
+bool Interpret(InterpState &S, APValue &Result);
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/InterpFrame.cpp b/contrib/llvm-project/clang/lib/AST/Interp/InterpFrame.cpp
new file mode 100644
index 000000000000..9d01bf0333fe
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/InterpFrame.cpp
@@ -0,0 +1,193 @@
+//===--- InterpFrame.cpp - Call Frame implementation for the VM -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "InterpFrame.h"
+#include "Function.h"
+#include "Interp.h"
+#include "InterpStack.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+InterpFrame::InterpFrame(InterpState &S, Function *Func, InterpFrame *Caller,
+ CodePtr RetPC, Pointer &&This)
+ : Caller(Caller), S(S), Func(Func), This(std::move(This)), RetPC(RetPC),
+ ArgSize(Func ? Func->getArgSize() : 0),
+ Args(static_cast<char *>(S.Stk.top())), FrameOffset(S.Stk.size()) {
+ if (Func) {
+ if (unsigned FrameSize = Func->getFrameSize()) {
+ Locals = std::make_unique<char[]>(FrameSize);
+ for (auto &Scope : Func->scopes()) {
+ for (auto &Local : Scope.locals()) {
+ Block *B = new (localBlock(Local.Offset)) Block(Local.Desc);
+ B->invokeCtor();
+ }
+ }
+ }
+ }
+}
+
+InterpFrame::~InterpFrame() {
+ if (Func && Func->isConstructor() && This.isBaseClass())
+ This.initialize();
+ for (auto &Param : Params)
+ S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
+}
+
+void InterpFrame::destroy(unsigned Idx) {
+ for (auto &Local : Func->getScope(Idx).locals()) {
+ S.deallocate(reinterpret_cast<Block *>(localBlock(Local.Offset)));
+ }
+}
+
+void InterpFrame::popArgs() {
+ for (PrimType Ty : Func->args_reverse())
+ TYPE_SWITCH(Ty, S.Stk.discard<T>());
+}
+
+template <typename T>
+static void print(llvm::raw_ostream &OS, const T &V, ASTContext &, QualType) {
+ OS << V;
+}
+
+template <>
+void print(llvm::raw_ostream &OS, const Pointer &P, ASTContext &Ctx,
+ QualType Ty) {
+ if (P.isZero()) {
+ OS << "nullptr";
+ return;
+ }
+
+ auto printDesc = [&OS, &Ctx](Descriptor *Desc) {
+ if (auto *D = Desc->asDecl()) {
+ // Subfields or named values.
+ if (auto *VD = dyn_cast<ValueDecl>(D)) {
+ OS << *VD;
+ return;
+ }
+ // Base classes.
+ if (isa<RecordDecl>(D)) {
+ return;
+ }
+ }
+ // Temporary expression.
+ if (auto *E = Desc->asExpr()) {
+ E->printPretty(OS, nullptr, Ctx.getPrintingPolicy());
+ return;
+ }
+ llvm_unreachable("Invalid descriptor type");
+ };
+
+ if (!Ty->isReferenceType())
+ OS << "&";
+ llvm::SmallVector<Pointer, 2> Levels;
+ for (Pointer F = P; !F.isRoot(); ) {
+ Levels.push_back(F);
+ F = F.isArrayElement() ? F.getArray().expand() : F.getBase();
+ }
+
+ printDesc(P.getDeclDesc());
+ for (auto It = Levels.rbegin(); It != Levels.rend(); ++It) {
+ if (It->inArray()) {
+ OS << "[" << It->expand().getIndex() << "]";
+ continue;
+ }
+ if (auto Index = It->getIndex()) {
+ OS << " + " << Index;
+ continue;
+ }
+ OS << ".";
+ printDesc(It->getFieldDesc());
+ }
+}
+
+void InterpFrame::describe(llvm::raw_ostream &OS) {
+ const FunctionDecl *F = getCallee();
+ auto *M = dyn_cast<CXXMethodDecl>(F);
+ if (M && M->isInstance() && !isa<CXXConstructorDecl>(F)) {
+ print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent()));
+ OS << "->";
+ }
+ OS << *F << "(";
+ unsigned Off = Func->hasRVO() ? primSize(PT_Ptr) : 0;
+ for (unsigned I = 0, N = F->getNumParams(); I < N; ++I) {
+ QualType Ty = F->getParamDecl(I)->getType();
+
+ PrimType PrimTy;
+ if (llvm::Optional<PrimType> T = S.Ctx.classify(Ty)) {
+ PrimTy = *T;
+ } else {
+ PrimTy = PT_Ptr;
+ }
+
+ TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getCtx(), Ty));
+ Off += align(primSize(PrimTy));
+ if (I + 1 != N)
+ OS << ", ";
+ }
+ OS << ")";
+}
+
+Frame *InterpFrame::getCaller() const {
+ if (Caller->Caller)
+ return Caller;
+ return S.getSplitFrame();
+}
+
+SourceLocation InterpFrame::getCallLocation() const {
+ if (!Caller->Func)
+ return S.getLocation(nullptr, {});
+ return S.getLocation(Caller->Func, RetPC - sizeof(uintptr_t));
+}
+
+const FunctionDecl *InterpFrame::getCallee() const {
+ return Func->getDecl();
+}
+
+Pointer InterpFrame::getLocalPointer(unsigned Offset) {
+ assert(Offset < Func->getFrameSize() && "Invalid local offset.");
+ return Pointer(
+ reinterpret_cast<Block *>(Locals.get() + Offset - sizeof(Block)));
+}
+
+Pointer InterpFrame::getParamPointer(unsigned Off) {
+ // Return the block if it was created previously.
+ auto Pt = Params.find(Off);
+ if (Pt != Params.end()) {
+ return Pointer(reinterpret_cast<Block *>(Pt->second.get()));
+ }
+
+ // Allocate memory to store the parameter and the block metadata.
+ const auto &Desc = Func->getParamDescriptor(Off);
+ size_t BlockSize = sizeof(Block) + Desc.second->getAllocSize();
+ auto Memory = std::make_unique<char[]>(BlockSize);
+ auto *B = new (Memory.get()) Block(Desc.second);
+
+ // Copy the initial value.
+ TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef<T>(Off)));
+
+ // Record the param.
+ Params.insert({Off, std::move(Memory)});
+ return Pointer(B);
+}
+
+SourceInfo InterpFrame::getSource(CodePtr PC) const {
+ return S.getSource(Func, PC);
+}
+
+const Expr *InterpFrame::getExpr(CodePtr PC) const {
+ return S.getExpr(Func, PC);
+}
+
+SourceLocation InterpFrame::getLocation(CodePtr PC) const {
+ return S.getLocation(Func, PC);
+}
+
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/InterpFrame.h b/contrib/llvm-project/clang/lib/AST/Interp/InterpFrame.h
new file mode 100644
index 000000000000..b8391b0bcf92
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/InterpFrame.h
@@ -0,0 +1,153 @@
+//===--- InterpFrame.h - Call Frame implementation for the VM ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the class storing information about stack frames in the interpreter.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTERPFRAME_H
+#define LLVM_CLANG_AST_INTERP_INTERPFRAME_H
+
+#include "Frame.h"
+#include "Pointer.h"
+#include "Program.h"
+#include "State.h"
+#include <cstdint>
+#include <vector>
+
+namespace clang {
+namespace interp {
+class Function;
+class InterpState;
+
+/// Frame storing local variables.
+class InterpFrame final : public Frame {
+public:
+ /// The frame of the previous function.
+ InterpFrame *Caller;
+
+ /// Creates a new frame for a method call.
+ InterpFrame(InterpState &S, Function *Func, InterpFrame *Caller,
+ CodePtr RetPC, Pointer &&This);
+
+ /// Destroys the frame, killing all live pointers to stack slots.
+ ~InterpFrame();
+
+ /// Invokes the destructors for a scope.
+ void destroy(unsigned Idx);
+
+ /// Pops the arguments off the stack.
+ void popArgs();
+
+ /// Describes the frame with arguments for diagnostic purposes.
+ void describe(llvm::raw_ostream &OS);
+
+ /// Returns the parent frame object.
+ Frame *getCaller() const;
+
+ /// Returns the location of the call to the frame.
+ SourceLocation getCallLocation() const;
+
+ /// Returns the caller.
+ const FunctionDecl *getCallee() const;
+
+ /// Returns the current function.
+ Function *getFunction() const { return Func; }
+
+ /// Returns the offset on the stack at which the frame starts.
+ size_t getFrameOffset() const { return FrameOffset; }
+
+ /// Returns the value of a local variable.
+ template <typename T> const T &getLocal(unsigned Offset) {
+ return localRef<T>(Offset);
+ }
+
+ /// Mutates a local variable.
+ template <typename T> void setLocal(unsigned Offset, const T &Value) {
+ localRef<T>(Offset) = Value;
+ }
+
+ /// Returns a pointer to a local variables.
+ Pointer getLocalPointer(unsigned Offset);
+
+ /// Returns the value of an argument.
+ template <typename T> const T &getParam(unsigned Offset) {
+ auto Pt = Params.find(Offset);
+ if (Pt == Params.end()) {
+ return stackRef<T>(Offset);
+ } else {
+ return Pointer(reinterpret_cast<Block *>(Pt->second.get())).deref<T>();
+ }
+ }
+
+ /// Mutates a local copy of a parameter.
+ template <typename T> void setParam(unsigned Offset, const T &Value) {
+ getParamPointer(Offset).deref<T>() = Value;
+ }
+
+ /// Returns a pointer to an argument - lazily creates a block.
+ Pointer getParamPointer(unsigned Offset);
+
+ /// Returns the 'this' pointer.
+ const Pointer &getThis() const { return This; }
+
+ /// Checks if the frame is a root frame - return should quit the interpreter.
+ bool isRoot() const { return !Func; }
+
+ /// Returns the PC of the frame's code start.
+ CodePtr getPC() const { return Func->getCodeBegin(); }
+
+ /// Returns the return address of the frame.
+ CodePtr getRetPC() const { return RetPC; }
+
+ /// Map a location to a source.
+ virtual SourceInfo getSource(CodePtr PC) const;
+ const Expr *getExpr(CodePtr PC) const;
+ SourceLocation getLocation(CodePtr PC) const;
+
+private:
+ /// Returns an original argument from the stack.
+ template <typename T> const T &stackRef(unsigned Offset) {
+ return *reinterpret_cast<const T *>(Args - ArgSize + Offset);
+ }
+
+ /// Returns an offset to a local.
+ template <typename T> T &localRef(unsigned Offset) {
+ return *reinterpret_cast<T *>(Locals.get() + Offset);
+ }
+
+ /// Returns a pointer to a local's block.
+ void *localBlock(unsigned Offset) {
+ return Locals.get() + Offset - sizeof(Block);
+ }
+
+private:
+ /// Reference to the interpreter state.
+ InterpState &S;
+ /// Reference to the function being executed.
+ Function *Func;
+ /// Current object pointer for methods.
+ Pointer This;
+ /// Return address.
+ CodePtr RetPC;
+ /// The size of all the arguments.
+ const unsigned ArgSize;
+ /// Pointer to the arguments in the callee's frame.
+ char *Args = nullptr;
+ /// Fixed, initial storage for known local variables.
+ std::unique_ptr<char[]> Locals;
+ /// Offset on the stack at entry.
+ const size_t FrameOffset;
+ /// Mapping from arg offsets to their argument blocks.
+ llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Params;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/InterpStack.cpp b/contrib/llvm-project/clang/lib/AST/Interp/InterpStack.cpp
new file mode 100644
index 000000000000..5c803f3d9424
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/InterpStack.cpp
@@ -0,0 +1,78 @@
+//===--- InterpStack.cpp - Stack implementation for the VM ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cassert>
+#include <cstdlib>
+#include "InterpStack.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+InterpStack::~InterpStack() {
+ clear();
+}
+
+void InterpStack::clear() {
+ if (Chunk && Chunk->Next)
+ free(Chunk->Next);
+ if (Chunk)
+ free(Chunk);
+ Chunk = nullptr;
+ StackSize = 0;
+}
+
+void *InterpStack::grow(size_t Size) {
+ assert(Size < ChunkSize - sizeof(StackChunk) && "Object too large");
+
+ if (!Chunk || sizeof(StackChunk) + Chunk->size() + Size > ChunkSize) {
+ if (Chunk && Chunk->Next) {
+ Chunk = Chunk->Next;
+ } else {
+ StackChunk *Next = new (malloc(ChunkSize)) StackChunk(Chunk);
+ if (Chunk)
+ Chunk->Next = Next;
+ Chunk = Next;
+ }
+ }
+
+ auto *Object = reinterpret_cast<void *>(Chunk->End);
+ Chunk->End += Size;
+ StackSize += Size;
+ return Object;
+}
+
+void *InterpStack::peek(size_t Size) {
+ assert(Chunk && "Stack is empty!");
+
+ StackChunk *Ptr = Chunk;
+ while (Size > Ptr->size()) {
+ Size -= Ptr->size();
+ Ptr = Ptr->Prev;
+ assert(Ptr && "Offset too large");
+ }
+
+ return reinterpret_cast<void *>(Ptr->End - Size);
+}
+
+void InterpStack::shrink(size_t Size) {
+ assert(Chunk && "Chunk is empty!");
+
+ while (Size > Chunk->size()) {
+ Size -= Chunk->size();
+ if (Chunk->Next) {
+ free(Chunk->Next);
+ Chunk->Next = nullptr;
+ }
+ Chunk->End = Chunk->start();
+ Chunk = Chunk->Prev;
+ assert(Chunk && "Offset too large");
+ }
+
+ Chunk->End -= Size;
+ StackSize -= Size;
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/InterpStack.h b/contrib/llvm-project/clang/lib/AST/Interp/InterpStack.h
new file mode 100644
index 000000000000..127adb6b8eba
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/InterpStack.h
@@ -0,0 +1,113 @@
+//===--- InterpStack.h - Stack implementation for the VM --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the upwards-growing stack used by the interpreter.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H
+#define LLVM_CLANG_AST_INTERP_INTERPSTACK_H
+
+#include <memory>
+
+namespace clang {
+namespace interp {
+
+/// Stack frame storing temporaries and parameters.
+class InterpStack final {
+public:
+ InterpStack() {}
+
+ /// Destroys the stack, freeing up storage.
+ ~InterpStack();
+
+ /// Constructs a value in place on the top of the stack.
+ template <typename T, typename... Tys> void push(Tys &&... Args) {
+ new (grow(aligned_size<T>())) T(std::forward<Tys>(Args)...);
+ }
+
+ /// Returns the value from the top of the stack and removes it.
+ template <typename T> T pop() {
+ auto *Ptr = &peek<T>();
+ auto Value = std::move(*Ptr);
+ Ptr->~T();
+ shrink(aligned_size<T>());
+ return Value;
+ }
+
+ /// Discards the top value from the stack.
+ template <typename T> void discard() {
+ auto *Ptr = &peek<T>();
+ Ptr->~T();
+ shrink(aligned_size<T>());
+ }
+
+ /// Returns a reference to the value on the top of the stack.
+ template <typename T> T &peek() {
+ return *reinterpret_cast<T *>(peek(aligned_size<T>()));
+ }
+
+ /// Returns a pointer to the top object.
+ void *top() { return Chunk ? peek(0) : nullptr; }
+
+ /// Returns the size of the stack in bytes.
+ size_t size() const { return StackSize; }
+
+ /// Clears the stack without calling any destructors.
+ void clear();
+
+private:
+ /// All stack slots are aligned to the native pointer alignment for storage.
+ /// The size of an object is rounded up to a pointer alignment multiple.
+ template <typename T> constexpr size_t aligned_size() const {
+ constexpr size_t PtrAlign = alignof(void *);
+ return ((sizeof(T) + PtrAlign - 1) / PtrAlign) * PtrAlign;
+ }
+
+ /// Grows the stack to accomodate a value and returns a pointer to it.
+ void *grow(size_t Size);
+ /// Returns a pointer from the top of the stack.
+ void *peek(size_t Size);
+ /// Shrinks the stack.
+ void shrink(size_t Size);
+
+ /// Allocate stack space in 1Mb chunks.
+ static constexpr size_t ChunkSize = 1024 * 1024;
+
+ /// Metadata for each stack chunk.
+ ///
+ /// The stack is composed of a linked list of chunks. Whenever an allocation
+ /// is out of bounds, a new chunk is linked. When a chunk becomes empty,
+ /// it is not immediately freed: a chunk is deallocated only when the
+ /// predecessor becomes empty.
+ struct StackChunk {
+ StackChunk *Next;
+ StackChunk *Prev;
+ char *End;
+
+ StackChunk(StackChunk *Prev = nullptr)
+ : Next(nullptr), Prev(Prev), End(reinterpret_cast<char *>(this + 1)) {}
+
+ /// Returns the size of the chunk, minus the header.
+ size_t size() { return End - start(); }
+
+ /// Returns a pointer to the start of the data region.
+ char *start() { return reinterpret_cast<char *>(this + 1); }
+ };
+ static_assert(sizeof(StackChunk) < ChunkSize, "Invalid chunk size");
+
+ /// First chunk on the stack.
+ StackChunk *Chunk = nullptr;
+ /// Total size of the stack.
+ size_t StackSize = 0;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/InterpState.cpp b/contrib/llvm-project/clang/lib/AST/Interp/InterpState.cpp
new file mode 100644
index 000000000000..25684f3c0939
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/InterpState.cpp
@@ -0,0 +1,74 @@
+//===--- InterpState.cpp - Interpreter for the constexpr VM -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "InterpState.h"
+#include <limits>
+#include "Function.h"
+#include "InterpFrame.h"
+#include "InterpStack.h"
+#include "Opcode.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "State.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+using APSInt = llvm::APSInt;
+
+InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
+ Context &Ctx, SourceMapper *M)
+ : Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), Current(nullptr),
+ CallStackDepth(Parent.getCallStackDepth() + 1) {}
+
+InterpState::~InterpState() {
+ while (Current) {
+ InterpFrame *Next = Current->Caller;
+ delete Current;
+ Current = Next;
+ }
+
+ while (DeadBlocks) {
+ DeadBlock *Next = DeadBlocks->Next;
+ free(DeadBlocks);
+ DeadBlocks = Next;
+ }
+}
+
+Frame *InterpState::getCurrentFrame() {
+ if (Current && Current->Caller) {
+ return Current;
+ } else {
+ return Parent.getCurrentFrame();
+ }
+}
+
+bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) {
+ QualType Type = E->getType();
+ CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
+ return noteUndefinedBehavior();
+}
+
+void InterpState::deallocate(Block *B) {
+ Descriptor *Desc = B->getDescriptor();
+ if (B->hasPointers()) {
+ size_t Size = B->getSize();
+
+ // Allocate a new block, transferring over pointers.
+ char *Memory = reinterpret_cast<char *>(malloc(sizeof(DeadBlock) + Size));
+ auto *D = new (Memory) DeadBlock(DeadBlocks, B);
+
+ // Move data from one block to another.
+ if (Desc->MoveFn)
+ Desc->MoveFn(B, B->data(), D->data(), Desc);
+ } else {
+ // Free storage, if necessary.
+ if (Desc->DtorFn)
+ Desc->DtorFn(B, B->data(), Desc);
+ }
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/InterpState.h b/contrib/llvm-project/clang/lib/AST/Interp/InterpState.h
new file mode 100644
index 000000000000..c2209bbcbb92
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/InterpState.h
@@ -0,0 +1,112 @@
+//===--- InterpState.h - Interpreter state for the constexpr VM -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Definition of the interpreter state and entry point.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTERPSTATE_H
+#define LLVM_CLANG_AST_INTERP_INTERPSTATE_H
+
+#include "Context.h"
+#include "Function.h"
+#include "InterpStack.h"
+#include "State.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/OptionalDiagnostic.h"
+
+namespace clang {
+namespace interp {
+class Context;
+class Function;
+class InterpStack;
+class InterpFrame;
+class SourceMapper;
+
+/// Interpreter context.
+class InterpState final : public State, public SourceMapper {
+public:
+ InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
+ SourceMapper *M = nullptr);
+
+ ~InterpState();
+
+ // Stack frame accessors.
+ Frame *getSplitFrame() { return Parent.getCurrentFrame(); }
+ Frame *getCurrentFrame() override;
+ unsigned getCallStackDepth() override { return CallStackDepth; }
+ const Frame *getBottomFrame() const override {
+ return Parent.getBottomFrame();
+ }
+
+ // Acces objects from the walker context.
+ Expr::EvalStatus &getEvalStatus() const override {
+ return Parent.getEvalStatus();
+ }
+ ASTContext &getCtx() const override { return Parent.getCtx(); }
+
+ // Forward status checks and updates to the walker.
+ bool checkingForUndefinedBehavior() const override {
+ return Parent.checkingForUndefinedBehavior();
+ }
+ bool keepEvaluatingAfterFailure() const override {
+ return Parent.keepEvaluatingAfterFailure();
+ }
+ bool checkingPotentialConstantExpression() const override {
+ return Parent.checkingPotentialConstantExpression();
+ }
+ bool noteUndefinedBehavior() override {
+ return Parent.noteUndefinedBehavior();
+ }
+ bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); }
+ void setActiveDiagnostic(bool Flag) override {
+ Parent.setActiveDiagnostic(Flag);
+ }
+ void setFoldFailureDiagnostic(bool Flag) override {
+ Parent.setFoldFailureDiagnostic(Flag);
+ }
+ bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); }
+
+ /// Reports overflow and return true if evaluation should continue.
+ bool reportOverflow(const Expr *E, const llvm::APSInt &Value);
+
+ /// Deallocates a pointer.
+ void deallocate(Block *B);
+
+ /// Delegates source mapping to the mapper.
+ SourceInfo getSource(Function *F, CodePtr PC) const override {
+ return M ? M->getSource(F, PC) : F->getSource(PC);
+ }
+
+private:
+ /// AST Walker state.
+ State &Parent;
+ /// Dead block chain.
+ DeadBlock *DeadBlocks = nullptr;
+ /// Reference to the offset-source mapping.
+ SourceMapper *M;
+
+public:
+ /// Reference to the module containing all bytecode.
+ Program &P;
+ /// Temporary stack.
+ InterpStack &Stk;
+ /// Interpreter Context.
+ Context &Ctx;
+ /// The current frame.
+ InterpFrame *Current = nullptr;
+ /// Call stack depth.
+ unsigned CallStackDepth;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Opcode.h b/contrib/llvm-project/clang/lib/AST/Interp/Opcode.h
new file mode 100644
index 000000000000..d2daa1ea52ac
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Opcode.h
@@ -0,0 +1,30 @@
+//===--- Opcode.h - Opcodes for the constexpr VM ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines all opcodes executed by the VM and emitted by the compiler.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_OPCODE_H
+#define LLVM_CLANG_AST_INTERP_OPCODE_H
+
+#include <cstdint>
+
+namespace clang {
+namespace interp {
+
+enum Opcode : uint32_t {
+#define GET_OPCODE_NAMES
+#include "Opcodes.inc"
+#undef GET_OPCODE_NAMES
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Opcodes.td b/contrib/llvm-project/clang/lib/AST/Interp/Opcodes.td
new file mode 100644
index 000000000000..4aba5f5cd83c
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Opcodes.td
@@ -0,0 +1,422 @@
+//===--- Opcodes.td - Opcode defitions for the constexpr VM -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper file used to generate opcodes, the interpreter and the disassembler.
+//
+//===----------------------------------------------------------------------===//
+
+
+//===----------------------------------------------------------------------===//
+// Types evaluated by the interpreter.
+//===----------------------------------------------------------------------===//
+
+class Type;
+def Bool : Type;
+def Sint8 : Type;
+def Uint8 : Type;
+def Sint16 : Type;
+def Uint16 : Type;
+def Sint32 : Type;
+def Uint32 : Type;
+def Sint64 : Type;
+def Uint64 : Type;
+def Ptr : Type;
+
+//===----------------------------------------------------------------------===//
+// Types transferred to the interpreter.
+//===----------------------------------------------------------------------===//
+
+class ArgType { string Name = ?; }
+def ArgSint8 : ArgType { let Name = "int8_t"; }
+def ArgUint8 : ArgType { let Name = "uint8_t"; }
+def ArgSint16 : ArgType { let Name = "int16_t"; }
+def ArgUint16 : ArgType { let Name = "uint16_t"; }
+def ArgSint32 : ArgType { let Name = "int32_t"; }
+def ArgUint32 : ArgType { let Name = "uint32_t"; }
+def ArgSint64 : ArgType { let Name = "int64_t"; }
+def ArgUint64 : ArgType { let Name = "uint64_t"; }
+def ArgBool : ArgType { let Name = "bool"; }
+
+def ArgFunction : ArgType { let Name = "Function *"; }
+def ArgRecord : ArgType { let Name = "Record *"; }
+
+def ArgSema : ArgType { let Name = "const fltSemantics *"; }
+
+def ArgExpr : ArgType { let Name = "const Expr *"; }
+def ArgFloatingLiteral : ArgType { let Name = "const FloatingLiteral *"; }
+def ArgCXXMethodDecl : ArgType { let Name = "const CXXMethodDecl *"; }
+def ArgFunctionDecl : ArgType { let Name = "const FunctionDecl *"; }
+def ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; }
+def ArgCXXRecordDecl : ArgType { let Name = "const CXXRecordDecl *"; }
+def ArgValueDecl : ArgType { let Name = "const ValueDecl *"; }
+def ArgRecordField : ArgType { let Name = "const Record::Field *"; }
+
+//===----------------------------------------------------------------------===//
+// Classes of types intructions operate on.
+//===----------------------------------------------------------------------===//
+
+class TypeClass {
+ list<Type> Types;
+}
+
+def AluTypeClass : TypeClass {
+ let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
+ Uint32, Sint64, Uint64, Bool];
+}
+
+def PtrTypeClass : TypeClass {
+ let Types = [Ptr];
+}
+
+def AllTypeClass : TypeClass {
+ let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types);
+}
+
+def ComparableTypeClass : TypeClass {
+ let Types = !listconcat(AluTypeClass.Types, [Ptr]);
+}
+
+class SingletonTypeClass<Type Ty> : TypeClass {
+ let Types = [Ty];
+}
+
+//===----------------------------------------------------------------------===//
+// Record describing all opcodes.
+//===----------------------------------------------------------------------===//
+
+class Opcode {
+ list<TypeClass> Types = [];
+ list<ArgType> Args = [];
+ string Name = "";
+ bit CanReturn = 0;
+ bit ChangesPC = 0;
+ bit HasCustomLink = 0;
+ bit HasCustomEval = 0;
+ bit HasGroup = 0;
+}
+
+class AluOpcode : Opcode {
+ let Types = [AluTypeClass];
+ let HasGroup = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Jump opcodes
+//===----------------------------------------------------------------------===//
+
+class JumpOpcode : Opcode {
+ let Args = [ArgSint32];
+ let ChangesPC = 1;
+ let HasCustomEval = 1;
+}
+
+// [] -> []
+def Jmp : JumpOpcode;
+// [Bool] -> [], jumps if true.
+def Jt : JumpOpcode;
+// [Bool] -> [], jumps if false.
+def Jf : JumpOpcode;
+
+//===----------------------------------------------------------------------===//
+// Returns
+//===----------------------------------------------------------------------===//
+
+// [Value] -> []
+def Ret : Opcode {
+ let Types = [AllTypeClass];
+ let ChangesPC = 1;
+ let CanReturn = 1;
+ let HasGroup = 1;
+ let HasCustomEval = 1;
+}
+// [] -> []
+def RetVoid : Opcode {
+ let CanReturn = 1;
+ let ChangesPC = 1;
+ let HasCustomEval = 1;
+}
+// [Value] -> []
+def RetValue : Opcode {
+ let CanReturn = 1;
+ let ChangesPC = 1;
+ let HasCustomEval = 1;
+}
+// [] -> EXIT
+def NoRet : Opcode {}
+
+//===----------------------------------------------------------------------===//
+// Frame management
+//===----------------------------------------------------------------------===//
+
+// [] -> []
+def Destroy : Opcode {
+ let Args = [ArgUint32];
+ let HasCustomEval = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Constants
+//===----------------------------------------------------------------------===//
+
+class ConstOpcode<Type Ty, ArgType ArgTy> : Opcode {
+ let Types = [SingletonTypeClass<Ty>];
+ let Args = [ArgTy];
+ let Name = "Const";
+}
+
+// [] -> [Integer]
+def ConstSint8 : ConstOpcode<Sint8, ArgSint8>;
+def ConstUint8 : ConstOpcode<Uint8, ArgUint8>;
+def ConstSint16 : ConstOpcode<Sint16, ArgSint16>;
+def ConstUint16 : ConstOpcode<Uint16, ArgUint16>;
+def ConstSint32 : ConstOpcode<Sint32, ArgSint32>;
+def ConstUint32 : ConstOpcode<Uint32, ArgUint32>;
+def ConstSint64 : ConstOpcode<Sint64, ArgSint64>;
+def ConstUint64 : ConstOpcode<Uint64, ArgUint64>;
+def ConstBool : ConstOpcode<Bool, ArgBool>;
+
+// [] -> [Integer]
+def Zero : Opcode {
+ let Types = [AluTypeClass];
+}
+
+// [] -> [Pointer]
+def Null : Opcode {
+ let Types = [PtrTypeClass];
+}
+
+//===----------------------------------------------------------------------===//
+// Pointer generation
+//===----------------------------------------------------------------------===//
+
+// [] -> [Pointer]
+def GetPtrLocal : Opcode {
+ // Offset of local.
+ let Args = [ArgUint32];
+ bit HasCustomEval = 1;
+}
+// [] -> [Pointer]
+def GetPtrParam : Opcode {
+ // Offset of parameter.
+ let Args = [ArgUint32];
+}
+// [] -> [Pointer]
+def GetPtrGlobal : Opcode {
+ // Index of global.
+ let Args = [ArgUint32];
+}
+// [Pointer] -> [Pointer]
+def GetPtrField : Opcode {
+ // Offset of field.
+ let Args = [ArgUint32];
+}
+// [Pointer] -> [Pointer]
+def GetPtrActiveField : Opcode {
+ // Offset of field.
+ let Args = [ArgUint32];
+}
+// [] -> [Pointer]
+def GetPtrActiveThisField : Opcode {
+ // Offset of field.
+ let Args = [ArgUint32];
+}
+// [] -> [Pointer]
+def GetPtrThisField : Opcode {
+ // Offset of field.
+ let Args = [ArgUint32];
+}
+// [Pointer] -> [Pointer]
+def GetPtrBase : Opcode {
+ // Offset of field, which is a base.
+ let Args = [ArgUint32];
+}
+// [Pointer] -> [Pointer]
+def GetPtrVirtBase : Opcode {
+ // RecordDecl of base class.
+ let Args = [ArgRecordDecl];
+}
+// [] -> [Pointer]
+def GetPtrThisBase : Opcode {
+ // Offset of field, which is a base.
+ let Args = [ArgUint32];
+}
+// [] -> [Pointer]
+def GetPtrThisVirtBase : Opcode {
+ // RecordDecl of base class.
+ let Args = [ArgRecordDecl];
+}
+// [] -> [Pointer]
+def This : Opcode;
+
+// [Pointer] -> [Pointer]
+def NarrowPtr : Opcode;
+// [Pointer] -> [Pointer]
+def ExpandPtr : Opcode;
+
+//===----------------------------------------------------------------------===//
+// Direct field accessors
+//===----------------------------------------------------------------------===//
+
+class AccessOpcode : Opcode {
+ let Types = [AllTypeClass];
+ let Args = [ArgUint32];
+ let HasGroup = 1;
+}
+
+class BitFieldOpcode : Opcode {
+ let Types = [AluTypeClass];
+ let Args = [ArgRecordField];
+ let HasGroup = 1;
+}
+
+// [] -> [Pointer]
+def GetLocal : AccessOpcode { let HasCustomEval = 1; }
+// [] -> [Pointer]
+def SetLocal : AccessOpcode { let HasCustomEval = 1; }
+
+// [] -> [Value]
+def GetGlobal : AccessOpcode;
+// [Value] -> []
+def InitGlobal : AccessOpcode;
+// [Value] -> []
+def SetGlobal : AccessOpcode;
+
+// [] -> [Value]
+def GetParam : AccessOpcode;
+// [Value] -> []
+def SetParam : AccessOpcode;
+
+// [Pointer] -> [Pointer, Value]
+def GetField : AccessOpcode;
+// [Pointer] -> [Value]
+def GetFieldPop : AccessOpcode;
+// [] -> [Value]
+def GetThisField : AccessOpcode;
+
+// [Pointer, Value] -> [Pointer]
+def SetField : AccessOpcode;
+// [Value] -> []
+def SetThisField : AccessOpcode;
+
+// [Value] -> []
+def InitThisField : AccessOpcode;
+// [Value] -> []
+def InitThisFieldActive : AccessOpcode;
+// [Value] -> []
+def InitThisBitField : BitFieldOpcode;
+// [Pointer, Value] -> []
+def InitField : AccessOpcode;
+// [Pointer, Value] -> []
+def InitBitField : BitFieldOpcode;
+// [Pointer, Value] -> []
+def InitFieldActive : AccessOpcode;
+
+//===----------------------------------------------------------------------===//
+// Pointer access
+//===----------------------------------------------------------------------===//
+
+class LoadOpcode : Opcode {
+ let Types = [AllTypeClass];
+ let HasGroup = 1;
+}
+
+// [Pointer] -> [Pointer, Value]
+def Load : LoadOpcode {}
+// [Pointer] -> [Value]
+def LoadPop : LoadOpcode {}
+
+class StoreOpcode : Opcode {
+ let Types = [AllTypeClass];
+ let HasGroup = 1;
+}
+
+class StoreBitFieldOpcode : Opcode {
+ let Types = [AluTypeClass];
+ let HasGroup = 1;
+}
+
+// [Pointer, Value] -> [Pointer]
+def Store : StoreOpcode {}
+// [Pointer, Value] -> []
+def StorePop : StoreOpcode {}
+
+// [Pointer, Value] -> [Pointer]
+def StoreBitField : StoreBitFieldOpcode {}
+// [Pointer, Value] -> []
+def StoreBitFieldPop : StoreBitFieldOpcode {}
+
+// [Pointer, Value] -> []
+def InitPop : StoreOpcode {}
+// [Pointer, Value] -> [Pointer]
+def InitElem : Opcode {
+ let Types = [AllTypeClass];
+ let Args = [ArgUint32];
+ let HasGroup = 1;
+}
+// [Pointer, Value] -> []
+def InitElemPop : Opcode {
+ let Types = [AllTypeClass];
+ let Args = [ArgUint32];
+ let HasGroup = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Pointer arithmetic.
+//===----------------------------------------------------------------------===//
+
+// [Pointer, Integral] -> [Pointer]
+def AddOffset : AluOpcode;
+// [Pointer, Integral] -> [Pointer]
+def SubOffset : AluOpcode;
+
+//===----------------------------------------------------------------------===//
+// Binary operators.
+//===----------------------------------------------------------------------===//
+
+// [Real, Real] -> [Real]
+def Sub : AluOpcode;
+def Add : AluOpcode;
+def Mul : AluOpcode;
+
+//===----------------------------------------------------------------------===//
+// Comparison opcodes.
+//===----------------------------------------------------------------------===//
+
+class EqualityOpcode : Opcode {
+ let Types = [AllTypeClass];
+ let HasGroup = 1;
+}
+
+def EQ : EqualityOpcode;
+def NE : EqualityOpcode;
+
+class ComparisonOpcode : Opcode {
+ let Types = [ComparableTypeClass];
+ let HasGroup = 1;
+}
+
+def LT : ComparisonOpcode;
+def LE : ComparisonOpcode;
+def GT : ComparisonOpcode;
+def GE : ComparisonOpcode;
+
+//===----------------------------------------------------------------------===//
+// Stack management.
+//===----------------------------------------------------------------------===//
+
+// [Value] -> []
+def Pop : Opcode {
+ let Types = [AllTypeClass];
+ let HasGroup = 1;
+}
+
+// [Value] -> [Value, Value]
+def Dup : Opcode {
+ let Types = [AllTypeClass];
+ let HasGroup = 1;
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Pointer.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Pointer.cpp
new file mode 100644
index 000000000000..1a10723aaca5
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Pointer.cpp
@@ -0,0 +1,193 @@
+//===--- Pointer.cpp - Types for the constexpr VM ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Pointer.h"
+#include "Block.h"
+#include "Function.h"
+#include "PrimType.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
+
+Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
+
+Pointer::Pointer(Pointer &&P)
+ : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
+ if (Pointee)
+ Pointee->movePointer(&P, this);
+}
+
+Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
+ : Pointee(Pointee), Base(Base), Offset(Offset) {
+ assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
+ if (Pointee)
+ Pointee->addPointer(this);
+}
+
+Pointer::~Pointer() {
+ if (Pointee) {
+ Pointee->removePointer(this);
+ Pointee->cleanup();
+ }
+}
+
+void Pointer::operator=(const Pointer &P) {
+ Block *Old = Pointee;
+
+ if (Pointee)
+ Pointee->removePointer(this);
+
+ Offset = P.Offset;
+ Base = P.Base;
+
+ Pointee = P.Pointee;
+ if (Pointee)
+ Pointee->addPointer(this);
+
+ if (Old)
+ Old->cleanup();
+}
+
+void Pointer::operator=(Pointer &&P) {
+ Block *Old = Pointee;
+
+ if (Pointee)
+ Pointee->removePointer(this);
+
+ Offset = P.Offset;
+ Base = P.Base;
+
+ Pointee = P.Pointee;
+ if (Pointee)
+ Pointee->movePointer(&P, this);
+
+ if (Old)
+ Old->cleanup();
+}
+
+APValue Pointer::toAPValue() const {
+ APValue::LValueBase Base;
+ llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
+ CharUnits Offset;
+ bool IsNullPtr;
+ bool IsOnePastEnd;
+
+ if (isZero()) {
+ Base = static_cast<const Expr *>(nullptr);
+ IsNullPtr = true;
+ IsOnePastEnd = false;
+ Offset = CharUnits::Zero();
+ } else {
+ // Build the lvalue base from the block.
+ Descriptor *Desc = getDeclDesc();
+ if (auto *VD = Desc->asValueDecl())
+ Base = VD;
+ else if (auto *E = Desc->asExpr())
+ Base = E;
+ else
+ llvm_unreachable("Invalid allocation type");
+
+ // Not a null pointer.
+ IsNullPtr = false;
+
+ if (isUnknownSizeArray()) {
+ IsOnePastEnd = false;
+ Offset = CharUnits::Zero();
+ } else {
+ // TODO: compute the offset into the object.
+ Offset = CharUnits::Zero();
+
+ // Build the path into the object.
+ Pointer Ptr = *this;
+ while (Ptr.isField()) {
+ if (Ptr.isArrayElement()) {
+ Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
+ Ptr = Ptr.getArray();
+ } else {
+ // TODO: figure out if base is virtual
+ bool IsVirtual = false;
+
+ // Create a path entry for the field.
+ Descriptor *Desc = Ptr.getFieldDesc();
+ if (auto *BaseOrMember = Desc->asDecl()) {
+ Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
+ Ptr = Ptr.getBase();
+ continue;
+ }
+ llvm_unreachable("Invalid field type");
+ }
+ }
+
+ IsOnePastEnd = isOnePastEnd();
+ }
+ }
+
+ return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
+}
+
+bool Pointer::isInitialized() const {
+ assert(Pointee && "Cannot check if null pointer was initialized");
+ Descriptor *Desc = getFieldDesc();
+ if (Desc->isPrimitiveArray()) {
+ if (Pointee->IsStatic)
+ return true;
+ // Primitive array field are stored in a bitset.
+ InitMap *Map = getInitMap();
+ if (!Map)
+ return false;
+ if (Map == (InitMap *)-1)
+ return true;
+ return Map->isInitialized(getIndex());
+ } else {
+ // Field has its bit in an inline descriptor.
+ return Base == 0 || getInlineDesc()->IsInitialized;
+ }
+}
+
+void Pointer::initialize() const {
+ assert(Pointee && "Cannot initialize null pointer");
+ Descriptor *Desc = getFieldDesc();
+ if (Desc->isPrimitiveArray()) {
+ if (!Pointee->IsStatic) {
+ // Primitive array initializer.
+ InitMap *&Map = getInitMap();
+ if (Map == (InitMap *)-1)
+ return;
+ if (Map == nullptr)
+ Map = InitMap::allocate(Desc->getNumElems());
+ if (Map->initialize(getIndex())) {
+ free(Map);
+ Map = (InitMap *)-1;
+ }
+ }
+ } else {
+ // Field has its bit in an inline descriptor.
+ assert(Base != 0 && "Only composite fields can be initialised");
+ getInlineDesc()->IsInitialized = true;
+ }
+}
+
+void Pointer::activate() const {
+ // Field has its bit in an inline descriptor.
+ assert(Base != 0 && "Only composite fields can be initialised");
+ getInlineDesc()->IsActive = true;
+}
+
+void Pointer::deactivate() const {
+ // TODO: this only appears in constructors, so nothing to deactivate.
+}
+
+bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
+ return A.Pointee == B.Pointee;
+}
+
+bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
+ return A.Base == B.Base && A.getFieldDesc()->IsArray;
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Pointer.h b/contrib/llvm-project/clang/lib/AST/Interp/Pointer.h
new file mode 100644
index 000000000000..b8fa98e24faa
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Pointer.h
@@ -0,0 +1,353 @@
+//===--- Pointer.h - Types for the constexpr VM -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the classes responsible for pointer tracking.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_POINTER_H
+#define LLVM_CLANG_AST_INTERP_POINTER_H
+
+#include "Block.h"
+#include "Descriptor.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ComparisonCategories.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace interp {
+class Block;
+class DeadBlock;
+class Context;
+class InterpState;
+class Pointer;
+class Function;
+enum PrimType : unsigned;
+
+/// A pointer to a memory block, live or dead.
+///
+/// This object can be allocated into interpreter stack frames. If pointing to
+/// a live block, it is a link in the chain of pointers pointing to the block.
+class Pointer {
+private:
+ static constexpr unsigned PastEndMark = (unsigned)-1;
+ static constexpr unsigned RootPtrMark = (unsigned)-1;
+
+public:
+ Pointer() {}
+ Pointer(Block *B);
+ Pointer(const Pointer &P);
+ Pointer(Pointer &&P);
+ ~Pointer();
+
+ void operator=(const Pointer &P);
+ void operator=(Pointer &&P);
+
+ /// Converts the pointer to an APValue.
+ APValue toAPValue() const;
+
+ /// Offsets a pointer inside an array.
+ Pointer atIndex(unsigned Idx) const {
+ if (Base == RootPtrMark)
+ return Pointer(Pointee, RootPtrMark, getDeclDesc()->getSize());
+ unsigned Off = Idx * elemSize();
+ if (getFieldDesc()->ElemDesc)
+ Off += sizeof(InlineDescriptor);
+ else
+ Off += sizeof(InitMap *);
+ return Pointer(Pointee, Base, Base + Off);
+ }
+
+ /// Creates a pointer to a field.
+ Pointer atField(unsigned Off) const {
+ unsigned Field = Offset + Off;
+ return Pointer(Pointee, Field, Field);
+ }
+
+ /// Restricts the scope of an array element pointer.
+ Pointer narrow() const {
+ // Null pointers cannot be narrowed.
+ if (isZero() || isUnknownSizeArray())
+ return *this;
+
+ // Pointer to an array of base types - enter block.
+ if (Base == RootPtrMark)
+ return Pointer(Pointee, 0, Offset == 0 ? Offset : PastEndMark);
+
+ // Pointer is one past end - magic offset marks that.
+ if (isOnePastEnd())
+ return Pointer(Pointee, Base, PastEndMark);
+
+ // Primitive arrays are a bit special since they do not have inline
+ // descriptors. If Offset != Base, then the pointer already points to
+ // an element and there is nothing to do. Otherwise, the pointer is
+ // adjusted to the first element of the array.
+ if (inPrimitiveArray()) {
+ if (Offset != Base)
+ return *this;
+ return Pointer(Pointee, Base, Offset + sizeof(InitMap *));
+ }
+
+ // Pointer is to a field or array element - enter it.
+ if (Offset != Base)
+ return Pointer(Pointee, Offset, Offset);
+
+ // Enter the first element of an array.
+ if (!getFieldDesc()->isArray())
+ return *this;
+
+ const unsigned NewBase = Base + sizeof(InlineDescriptor);
+ return Pointer(Pointee, NewBase, NewBase);
+ }
+
+ /// Expands a pointer to the containing array, undoing narrowing.
+ Pointer expand() const {
+ if (isElementPastEnd()) {
+ // Revert to an outer one-past-end pointer.
+ unsigned Adjust;
+ if (inPrimitiveArray())
+ Adjust = sizeof(InitMap *);
+ else
+ Adjust = sizeof(InlineDescriptor);
+ return Pointer(Pointee, Base, Base + getSize() + Adjust);
+ }
+
+ // Do not step out of array elements.
+ if (Base != Offset)
+ return *this;
+
+ // If at base, point to an array of base types.
+ if (Base == 0)
+ return Pointer(Pointee, RootPtrMark, 0);
+
+ // Step into the containing array, if inside one.
+ unsigned Next = Base - getInlineDesc()->Offset;
+ Descriptor *Desc = Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc;
+ if (!Desc->IsArray)
+ return *this;
+ return Pointer(Pointee, Next, Offset);
+ }
+
+ /// Checks if the pointer is null.
+ bool isZero() const { return Pointee == nullptr; }
+ /// Checks if the pointer is live.
+ bool isLive() const { return Pointee && !Pointee->IsDead; }
+ /// Checks if the item is a field in an object.
+ bool isField() const { return Base != 0 && Base != RootPtrMark; }
+
+ /// Accessor for information about the declaration site.
+ Descriptor *getDeclDesc() const { return Pointee->Desc; }
+ SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); }
+
+ /// Returns a pointer to the object of which this pointer is a field.
+ Pointer getBase() const {
+ if (Base == RootPtrMark) {
+ assert(Offset == PastEndMark && "cannot get base of a block");
+ return Pointer(Pointee, Base, 0);
+ }
+ assert(Offset == Base && "not an inner field");
+ unsigned NewBase = Base - getInlineDesc()->Offset;
+ return Pointer(Pointee, NewBase, NewBase);
+ }
+ /// Returns the parent array.
+ Pointer getArray() const {
+ if (Base == RootPtrMark) {
+ assert(Offset != 0 && Offset != PastEndMark && "not an array element");
+ return Pointer(Pointee, Base, 0);
+ }
+ assert(Offset != Base && "not an array element");
+ return Pointer(Pointee, Base, Base);
+ }
+
+ /// Accessors for information about the innermost field.
+ Descriptor *getFieldDesc() const {
+ if (Base == 0 || Base == RootPtrMark)
+ return getDeclDesc();
+ return getInlineDesc()->Desc;
+ }
+
+ /// Returns the type of the innermost field.
+ QualType getType() const { return getFieldDesc()->getType(); }
+
+ /// Returns the element size of the innermost field.
+ size_t elemSize() const {
+ if (Base == RootPtrMark)
+ return getDeclDesc()->getSize();
+ return getFieldDesc()->getElemSize();
+ }
+ /// Returns the total size of the innermost field.
+ size_t getSize() const { return getFieldDesc()->getSize(); }
+
+ /// Returns the offset into an array.
+ unsigned getOffset() const {
+ assert(Offset != PastEndMark && "invalid offset");
+ if (Base == RootPtrMark)
+ return Offset;
+
+ unsigned Adjust = 0;
+ if (Offset != Base) {
+ if (getFieldDesc()->ElemDesc)
+ Adjust = sizeof(InlineDescriptor);
+ else
+ Adjust = sizeof(InitMap *);
+ }
+ return Offset - Base - Adjust;
+ }
+
+ /// Checks if the innermost field is an array.
+ bool inArray() const { return getFieldDesc()->IsArray; }
+ /// Checks if the structure is a primitive array.
+ bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); }
+ /// Checks if the structure is an array of unknown size.
+ bool isUnknownSizeArray() const {
+ return getFieldDesc()->isUnknownSizeArray();
+ }
+ /// Checks if the pointer points to an array.
+ bool isArrayElement() const { return Base != Offset; }
+ /// Pointer points directly to a block.
+ bool isRoot() const {
+ return (Base == 0 || Base == RootPtrMark) && Offset == 0;
+ }
+
+ /// Returns the record descriptor of a class.
+ Record *getRecord() const { return getFieldDesc()->ElemRecord; }
+ /// Returns the field information.
+ const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
+
+ /// Checks if the object is a union.
+ bool isUnion() const;
+
+ /// Checks if the storage is extern.
+ bool isExtern() const { return Pointee->isExtern(); }
+ /// Checks if the storage is static.
+ bool isStatic() const { return Pointee->isStatic(); }
+ /// Checks if the storage is temporary.
+ bool isTemporary() const { return Pointee->isTemporary(); }
+ /// Checks if the storage is a static temporary.
+ bool isStaticTemporary() const { return isStatic() && isTemporary(); }
+
+ /// Checks if the field is mutable.
+ bool isMutable() const { return Base != 0 && getInlineDesc()->IsMutable; }
+ /// Checks if an object was initialized.
+ bool isInitialized() const;
+ /// Checks if the object is active.
+ bool isActive() const { return Base == 0 || getInlineDesc()->IsActive; }
+ /// Checks if a structure is a base class.
+ bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
+
+ /// Checks if an object or a subfield is mutable.
+ bool isConst() const {
+ return Base == 0 ? getDeclDesc()->IsConst : getInlineDesc()->IsConst;
+ }
+
+ /// Returns the declaration ID.
+ llvm::Optional<unsigned> getDeclID() const { return Pointee->getDeclID(); }
+
+ /// Returns the byte offset from the start.
+ unsigned getByteOffset() const {
+ return Offset;
+ }
+
+ /// Returns the number of elements.
+ unsigned getNumElems() const { return getSize() / elemSize(); }
+
+ /// Returns the index into an array.
+ int64_t getIndex() const {
+ if (isElementPastEnd())
+ return 1;
+ if (auto ElemSize = elemSize())
+ return getOffset() / ElemSize;
+ return 0;
+ }
+
+ /// Checks if the index is one past end.
+ bool isOnePastEnd() const {
+ return isElementPastEnd() || getSize() == getOffset();
+ }
+
+ /// Checks if the pointer is an out-of-bounds element pointer.
+ bool isElementPastEnd() const { return Offset == PastEndMark; }
+
+ /// Dereferences the pointer, if it's live.
+ template <typename T> T &deref() const {
+ assert(isLive() && "Invalid pointer");
+ return *reinterpret_cast<T *>(Pointee->data() + Offset);
+ }
+
+ /// Dereferences a primitive element.
+ template <typename T> T &elem(unsigned I) const {
+ return reinterpret_cast<T *>(Pointee->data())[I];
+ }
+
+ /// Initializes a field.
+ void initialize() const;
+ /// Activats a field.
+ void activate() const;
+ /// Deactivates an entire strurcutre.
+ void deactivate() const;
+
+ /// Checks if two pointers are comparable.
+ static bool hasSameBase(const Pointer &A, const Pointer &B);
+ /// Checks if two pointers can be subtracted.
+ static bool hasSameArray(const Pointer &A, const Pointer &B);
+
+ /// Prints the pointer.
+ void print(llvm::raw_ostream &OS) const {
+ OS << "{" << Base << ", " << Offset << ", ";
+ if (Pointee)
+ OS << Pointee->getSize();
+ else
+ OS << "nullptr";
+ OS << "}";
+ }
+
+private:
+ friend class Block;
+ friend class DeadBlock;
+
+ Pointer(Block *Pointee, unsigned Base, unsigned Offset);
+
+ /// Returns the embedded descriptor preceding a field.
+ InlineDescriptor *getInlineDesc() const { return getDescriptor(Base); }
+
+ /// Returns a descriptor at a given offset.
+ InlineDescriptor *getDescriptor(unsigned Offset) const {
+ assert(Offset != 0 && "Not a nested pointer");
+ return reinterpret_cast<InlineDescriptor *>(Pointee->data() + Offset) - 1;
+ }
+
+ /// Returns a reference to the pointer which stores the initialization map.
+ InitMap *&getInitMap() const {
+ return *reinterpret_cast<InitMap **>(Pointee->data() + Base);
+ }
+
+ /// The block the pointer is pointing to.
+ Block *Pointee = nullptr;
+ /// Start of the current subfield.
+ unsigned Base = 0;
+ /// Offset into the block.
+ unsigned Offset = 0;
+
+ /// Previous link in the pointer chain.
+ Pointer *Prev = nullptr;
+ /// Next link in the pointer chain.
+ Pointer *Next = nullptr;
+};
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {
+ P.print(OS);
+ return OS;
+}
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/PrimType.cpp b/contrib/llvm-project/clang/lib/AST/Interp/PrimType.cpp
new file mode 100644
index 000000000000..082bfaf3c207
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/PrimType.cpp
@@ -0,0 +1,23 @@
+//===--- Type.cpp - Types for the constexpr VM ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrimType.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+namespace clang {
+namespace interp {
+
+size_t primSize(PrimType Type) {
+ TYPE_SWITCH(Type, return sizeof(T));
+ llvm_unreachable("not a primitive type");
+}
+
+} // namespace interp
+} // namespace clang
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/PrimType.h b/contrib/llvm-project/clang/lib/AST/Interp/PrimType.h
new file mode 100644
index 000000000000..f5f4f8e5c32d
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/PrimType.h
@@ -0,0 +1,115 @@
+//===--- PrimType.h - Types for the constexpr VM --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the VM types and helpers operating on types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_TYPE_H
+#define LLVM_CLANG_AST_INTERP_TYPE_H
+
+#include <climits>
+#include <cstddef>
+#include <cstdint>
+#include "Boolean.h"
+#include "Integral.h"
+#include "Pointer.h"
+
+namespace clang {
+namespace interp {
+
+/// Enumeration of the primitive types of the VM.
+enum PrimType : unsigned {
+ PT_Sint8,
+ PT_Uint8,
+ PT_Sint16,
+ PT_Uint16,
+ PT_Sint32,
+ PT_Uint32,
+ PT_Sint64,
+ PT_Uint64,
+ PT_Bool,
+ PT_Ptr,
+};
+
+/// Mapping from primitive types to their representation.
+template <PrimType T> struct PrimConv;
+template <> struct PrimConv<PT_Sint8> { using T = Integral<8, true>; };
+template <> struct PrimConv<PT_Uint8> { using T = Integral<8, false>; };
+template <> struct PrimConv<PT_Sint16> { using T = Integral<16, true>; };
+template <> struct PrimConv<PT_Uint16> { using T = Integral<16, false>; };
+template <> struct PrimConv<PT_Sint32> { using T = Integral<32, true>; };
+template <> struct PrimConv<PT_Uint32> { using T = Integral<32, false>; };
+template <> struct PrimConv<PT_Sint64> { using T = Integral<64, true>; };
+template <> struct PrimConv<PT_Uint64> { using T = Integral<64, false>; };
+template <> struct PrimConv<PT_Bool> { using T = Boolean; };
+template <> struct PrimConv<PT_Ptr> { using T = Pointer; };
+
+/// Returns the size of a primitive type in bytes.
+size_t primSize(PrimType Type);
+
+/// Aligns a size to the pointer alignment.
+constexpr size_t align(size_t Size) {
+ return ((Size + alignof(void *) - 1) / alignof(void *)) * alignof(void *);
+}
+
+inline bool isPrimitiveIntegral(PrimType Type) {
+ switch (Type) {
+ case PT_Bool:
+ case PT_Sint8:
+ case PT_Uint8:
+ case PT_Sint16:
+ case PT_Uint16:
+ case PT_Sint32:
+ case PT_Uint32:
+ case PT_Sint64:
+ case PT_Uint64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace interp
+} // namespace clang
+
+/// Helper macro to simplify type switches.
+/// The macro implicitly exposes a type T in the scope of the inner block.
+#define TYPE_SWITCH_CASE(Name, B) \
+ case Name: { using T = PrimConv<Name>::T; do {B;} while(0); break; }
+#define TYPE_SWITCH(Expr, B) \
+ switch (Expr) { \
+ TYPE_SWITCH_CASE(PT_Sint8, B) \
+ TYPE_SWITCH_CASE(PT_Uint8, B) \
+ TYPE_SWITCH_CASE(PT_Sint16, B) \
+ TYPE_SWITCH_CASE(PT_Uint16, B) \
+ TYPE_SWITCH_CASE(PT_Sint32, B) \
+ TYPE_SWITCH_CASE(PT_Uint32, B) \
+ TYPE_SWITCH_CASE(PT_Sint64, B) \
+ TYPE_SWITCH_CASE(PT_Uint64, B) \
+ TYPE_SWITCH_CASE(PT_Bool, B) \
+ TYPE_SWITCH_CASE(PT_Ptr, B) \
+ }
+#define COMPOSITE_TYPE_SWITCH(Expr, B, D) \
+ switch (Expr) { \
+ TYPE_SWITCH_CASE(PT_Ptr, B) \
+ default: do { D; } while(0); break; \
+ }
+#define INT_TYPE_SWITCH(Expr, B) \
+ switch (Expr) { \
+ TYPE_SWITCH_CASE(PT_Sint8, B) \
+ TYPE_SWITCH_CASE(PT_Uint8, B) \
+ TYPE_SWITCH_CASE(PT_Sint16, B) \
+ TYPE_SWITCH_CASE(PT_Uint16, B) \
+ TYPE_SWITCH_CASE(PT_Sint32, B) \
+ TYPE_SWITCH_CASE(PT_Uint32, B) \
+ TYPE_SWITCH_CASE(PT_Sint64, B) \
+ TYPE_SWITCH_CASE(PT_Uint64, B) \
+ default: llvm_unreachable("not an integer"); \
+ }
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Program.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Program.cpp
new file mode 100644
index 000000000000..fcbab0ea8172
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Program.cpp
@@ -0,0 +1,364 @@
+//===--- Program.cpp - Bytecode for the constexpr VM ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Program.h"
+#include "ByteCodeStmtGen.h"
+#include "Context.h"
+#include "Function.h"
+#include "Opcode.h"
+#include "PrimType.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+unsigned Program::createGlobalString(const StringLiteral *S) {
+ const size_t CharWidth = S->getCharByteWidth();
+ const size_t BitWidth = CharWidth * Ctx.getCharBit();
+
+ PrimType CharType;
+ switch (CharWidth) {
+ case 1:
+ CharType = PT_Sint8;
+ break;
+ case 2:
+ CharType = PT_Uint16;
+ break;
+ case 4:
+ CharType = PT_Uint32;
+ break;
+ default:
+ llvm_unreachable("unsupported character width");
+ }
+
+ // Create a descriptor for the string.
+ Descriptor *Desc = allocateDescriptor(S, CharType, S->getLength() + 1,
+ /*isConst=*/true,
+ /*isTemporary=*/false,
+ /*isMutable=*/false);
+
+ // Allocate storage for the string.
+ // The byte length does not include the null terminator.
+ unsigned I = Globals.size();
+ unsigned Sz = Desc->getAllocSize();
+ auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true,
+ /*isExtern=*/false);
+ Globals.push_back(G);
+
+ // Construct the string in storage.
+ const Pointer Ptr(G->block());
+ for (unsigned I = 0, N = S->getLength(); I <= N; ++I) {
+ Pointer Field = Ptr.atIndex(I).narrow();
+ const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I);
+ switch (CharType) {
+ case PT_Sint8: {
+ using T = PrimConv<PT_Sint8>::T;
+ Field.deref<T>() = T::from(CodePoint, BitWidth);
+ break;
+ }
+ case PT_Uint16: {
+ using T = PrimConv<PT_Uint16>::T;
+ Field.deref<T>() = T::from(CodePoint, BitWidth);
+ break;
+ }
+ case PT_Uint32: {
+ using T = PrimConv<PT_Uint32>::T;
+ Field.deref<T>() = T::from(CodePoint, BitWidth);
+ break;
+ }
+ default:
+ llvm_unreachable("unsupported character type");
+ }
+ }
+ return I;
+}
+
+Pointer Program::getPtrGlobal(unsigned Idx) {
+ assert(Idx < Globals.size());
+ return Pointer(Globals[Idx]->block());
+}
+
+llvm::Optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
+ auto It = GlobalIndices.find(VD);
+ if (It != GlobalIndices.end())
+ return It->second;
+
+ // Find any previous declarations which were aleady evaluated.
+ llvm::Optional<unsigned> Index;
+ for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
+ auto It = GlobalIndices.find(P);
+ if (It != GlobalIndices.end()) {
+ Index = It->second;
+ break;
+ }
+ }
+
+ // Map the decl to the existing index.
+ if (Index) {
+ GlobalIndices[VD] = *Index;
+ return {};
+ }
+
+ return Index;
+}
+
+llvm::Optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD) {
+ if (auto Idx = getGlobal(VD))
+ return Idx;
+
+ if (auto Idx = createGlobal(VD)) {
+ GlobalIndices[VD] = *Idx;
+ return Idx;
+ }
+ return {};
+}
+
+llvm::Optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) {
+ auto &ASTCtx = Ctx.getASTContext();
+
+ // Create a pointer to an incomplete array of the specified elements.
+ QualType ElemTy = PD->getType()->castAs<PointerType>()->getPointeeType();
+ QualType Ty = ASTCtx.getIncompleteArrayType(ElemTy, ArrayType::Normal, 0);
+
+ // Dedup blocks since they are immutable and pointers cannot be compared.
+ auto It = DummyParams.find(PD);
+ if (It != DummyParams.end())
+ return It->second;
+
+ if (auto Idx = createGlobal(PD, Ty, /*isStatic=*/true, /*isExtern=*/true)) {
+ DummyParams[PD] = *Idx;
+ return Idx;
+ }
+ return {};
+}
+
+llvm::Optional<unsigned> Program::createGlobal(const ValueDecl *VD) {
+ bool IsStatic, IsExtern;
+ if (auto *Var = dyn_cast<VarDecl>(VD)) {
+ IsStatic = !Var->hasLocalStorage();
+ IsExtern = !Var->getAnyInitializer();
+ } else {
+ IsStatic = false;
+ IsExtern = true;
+ }
+ if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern)) {
+ for (const Decl *P = VD; P; P = P->getPreviousDecl())
+ GlobalIndices[P] = *Idx;
+ return *Idx;
+ }
+ return {};
+}
+
+llvm::Optional<unsigned> Program::createGlobal(const Expr *E) {
+ return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false);
+}
+
+llvm::Optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
+ bool IsStatic, bool IsExtern) {
+ // Create a descriptor for the global.
+ Descriptor *Desc;
+ const bool IsConst = Ty.isConstQualified();
+ const bool IsTemporary = D.dyn_cast<const Expr *>();
+ if (auto T = Ctx.classify(Ty)) {
+ Desc = createDescriptor(D, *T, IsConst, IsTemporary);
+ } else {
+ Desc = createDescriptor(D, Ty.getTypePtr(), IsConst, IsTemporary);
+ }
+ if (!Desc)
+ return {};
+
+ // Allocate a block for storage.
+ unsigned I = Globals.size();
+
+ auto *G = new (Allocator, Desc->getAllocSize())
+ Global(getCurrentDecl(), Desc, IsStatic, IsExtern);
+ G->block()->invokeCtor();
+
+ Globals.push_back(G);
+
+ return I;
+}
+
+Function *Program::getFunction(const FunctionDecl *F) {
+ F = F->getDefinition();
+ auto It = Funcs.find(F);
+ return It == Funcs.end() ? nullptr : It->second.get();
+}
+
+llvm::Expected<Function *> Program::getOrCreateFunction(const FunctionDecl *F) {
+ if (Function *Func = getFunction(F)) {
+ return Func;
+ }
+
+ // Try to compile the function if it wasn't compiled yet.
+ if (const FunctionDecl *FD = F->getDefinition())
+ return ByteCodeStmtGen<ByteCodeEmitter>(Ctx, *this).compileFunc(FD);
+
+ // A relocation which traps if not resolved.
+ return nullptr;
+}
+
+Record *Program::getOrCreateRecord(const RecordDecl *RD) {
+ // Use the actual definition as a key.
+ RD = RD->getDefinition();
+ if (!RD)
+ return nullptr;
+
+ // Deduplicate records.
+ auto It = Records.find(RD);
+ if (It != Records.end()) {
+ return It->second;
+ }
+
+ // Number of bytes required by fields and base classes.
+ unsigned Size = 0;
+ // Number of bytes required by virtual base.
+ unsigned VirtSize = 0;
+
+ // Helper to get a base descriptor.
+ auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * {
+ if (!BR)
+ return nullptr;
+ return allocateDescriptor(BD, BR, /*isConst=*/false,
+ /*isTemporary=*/false,
+ /*isMutable=*/false);
+ };
+
+ // Reserve space for base classes.
+ Record::BaseList Bases;
+ Record::VirtualBaseList VirtBases;
+ if (auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (const CXXBaseSpecifier &Spec : CD->bases()) {
+ if (Spec.isVirtual())
+ continue;
+
+ const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
+ Record *BR = getOrCreateRecord(BD);
+ if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
+ Size += align(sizeof(InlineDescriptor));
+ Bases.push_back({BD, Size, Desc, BR});
+ Size += align(BR->getSize());
+ continue;
+ }
+ return nullptr;
+ }
+
+ for (const CXXBaseSpecifier &Spec : CD->vbases()) {
+ const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
+ Record *BR = getOrCreateRecord(BD);
+
+ if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
+ VirtSize += align(sizeof(InlineDescriptor));
+ VirtBases.push_back({BD, VirtSize, Desc, BR});
+ VirtSize += align(BR->getSize());
+ continue;
+ }
+ return nullptr;
+ }
+ }
+
+ // Reserve space for fields.
+ Record::FieldList Fields;
+ for (const FieldDecl *FD : RD->fields()) {
+ // Reserve space for the field's descriptor and the offset.
+ Size += align(sizeof(InlineDescriptor));
+
+ // Classify the field and add its metadata.
+ QualType FT = FD->getType();
+ const bool IsConst = FT.isConstQualified();
+ const bool IsMutable = FD->isMutable();
+ Descriptor *Desc;
+ if (llvm::Optional<PrimType> T = Ctx.classify(FT)) {
+ Desc = createDescriptor(FD, *T, IsConst, /*isTemporary=*/false,
+ IsMutable);
+ } else {
+ Desc = createDescriptor(FD, FT.getTypePtr(), IsConst,
+ /*isTemporary=*/false, IsMutable);
+ }
+ if (!Desc)
+ return nullptr;
+ Fields.push_back({FD, Size, Desc});
+ Size += align(Desc->getAllocSize());
+ }
+
+ Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),
+ std::move(VirtBases), VirtSize, Size);
+ Records.insert({RD, R});
+ return R;
+}
+
+Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
+ bool IsConst, bool IsTemporary,
+ bool IsMutable) {
+ // Classes and structures.
+ if (auto *RT = Ty->getAs<RecordType>()) {
+ if (auto *Record = getOrCreateRecord(RT->getDecl()))
+ return allocateDescriptor(D, Record, IsConst, IsTemporary, IsMutable);
+ }
+
+ // Arrays.
+ if (auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
+ QualType ElemTy = ArrayType->getElementType();
+ // Array of well-known bounds.
+ if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
+ size_t NumElems = CAT->getSize().getZExtValue();
+ if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
+ // Arrays of primitives.
+ unsigned ElemSize = primSize(*T);
+ if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) {
+ return {};
+ }
+ return allocateDescriptor(D, *T, NumElems, IsConst, IsTemporary,
+ IsMutable);
+ } else {
+ // Arrays of composites. In this case, the array is a list of pointers,
+ // followed by the actual elements.
+ Descriptor *Desc =
+ createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
+ if (!Desc)
+ return nullptr;
+ InterpSize ElemSize = Desc->getAllocSize() + sizeof(InlineDescriptor);
+ if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
+ return {};
+ return allocateDescriptor(D, Desc, NumElems, IsConst, IsTemporary,
+ IsMutable);
+ }
+ }
+
+ // Array of unknown bounds - cannot be accessed and pointer arithmetic
+ // is forbidden on pointers to such objects.
+ if (isa<IncompleteArrayType>(ArrayType)) {
+ if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
+ return allocateDescriptor(D, *T, IsTemporary,
+ Descriptor::UnknownSize{});
+ } else {
+ Descriptor *Desc =
+ createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
+ if (!Desc)
+ return nullptr;
+ return allocateDescriptor(D, Desc, IsTemporary,
+ Descriptor::UnknownSize{});
+ }
+ }
+ }
+
+ // Atomic types.
+ if (auto *AT = Ty->getAs<AtomicType>()) {
+ const Type *InnerTy = AT->getValueType().getTypePtr();
+ return createDescriptor(D, InnerTy, IsConst, IsTemporary, IsMutable);
+ }
+
+ // Complex types - represented as arrays of elements.
+ if (auto *CT = Ty->getAs<ComplexType>()) {
+ PrimType ElemTy = *Ctx.classify(CT->getElementType());
+ return allocateDescriptor(D, ElemTy, 2, IsConst, IsTemporary, IsMutable);
+ }
+
+ return nullptr;
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Program.h b/contrib/llvm-project/clang/lib/AST/Interp/Program.h
new file mode 100644
index 000000000000..5f0012db9b3f
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Program.h
@@ -0,0 +1,220 @@
+//===--- Program.h - Bytecode for the constexpr VM --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a program which organises and links multiple bytecode functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_PROGRAM_H
+#define LLVM_CLANG_AST_INTERP_PROGRAM_H
+
+#include <map>
+#include <vector>
+#include "Function.h"
+#include "Pointer.h"
+#include "PrimType.h"
+#include "Record.h"
+#include "Source.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+
+namespace clang {
+class RecordDecl;
+class Expr;
+class FunctionDecl;
+class Stmt;
+class StringLiteral;
+class VarDecl;
+
+namespace interp {
+class Context;
+class State;
+class Record;
+class Scope;
+
+/// The program contains and links the bytecode for all functions.
+class Program {
+public:
+ Program(Context &Ctx) : Ctx(Ctx) {}
+
+ /// Emits a string literal among global data.
+ unsigned createGlobalString(const StringLiteral *S);
+
+ /// Returns a pointer to a global.
+ Pointer getPtrGlobal(unsigned Idx);
+
+ /// Returns the value of a global.
+ Block *getGlobal(unsigned Idx) {
+ assert(Idx < Globals.size());
+ return Globals[Idx]->block();
+ }
+
+ /// Finds a global's index.
+ llvm::Optional<unsigned> getGlobal(const ValueDecl *VD);
+
+ /// Returns or creates a global an creates an index to it.
+ llvm::Optional<unsigned> getOrCreateGlobal(const ValueDecl *VD);
+
+ /// Returns or creates a dummy value for parameters.
+ llvm::Optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
+
+ /// Creates a global and returns its index.
+ llvm::Optional<unsigned> createGlobal(const ValueDecl *VD);
+
+ /// Creates a global from a lifetime-extended temporary.
+ llvm::Optional<unsigned> createGlobal(const Expr *E);
+
+ /// Creates a new function from a code range.
+ template <typename... Ts>
+ Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
+ auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
+ Funcs.insert({Def, std::unique_ptr<Function>(Func)});
+ return Func;
+ }
+ /// Creates an anonymous function.
+ template <typename... Ts>
+ Function *createFunction(Ts &&... Args) {
+ auto *Func = new Function(*this, std::forward<Ts>(Args)...);
+ AnonFuncs.emplace_back(Func);
+ return Func;
+ }
+
+ /// Returns a function.
+ Function *getFunction(const FunctionDecl *F);
+
+ /// Returns a pointer to a function if it exists and can be compiled.
+ /// If a function couldn't be compiled, an error is returned.
+ /// If a function was not yet defined, a null pointer is returned.
+ llvm::Expected<Function *> getOrCreateFunction(const FunctionDecl *F);
+
+ /// Returns a record or creates one if it does not exist.
+ Record *getOrCreateRecord(const RecordDecl *RD);
+
+ /// Creates a descriptor for a primitive type.
+ Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
+ bool IsConst = false,
+ bool IsTemporary = false,
+ bool IsMutable = false) {
+ return allocateDescriptor(D, Type, IsConst, IsTemporary, IsMutable);
+ }
+
+ /// Creates a descriptor for a composite type.
+ Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
+ bool IsConst = false, bool IsTemporary = false,
+ bool IsMutable = false);
+
+ /// Context to manage declaration lifetimes.
+ class DeclScope {
+ public:
+ DeclScope(Program &P, const VarDecl *VD) : P(P) { P.startDeclaration(VD); }
+ ~DeclScope() { P.endDeclaration(); }
+
+ private:
+ Program &P;
+ };
+
+ /// Returns the current declaration ID.
+ llvm::Optional<unsigned> getCurrentDecl() const {
+ if (CurrentDeclaration == NoDeclaration)
+ return llvm::Optional<unsigned>{};
+ return LastDeclaration;
+ }
+
+private:
+ friend class DeclScope;
+
+ llvm::Optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
+ bool IsStatic, bool IsExtern);
+
+ /// Reference to the VM context.
+ Context &Ctx;
+ /// Mapping from decls to cached bytecode functions.
+ llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
+ /// List of anonymous functions.
+ std::vector<std::unique_ptr<Function>> AnonFuncs;
+
+ /// Function relocation locations.
+ llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
+
+ /// Custom allocator for global storage.
+ using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;
+
+ /// Descriptor + storage for a global object.
+ ///
+ /// Global objects never go out of scope, thus they do not track pointers.
+ class Global {
+ public:
+ /// Create a global descriptor for string literals.
+ template <typename... Tys>
+ Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}
+
+ /// Allocates the global in the pool, reserving storate for data.
+ void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
+ return Alloc.Allocate(Meta + Data, alignof(void *));
+ }
+
+ /// Return a pointer to the data.
+ char *data() { return B.data(); }
+ /// Return a pointer to the block.
+ Block *block() { return &B; }
+
+ private:
+ /// Required metadata - does not actually track pointers.
+ Block B;
+ };
+
+ /// Allocator for globals.
+ PoolAllocTy Allocator;
+
+ /// Global objects.
+ std::vector<Global *> Globals;
+ /// Cached global indices.
+ llvm::DenseMap<const void *, unsigned> GlobalIndices;
+
+ /// Mapping from decls to record metadata.
+ llvm::DenseMap<const RecordDecl *, Record *> Records;
+
+ /// Dummy parameter to generate pointers from.
+ llvm::DenseMap<const ParmVarDecl *, unsigned> DummyParams;
+
+ /// Creates a new descriptor.
+ template <typename... Ts>
+ Descriptor *allocateDescriptor(Ts &&... Args) {
+ return new (Allocator) Descriptor(std::forward<Ts>(Args)...);
+ }
+
+ /// No declaration ID.
+ static constexpr unsigned NoDeclaration = (unsigned)-1;
+ /// Last declaration ID.
+ unsigned LastDeclaration = 0;
+ /// Current declaration ID.
+ unsigned CurrentDeclaration = NoDeclaration;
+
+ /// Starts evaluating a declaration.
+ void startDeclaration(const VarDecl *Decl) {
+ LastDeclaration += 1;
+ CurrentDeclaration = LastDeclaration;
+ }
+
+ /// Ends a global declaration.
+ void endDeclaration() {
+ CurrentDeclaration = NoDeclaration;
+ }
+
+public:
+ /// Dumps the disassembled bytecode to \c llvm::errs().
+ void dump() const;
+ void dump(llvm::raw_ostream &OS) const;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Record.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Record.cpp
new file mode 100644
index 000000000000..f440c4705051
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Record.cpp
@@ -0,0 +1,46 @@
+//===--- Record.cpp - struct and class metadata for the VM ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Record.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+Record::Record(const RecordDecl *Decl, BaseList &&SrcBases,
+ FieldList &&SrcFields, VirtualBaseList &&SrcVirtualBases,
+ unsigned VirtualSize, unsigned BaseSize)
+ : Decl(Decl), Bases(std::move(SrcBases)), Fields(std::move(SrcFields)),
+ BaseSize(BaseSize), VirtualSize(VirtualSize) {
+ for (Base &V : SrcVirtualBases)
+ VirtualBases.push_back({ V.Decl, V.Offset + BaseSize, V.Desc, V.R });
+
+ for (Base &B : Bases)
+ BaseMap[B.Decl] = &B;
+ for (Field &F : Fields)
+ FieldMap[F.Decl] = &F;
+ for (Base &V : VirtualBases)
+ VirtualBaseMap[V.Decl] = &V;
+}
+
+const Record::Field *Record::getField(const FieldDecl *FD) const {
+ auto It = FieldMap.find(FD);
+ assert(It != FieldMap.end() && "Missing field");
+ return It->second;
+}
+
+const Record::Base *Record::getBase(const RecordDecl *FD) const {
+ auto It = BaseMap.find(FD);
+ assert(It != BaseMap.end() && "Missing base");
+ return It->second;
+}
+
+const Record::Base *Record::getVirtualBase(const RecordDecl *FD) const {
+ auto It = VirtualBaseMap.find(FD);
+ assert(It != VirtualBaseMap.end() && "Missing virtual base");
+ return It->second;
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Record.h b/contrib/llvm-project/clang/lib/AST/Interp/Record.h
new file mode 100644
index 000000000000..9cdee9003752
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Record.h
@@ -0,0 +1,121 @@
+//===--- Record.h - struct and class metadata for the VM --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// A record is part of a program to describe the layout and methods of a struct.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_RECORD_H
+#define LLVM_CLANG_AST_INTERP_RECORD_H
+
+#include "Pointer.h"
+
+namespace clang {
+namespace interp {
+class Program;
+
+/// Structure/Class descriptor.
+class Record {
+public:
+ /// Describes a record field.
+ struct Field {
+ const FieldDecl *Decl;
+ unsigned Offset;
+ Descriptor *Desc;
+ };
+
+ /// Describes a base class.
+ struct Base {
+ const RecordDecl *Decl;
+ unsigned Offset;
+ Descriptor *Desc;
+ Record *R;
+ };
+
+ /// Mapping from identifiers to field descriptors.
+ using FieldList = llvm::SmallVector<Field, 8>;
+ /// Mapping from identifiers to base classes.
+ using BaseList = llvm::SmallVector<Base, 8>;
+ /// List of virtual base classes.
+ using VirtualBaseList = llvm::SmallVector<Base, 2>;
+
+public:
+ /// Returns the underlying declaration.
+ const RecordDecl *getDecl() const { return Decl; }
+ /// Checks if the record is a union.
+ bool isUnion() const { return getDecl()->isUnion(); }
+ /// Returns the size of the record.
+ unsigned getSize() const { return BaseSize; }
+ /// Returns the full size of the record, including records.
+ unsigned getFullSize() const { return BaseSize + VirtualSize; }
+ /// Returns a field.
+ const Field *getField(const FieldDecl *FD) const;
+ /// Returns a base descriptor.
+ const Base *getBase(const RecordDecl *FD) const;
+ /// Returns a virtual base descriptor.
+ const Base *getVirtualBase(const RecordDecl *RD) const;
+
+ using const_field_iter = FieldList::const_iterator;
+ llvm::iterator_range<const_field_iter> fields() const {
+ return llvm::make_range(Fields.begin(), Fields.end());
+ }
+
+ unsigned getNumFields() { return Fields.size(); }
+ Field *getField(unsigned I) { return &Fields[I]; }
+
+ using const_base_iter = BaseList::const_iterator;
+ llvm::iterator_range<const_base_iter> bases() const {
+ return llvm::make_range(Bases.begin(), Bases.end());
+ }
+
+ unsigned getNumBases() { return Bases.size(); }
+ Base *getBase(unsigned I) { return &Bases[I]; }
+
+ using const_virtual_iter = VirtualBaseList::const_iterator;
+ llvm::iterator_range<const_virtual_iter> virtual_bases() const {
+ return llvm::make_range(VirtualBases.begin(), VirtualBases.end());
+ }
+
+ unsigned getNumVirtualBases() { return VirtualBases.size(); }
+ Base *getVirtualBase(unsigned I) { return &VirtualBases[I]; }
+
+private:
+ /// Constructor used by Program to create record descriptors.
+ Record(const RecordDecl *, BaseList &&Bases, FieldList &&Fields,
+ VirtualBaseList &&VirtualBases, unsigned VirtualSize,
+ unsigned BaseSize);
+
+private:
+ friend class Program;
+
+ /// Original declaration.
+ const RecordDecl *Decl;
+ /// List of all base classes.
+ BaseList Bases;
+ /// List of all the fields in the record.
+ FieldList Fields;
+ /// List o fall virtual bases.
+ VirtualBaseList VirtualBases;
+
+ /// Mapping from declarations to bases.
+ llvm::DenseMap<const RecordDecl *, Base *> BaseMap;
+ /// Mapping from field identifiers to descriptors.
+ llvm::DenseMap<const FieldDecl *, Field *> FieldMap;
+ /// Mapping from declarations to virtual bases.
+ llvm::DenseMap<const RecordDecl *, Base *> VirtualBaseMap;
+ /// Mapping from
+ /// Size of the structure.
+ unsigned BaseSize;
+ /// Size of all virtual bases.
+ unsigned VirtualSize;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Source.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Source.cpp
new file mode 100644
index 000000000000..4bec87812638
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Source.cpp
@@ -0,0 +1,39 @@
+//===--- Source.cpp - Source expression tracking ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Source.h"
+#include "clang/AST/Expr.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+SourceLocation SourceInfo::getLoc() const {
+ if (const Expr *E = asExpr())
+ return E->getExprLoc();
+ if (const Stmt *S = asStmt())
+ return S->getBeginLoc();
+ if (const Decl *D = asDecl())
+ return D->getBeginLoc();
+ return SourceLocation();
+}
+
+const Expr *SourceInfo::asExpr() const {
+ if (auto *S = Source.dyn_cast<const Stmt *>())
+ return dyn_cast<Expr>(S);
+ return nullptr;
+}
+
+const Expr *SourceMapper::getExpr(Function *F, CodePtr PC) const {
+ if (const Expr *E = getSource(F, PC).asExpr())
+ return E;
+ llvm::report_fatal_error("missing source expression");
+}
+
+SourceLocation SourceMapper::getLocation(Function *F, CodePtr PC) const {
+ return getSource(F, PC).getLoc();
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Source.h b/contrib/llvm-project/clang/lib/AST/Interp/Source.h
new file mode 100644
index 000000000000..e591c3399d7c
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/Source.h
@@ -0,0 +1,118 @@
+//===--- Source.h - Source location provider for the VM --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a program which organises and links multiple bytecode functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_SOURCE_H
+#define LLVM_CLANG_AST_INTERP_SOURCE_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Stmt.h"
+#include "llvm/Support/Endian.h"
+
+namespace clang {
+namespace interp {
+class Function;
+
+/// Pointer into the code segment.
+class CodePtr {
+public:
+ CodePtr() : Ptr(nullptr) {}
+
+ CodePtr &operator+=(int32_t Offset) {
+ Ptr += Offset;
+ return *this;
+ }
+
+ int32_t operator-(const CodePtr &RHS) const {
+ assert(Ptr != nullptr && RHS.Ptr != nullptr && "Invalid code pointer");
+ return Ptr - RHS.Ptr;
+ }
+
+ CodePtr operator-(size_t RHS) const {
+ assert(Ptr != nullptr && "Invalid code pointer");
+ return CodePtr(Ptr - RHS);
+ }
+
+ bool operator!=(const CodePtr &RHS) const { return Ptr != RHS.Ptr; }
+
+ /// Reads data and advances the pointer.
+ template <typename T> T read() {
+ T Value = ReadHelper<T>(Ptr);
+ Ptr += sizeof(T);
+ return Value;
+ }
+
+private:
+ /// Constructor used by Function to generate pointers.
+ CodePtr(const char *Ptr) : Ptr(Ptr) {}
+
+ /// Helper to decode a value or a pointer.
+ template <typename T>
+ static typename std::enable_if<!std::is_pointer<T>::value, T>::type
+ ReadHelper(const char *Ptr) {
+ using namespace llvm::support;
+ return endian::read<T, endianness::native, 1>(Ptr);
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_pointer<T>::value, T>::type
+ ReadHelper(const char *Ptr) {
+ using namespace llvm::support;
+ auto Punned = endian::read<uintptr_t, endianness::native, 1>(Ptr);
+ return reinterpret_cast<T>(Punned);
+ }
+
+private:
+ friend class Function;
+
+ /// Pointer into the code owned by a function.
+ const char *Ptr;
+};
+
+/// Describes the statement/declaration an opcode was generated from.
+class SourceInfo {
+public:
+ SourceInfo() {}
+ SourceInfo(const Stmt *E) : Source(E) {}
+ SourceInfo(const Decl *D) : Source(D) {}
+
+ SourceLocation getLoc() const;
+
+ const Stmt *asStmt() const { return Source.dyn_cast<const Stmt *>(); }
+ const Decl *asDecl() const { return Source.dyn_cast<const Decl *>(); }
+ const Expr *asExpr() const;
+
+ operator bool() const { return !Source.isNull(); }
+
+private:
+ llvm::PointerUnion<const Decl *, const Stmt *> Source;
+};
+
+using SourceMap = std::vector<std::pair<unsigned, SourceInfo>>;
+
+/// Interface for classes which map locations to sources.
+class SourceMapper {
+public:
+ virtual ~SourceMapper() {}
+
+ /// Returns source information for a given PC in a function.
+ virtual SourceInfo getSource(Function *F, CodePtr PC) const = 0;
+
+ /// Returns the expression if an opcode belongs to one, null otherwise.
+ const Expr *getExpr(Function *F, CodePtr PC) const;
+ /// Returns the location from which an opcode originates.
+ SourceLocation getLocation(Function *F, CodePtr PC) const;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/State.cpp b/contrib/llvm-project/clang/lib/AST/Interp/State.cpp
new file mode 100644
index 000000000000..692cc2e8d69b
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/State.cpp
@@ -0,0 +1,158 @@
+//===--- State.cpp - State chain for the VM and AST Walker ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "State.h"
+#include "Frame.h"
+#include "Program.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+State::~State() {}
+
+OptionalDiagnostic State::FFDiag(SourceLocation Loc, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ return diag(Loc, DiagId, ExtraNotes, false);
+}
+
+OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ if (getEvalStatus().Diag)
+ return diag(E->getExprLoc(), DiagId, ExtraNotes, false);
+ setActiveDiagnostic(false);
+ return OptionalDiagnostic();
+}
+
+OptionalDiagnostic State::FFDiag(const SourceInfo &SI, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ if (getEvalStatus().Diag)
+ return diag(SI.getLoc(), DiagId, ExtraNotes, false);
+ setActiveDiagnostic(false);
+ return OptionalDiagnostic();
+}
+
+OptionalDiagnostic State::CCEDiag(SourceLocation Loc, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ // Don't override a previous diagnostic. Don't bother collecting
+ // diagnostics if we're evaluating for overflow.
+ if (!getEvalStatus().Diag || !getEvalStatus().Diag->empty()) {
+ setActiveDiagnostic(false);
+ return OptionalDiagnostic();
+ }
+ return diag(Loc, DiagId, ExtraNotes, true);
+}
+
+OptionalDiagnostic State::CCEDiag(const Expr *E, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
+}
+
+OptionalDiagnostic State::CCEDiag(const SourceInfo &SI, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ return CCEDiag(SI.getLoc(), DiagId, ExtraNotes);
+}
+
+OptionalDiagnostic State::Note(SourceLocation Loc, diag::kind DiagId) {
+ if (!hasActiveDiagnostic())
+ return OptionalDiagnostic();
+ return OptionalDiagnostic(&addDiag(Loc, DiagId));
+}
+
+void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
+ if (hasActiveDiagnostic()) {
+ getEvalStatus().Diag->insert(getEvalStatus().Diag->end(), Diags.begin(),
+ Diags.end());
+ }
+}
+
+DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) {
+ return getCtx().getDiagnostics().Report(Loc, DiagId);
+}
+
+/// Add a diagnostic to the diagnostics list.
+PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) {
+ PartialDiagnostic PD(DiagId, getCtx().getDiagAllocator());
+ getEvalStatus().Diag->push_back(std::make_pair(Loc, PD));
+ return getEvalStatus().Diag->back().second;
+}
+
+OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId,
+ unsigned ExtraNotes, bool IsCCEDiag) {
+ Expr::EvalStatus &EvalStatus = getEvalStatus();
+ if (EvalStatus.Diag) {
+ if (hasPriorDiagnostic()) {
+ return OptionalDiagnostic();
+ }
+
+ unsigned CallStackNotes = getCallStackDepth() - 1;
+ unsigned Limit = getCtx().getDiagnostics().getConstexprBacktraceLimit();
+ if (Limit)
+ CallStackNotes = std::min(CallStackNotes, Limit + 1);
+ if (checkingPotentialConstantExpression())
+ CallStackNotes = 0;
+
+ setActiveDiagnostic(true);
+ setFoldFailureDiagnostic(!IsCCEDiag);
+ EvalStatus.Diag->clear();
+ EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
+ addDiag(Loc, DiagId);
+ if (!checkingPotentialConstantExpression()) {
+ addCallStack(Limit);
+ }
+ return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
+ }
+ setActiveDiagnostic(false);
+ return OptionalDiagnostic();
+}
+
+const LangOptions &State::getLangOpts() const { return getCtx().getLangOpts(); }
+
+void State::addCallStack(unsigned Limit) {
+ // Determine which calls to skip, if any.
+ unsigned ActiveCalls = getCallStackDepth() - 1;
+ unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart;
+ if (Limit && Limit < ActiveCalls) {
+ SkipStart = Limit / 2 + Limit % 2;
+ SkipEnd = ActiveCalls - Limit / 2;
+ }
+
+ // Walk the call stack and add the diagnostics.
+ unsigned CallIdx = 0;
+ Frame *Top = getCurrentFrame();
+ const Frame *Bottom = getBottomFrame();
+ for (Frame *F = Top; F != Bottom; F = F->getCaller(), ++CallIdx) {
+ SourceLocation CallLocation = F->getCallLocation();
+
+ // Skip this call?
+ if (CallIdx >= SkipStart && CallIdx < SkipEnd) {
+ if (CallIdx == SkipStart) {
+ // Note that we're skipping calls.
+ addDiag(CallLocation, diag::note_constexpr_calls_suppressed)
+ << unsigned(ActiveCalls - Limit);
+ }
+ continue;
+ }
+
+ // Use a different note for an inheriting constructor, because from the
+ // user's perspective it's not really a function at all.
+ if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(F->getCallee())) {
+ if (CD->isInheritingConstructor()) {
+ addDiag(CallLocation, diag::note_constexpr_inherited_ctor_call_here)
+ << CD->getParent();
+ continue;
+ }
+ }
+
+ SmallVector<char, 128> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ F->describe(Out);
+ addDiag(CallLocation, diag::note_constexpr_call_here) << Out.str();
+ }
+}
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/State.h b/contrib/llvm-project/clang/lib/AST/Interp/State.h
new file mode 100644
index 000000000000..d9a645a3eb3e
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/AST/Interp/State.h
@@ -0,0 +1,133 @@
+//===--- State.h - State chain for the VM and AST Walker --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the base class of the interpreter and evaluator state.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_STATE_H
+#define LLVM_CLANG_AST_INTERP_STATE_H
+
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/OptionalDiagnostic.h"
+
+namespace clang {
+
+/// Kinds of access we can perform on an object, for diagnostics. Note that
+/// we consider a member function call to be a kind of access, even though
+/// it is not formally an access of the object, because it has (largely) the
+/// same set of semantic restrictions.
+enum AccessKinds {
+ AK_Read,
+ AK_ReadObjectRepresentation,
+ AK_Assign,
+ AK_Increment,
+ AK_Decrement,
+ AK_MemberCall,
+ AK_DynamicCast,
+ AK_TypeId,
+ AK_Construct,
+ AK_Destroy,
+};
+
+// The order of this enum is important for diagnostics.
+enum CheckSubobjectKind {
+ CSK_Base,
+ CSK_Derived,
+ CSK_Field,
+ CSK_ArrayToPointer,
+ CSK_ArrayIndex,
+ CSK_Real,
+ CSK_Imag
+};
+
+namespace interp {
+class Frame;
+class SourceInfo;
+
+/// Interface for the VM to interact with the AST walker's context.
+class State {
+public:
+ virtual ~State();
+
+ virtual bool checkingForUndefinedBehavior() const = 0;
+ virtual bool checkingPotentialConstantExpression() const = 0;
+ virtual bool noteUndefinedBehavior() = 0;
+ virtual bool keepEvaluatingAfterFailure() const = 0;
+ virtual Frame *getCurrentFrame() = 0;
+ virtual const Frame *getBottomFrame() const = 0;
+ virtual bool hasActiveDiagnostic() = 0;
+ virtual void setActiveDiagnostic(bool Flag) = 0;
+ virtual void setFoldFailureDiagnostic(bool Flag) = 0;
+ virtual Expr::EvalStatus &getEvalStatus() const = 0;
+ virtual ASTContext &getCtx() const = 0;
+ virtual bool hasPriorDiagnostic() = 0;
+ virtual unsigned getCallStackDepth() = 0;
+
+public:
+ // Diagnose that the evaluation could not be folded (FF => FoldFailure)
+ OptionalDiagnostic
+ FFDiag(SourceLocation Loc,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ OptionalDiagnostic
+ FFDiag(const Expr *E,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ OptionalDiagnostic
+ FFDiag(const SourceInfo &SI,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ /// Diagnose that the evaluation does not produce a C++11 core constant
+ /// expression.
+ ///
+ /// FIXME: Stop evaluating if we're in EM_ConstantExpression or
+ /// EM_PotentialConstantExpression mode and we produce one of these.
+ OptionalDiagnostic
+ CCEDiag(SourceLocation Loc,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ OptionalDiagnostic
+ CCEDiag(const Expr *E,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ OptionalDiagnostic
+ CCEDiag(const SourceInfo &SI,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ /// Add a note to a prior diagnostic.
+ OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId);
+
+ /// Add a stack of notes to a prior diagnostic.
+ void addNotes(ArrayRef<PartialDiagnosticAt> Diags);
+
+ /// Directly reports a diagnostic message.
+ DiagnosticBuilder report(SourceLocation Loc, diag::kind DiagId);
+
+ const LangOptions &getLangOpts() const;
+
+private:
+ void addCallStack(unsigned Limit);
+
+ PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId);
+
+ OptionalDiagnostic diag(SourceLocation Loc, diag::kind DiagId,
+ unsigned ExtraNotes, bool IsCCEDiag);
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/AST/ItaniumCXXABI.cpp b/contrib/llvm-project/clang/lib/AST/ItaniumCXXABI.cpp
index 77fb5a1d33b3..069add8464ae 100644
--- a/contrib/llvm-project/clang/lib/AST/ItaniumCXXABI.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ItaniumCXXABI.cpp
@@ -19,10 +19,12 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Mangle.h"
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/iterator.h"
using namespace clang;
@@ -73,10 +75,33 @@ struct DecompositionDeclName {
}
namespace llvm {
+template<typename T> bool isDenseMapKeyEmpty(T V) {
+ return llvm::DenseMapInfo<T>::isEqual(
+ V, llvm::DenseMapInfo<T>::getEmptyKey());
+}
+template<typename T> bool isDenseMapKeyTombstone(T V) {
+ return llvm::DenseMapInfo<T>::isEqual(
+ V, llvm::DenseMapInfo<T>::getTombstoneKey());
+}
+
+template<typename T>
+Optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) {
+ bool LHSEmpty = isDenseMapKeyEmpty(LHS);
+ bool RHSEmpty = isDenseMapKeyEmpty(RHS);
+ if (LHSEmpty || RHSEmpty)
+ return LHSEmpty && RHSEmpty;
+
+ bool LHSTombstone = isDenseMapKeyTombstone(LHS);
+ bool RHSTombstone = isDenseMapKeyTombstone(RHS);
+ if (LHSTombstone || RHSTombstone)
+ return LHSTombstone && RHSTombstone;
+
+ return None;
+}
+
template<>
struct DenseMapInfo<DecompositionDeclName> {
using ArrayInfo = llvm::DenseMapInfo<ArrayRef<const BindingDecl*>>;
- using IdentInfo = llvm::DenseMapInfo<const IdentifierInfo*>;
static DecompositionDeclName getEmptyKey() {
return {ArrayInfo::getEmptyKey()};
}
@@ -88,10 +113,10 @@ struct DenseMapInfo<DecompositionDeclName> {
return llvm::hash_combine_range(Key.begin(), Key.end());
}
static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName RHS) {
- if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getEmptyKey()))
- return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getEmptyKey());
- if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getTombstoneKey()))
- return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getTombstoneKey());
+ if (Optional<bool> Result = areDenseMapKeysEqualSpecialValues(
+ LHS.Bindings, RHS.Bindings))
+ return *Result;
+
return LHS.Bindings.size() == RHS.Bindings.size() &&
std::equal(LHS.begin(), LHS.end(), RHS.begin());
}
@@ -103,29 +128,32 @@ namespace {
/// Keeps track of the mangled names of lambda expressions and block
/// literals within a particular context.
class ItaniumNumberingContext : public MangleNumberingContext {
- llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
+ ItaniumMangleContext *Mangler;
+ llvm::StringMap<unsigned> LambdaManglingNumbers;
+ unsigned BlockManglingNumber = 0;
llvm::DenseMap<const IdentifierInfo *, unsigned> VarManglingNumbers;
llvm::DenseMap<const IdentifierInfo *, unsigned> TagManglingNumbers;
llvm::DenseMap<DecompositionDeclName, unsigned>
DecompsitionDeclManglingNumbers;
public:
+ ItaniumNumberingContext(ItaniumMangleContext *Mangler) : Mangler(Mangler) {}
+
unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
- const FunctionProtoType *Proto =
- CallOperator->getType()->getAs<FunctionProtoType>();
- ASTContext &Context = CallOperator->getASTContext();
+ const CXXRecordDecl *Lambda = CallOperator->getParent();
+ assert(Lambda->isLambda());
+
+ // Computation of the <lambda-sig> is non-trivial and subtle. Rather than
+ // duplicating it here, just mangle the <lambda-sig> directly.
+ llvm::SmallString<128> LambdaSig;
+ llvm::raw_svector_ostream Out(LambdaSig);
+ Mangler->mangleLambdaSig(Lambda, Out);
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.Variadic = Proto->isVariadic();
- QualType Key =
- Context.getFunctionType(Context.VoidTy, Proto->getParamTypes(), EPI);
- Key = Context.getCanonicalType(Key);
- return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
+ return ++LambdaManglingNumbers[LambdaSig];
}
unsigned getManglingNumber(const BlockDecl *BD) override {
- const Type *Ty = nullptr;
- return ++ManglingNumbers[Ty];
+ return ++BlockManglingNumber;
}
unsigned getStaticLocalNumber(const VarDecl *VD) override {
@@ -154,10 +182,13 @@ public:
};
class ItaniumCXXABI : public CXXABI {
+private:
+ std::unique_ptr<MangleContext> Mangler;
protected:
ASTContext &Context;
public:
- ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { }
+ ItaniumCXXABI(ASTContext &Ctx)
+ : Mangler(Ctx.createMangleContext()), Context(Ctx) {}
MemberPointerInfo
getMemberPointerInfo(const MemberPointerType *MPT) const override {
@@ -218,7 +249,8 @@ public:
std::unique_ptr<MangleNumberingContext>
createMangleNumberingContext() const override {
- return llvm::make_unique<ItaniumNumberingContext>();
+ return std::make_unique<ItaniumNumberingContext>(
+ cast<ItaniumMangleContext>(Mangler.get()));
}
};
}
diff --git a/contrib/llvm-project/clang/lib/AST/ItaniumMangle.cpp b/contrib/llvm-project/clang/lib/AST/ItaniumMangle.cpp
index 6c813f09a4b3..5d485e000750 100644
--- a/contrib/llvm-project/clang/lib/AST/ItaniumMangle.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ItaniumMangle.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
@@ -170,6 +171,8 @@ public:
void mangleStringLiteral(const StringLiteral *, raw_ostream &) override;
+ void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) override;
+
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
// Lambda closure types are already numbered.
if (isLambda(ND))
@@ -424,6 +427,7 @@ public:
void mangleName(const NamedDecl *ND);
void mangleType(QualType T);
void mangleNameOrStandardSubstitution(const NamedDecl *ND);
+ void mangleLambdaSig(const CXXRecordDecl *Lambda);
private:
@@ -513,7 +517,7 @@ private:
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T);
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
void mangleType(const TagType*);
void mangleType(TemplateName);
@@ -550,7 +554,7 @@ private:
void mangleTemplateArgs(const TemplateArgumentList &AL);
void mangleTemplateArg(TemplateArgument A);
- void mangleTemplateParameter(unsigned Index);
+ void mangleTemplateParameter(unsigned Depth, unsigned Index);
void mangleFunctionParam(const ParmVarDecl *parm);
@@ -965,8 +969,8 @@ void CXXNameMangler::mangleUnscopedTemplateName(
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
assert(!AdditionalAbiTags &&
"template template param cannot have abi tags");
- mangleTemplateParameter(TTP->getIndex());
- } else if (isa<BuiltinTemplateDecl>(ND)) {
+ mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
+ } else if (isa<BuiltinTemplateDecl>(ND) || isa<ConceptDecl>(ND)) {
mangleUnscopedName(ND, AdditionalAbiTags);
} else {
mangleUnscopedName(ND->getTemplatedDecl(), AdditionalAbiTags);
@@ -1321,7 +1325,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
// We must have an anonymous union or struct declaration.
- const RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl();
+ const RecordDecl *RD = VD->getType()->castAs<RecordType>()->getDecl();
// Itanium C++ ABI 5.1.2:
//
@@ -1685,17 +1689,45 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
// ::= Ty # template type parameter
// ::= Tn <type> # template non-type parameter
// ::= Tt <template-param-decl>* E # template template parameter
+// ::= Tp <template-param-decl> # template parameter pack
void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
- if (isa<TemplateTypeParmDecl>(Decl)) {
+ if (auto *Ty = dyn_cast<TemplateTypeParmDecl>(Decl)) {
+ if (Ty->isParameterPack())
+ Out << "Tp";
Out << "Ty";
} else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) {
- Out << "Tn";
- mangleType(Tn->getType());
+ if (Tn->isExpandedParameterPack()) {
+ for (unsigned I = 0, N = Tn->getNumExpansionTypes(); I != N; ++I) {
+ Out << "Tn";
+ mangleType(Tn->getExpansionType(I));
+ }
+ } else {
+ QualType T = Tn->getType();
+ if (Tn->isParameterPack()) {
+ Out << "Tp";
+ if (auto *PackExpansion = T->getAs<PackExpansionType>())
+ T = PackExpansion->getPattern();
+ }
+ Out << "Tn";
+ mangleType(T);
+ }
} else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) {
- Out << "Tt";
- for (auto *Param : *Tt->getTemplateParameters())
- mangleTemplateParamDecl(Param);
- Out << "E";
+ if (Tt->isExpandedParameterPack()) {
+ for (unsigned I = 0, N = Tt->getNumExpansionTemplateParameters(); I != N;
+ ++I) {
+ Out << "Tt";
+ for (auto *Param : *Tt->getExpansionTemplateParameters(I))
+ mangleTemplateParamDecl(Param);
+ Out << "E";
+ }
+ } else {
+ if (Tt->isParameterPack())
+ Out << "Tp";
+ Out << "Tt";
+ for (auto *Param : *Tt->getTemplateParameters())
+ mangleTemplateParamDecl(Param);
+ Out << "E";
+ }
}
}
@@ -1726,12 +1758,7 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
}
Out << "Ul";
- for (auto *D : Lambda->getLambdaExplicitTemplateParameters())
- mangleTemplateParamDecl(D);
- const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
- getAs<FunctionProtoType>();
- mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
- Lambda->getLambdaStaticInvoker());
+ mangleLambdaSig(Lambda);
Out << "E";
// The number is omitted for the first closure type with a given
@@ -1746,6 +1773,15 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
Out << '_';
}
+void CXXNameMangler::mangleLambdaSig(const CXXRecordDecl *Lambda) {
+ for (auto *D : Lambda->getLambdaExplicitTemplateParameters())
+ mangleTemplateParamDecl(D);
+ const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
+ getAs<FunctionProtoType>();
+ mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
+ Lambda->getLambdaStaticInvoker());
+}
+
void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
switch (qualifier->getKind()) {
case NestedNameSpecifier::Global:
@@ -1852,10 +1888,10 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND,
// <template-template-param> ::= <template-param>
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
- mangleTemplateParameter(TTP->getIndex());
+ mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
} else {
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
- if (isa<BuiltinTemplateDecl>(ND))
+ if (isa<BuiltinTemplateDecl>(ND) || isa<ConceptDecl>(ND))
mangleUnqualifiedName(ND, nullptr);
else
mangleUnqualifiedName(ND->getTemplatedDecl(), nullptr);
@@ -1885,8 +1921,8 @@ void CXXNameMangler::mangleType(TemplateName TN) {
goto HaveDecl;
HaveDecl:
- if (isa<TemplateTemplateParmDecl>(TD))
- mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex());
+ if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TD))
+ mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
else
mangleName(TD);
break;
@@ -2266,6 +2302,16 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp
case LangAS::cuda_device: ASString = "CUdevice"; break;
case LangAS::cuda_constant: ASString = "CUconstant"; break;
case LangAS::cuda_shared: ASString = "CUshared"; break;
+ // <ptrsize-addrspace> ::= [ "ptr32_sptr" | "ptr32_uptr" | "ptr64" ]
+ case LangAS::ptr32_sptr:
+ ASString = "ptr32_sptr";
+ break;
+ case LangAS::ptr32_uptr:
+ ASString = "ptr32_uptr";
+ break;
+ case LangAS::ptr64:
+ ASString = "ptr64";
+ break;
}
}
if (!ASString.empty())
@@ -2464,7 +2510,7 @@ void CXXNameMangler::mangleType(QualType T) {
case Type::CLASS: \
mangleType(static_cast<const CLASS##Type*>(ty)); \
break;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
}
@@ -2671,6 +2717,15 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
Out << type_name.size() << type_name; \
break;
#include "clang/Basic/OpenCLExtensionTypes.def"
+ // The SVE types are effectively target-specific. The mangling scheme
+ // is defined in the appendices to the Procedure Call Standard for the
+ // Arm Architecture.
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id: \
+ type_name = Name; \
+ Out << 'u' << type_name.size() << type_name; \
+ break;
+#include "clang/Basic/AArch64SVEACLETypes.def"
}
}
@@ -2955,7 +3010,7 @@ void CXXNameMangler::mangleType(const MemberPointerType *T) {
// <type> ::= <template-param>
void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
- mangleTemplateParameter(T->getIndex());
+ mangleTemplateParameter(T->getDepth(), T->getIndex());
}
// <type> ::= <template-param>
@@ -3526,7 +3581,7 @@ void CXXNameMangler::mangleDeclRefExpr(const NamedDecl *D) {
case Decl::NonTypeTemplateParm:
const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
- mangleTemplateParameter(PD->getIndex());
+ mangleTemplateParameter(PD->getDepth(), PD->getIndex());
break;
}
}
@@ -3614,6 +3669,7 @@ recurse:
case Expr::ConvertVectorExprClass:
case Expr::StmtExprClass:
case Expr::TypeTraitExprClass:
+ case Expr::RequiresExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::VAArgExprClass:
@@ -4046,6 +4102,17 @@ recurse:
break;
}
+ case Expr::CXXRewrittenBinaryOperatorClass: {
+ // The mangled form represents the original syntax.
+ CXXRewrittenBinaryOperator::DecomposedForm Decomposed =
+ cast<CXXRewrittenBinaryOperator>(E)->getDecomposedForm();
+ mangleOperatorName(BinaryOperator::getOverloadedOperator(Decomposed.Opcode),
+ /*Arity=*/2);
+ mangleExpression(Decomposed.LHS);
+ mangleExpression(Decomposed.RHS);
+ break;
+ }
+
case Expr::ConditionalOperatorClass: {
const ConditionalOperator *CO = cast<ConditionalOperator>(E);
mangleOperatorName(OO_Conditional, /*Arity=*/3);
@@ -4123,6 +4190,18 @@ recurse:
mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity);
break;
+
+ case Expr::ConceptSpecializationExprClass: {
+ // <expr-primary> ::= L <mangled-name> E # external name
+ Out << "L_Z";
+ auto *CSE = cast<ConceptSpecializationExpr>(E);
+ mangleTemplateName(CSE->getNamedConcept(),
+ CSE->getTemplateArguments().data(),
+ CSE->getTemplateArguments().size());
+ Out << 'E';
+ break;
+ }
+
case Expr::DeclRefExprClass:
mangleDeclRefExpr(cast<DeclRefExpr>(E)->getDecl());
break;
@@ -4229,8 +4308,11 @@ recurse:
}
case Expr::GNUNullExprClass:
- // FIXME: should this really be mangled the same as nullptr?
- // fallthrough
+ // Mangle as if an integer literal 0.
+ Out << 'L';
+ mangleType(E->getType());
+ Out << "0E";
+ break;
case Expr::CXXNullPtrLiteralExprClass: {
Out << "LDnE";
@@ -4255,20 +4337,20 @@ recurse:
Out << "sZ";
const NamedDecl *Pack = SPE->getPack();
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
- mangleTemplateParameter(TTP->getIndex());
+ mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
else if (const NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Pack))
- mangleTemplateParameter(NTTP->getIndex());
+ mangleTemplateParameter(NTTP->getDepth(), NTTP->getIndex());
else if (const TemplateTemplateParmDecl *TempTP
= dyn_cast<TemplateTemplateParmDecl>(Pack))
- mangleTemplateParameter(TempTP->getIndex());
+ mangleTemplateParameter(TempTP->getDepth(), TempTP->getIndex());
else
mangleFunctionParam(cast<ParmVarDecl>(Pack));
break;
}
case Expr::MaterializeTemporaryExprClass: {
- mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr());
+ mangleExpression(cast<MaterializeTemporaryExpr>(E)->getSubExpr());
break;
}
@@ -4548,13 +4630,21 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
}
}
-void CXXNameMangler::mangleTemplateParameter(unsigned Index) {
+void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) {
// <template-param> ::= T_ # first template parameter
// ::= T <parameter-2 non-negative number> _
- if (Index == 0)
- Out << "T_";
- else
- Out << 'T' << (Index - 1) << '_';
+ // ::= TL <L-1 non-negative number> __
+ // ::= TL <L-1 non-negative number> _
+ // <parameter-2 non-negative number> _
+ //
+ // The latter two manglings are from a proposal here:
+ // https://github.com/itanium-cxx-abi/cxx-abi/issues/31#issuecomment-528122117
+ Out << 'T';
+ if (Depth != 0)
+ Out << 'L' << (Depth - 1) << '_';
+ if (Index != 0)
+ Out << (Index - 1);
+ Out << '_';
}
void CXXNameMangler::mangleSeqID(unsigned SeqID) {
@@ -5071,6 +5161,12 @@ void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_os
llvm_unreachable("Can't mangle string literals");
}
+void ItaniumMangleContextImpl::mangleLambdaSig(const CXXRecordDecl *Lambda,
+ raw_ostream &Out) {
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.mangleLambdaSig(Lambda);
+}
+
ItaniumMangleContext *
ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
return new ItaniumMangleContextImpl(Context, Diags);
diff --git a/contrib/llvm-project/clang/lib/AST/JSONNodeDumper.cpp b/contrib/llvm-project/clang/lib/AST/JSONNodeDumper.cpp
index 04b933b0fb30..c30b07137edc 100644
--- a/contrib/llvm-project/clang/lib/AST/JSONNodeDumper.cpp
+++ b/contrib/llvm-project/clang/lib/AST/JSONNodeDumper.cpp
@@ -66,6 +66,10 @@ void JSONNodeDumper::Visit(const Stmt *S) {
void JSONNodeDumper::Visit(const Type *T) {
JOS.attribute("id", createPointerRepresentation(T));
+
+ if (!T)
+ return;
+
JOS.attribute("kind", (llvm::Twine(T->getTypeClassName()) + "Type").str());
JOS.attribute("type", createQualType(QualType(T, 0), /*Desugar*/ false));
attributeOnlyIfTrue("isDependent", T->isDependentType());
@@ -107,9 +111,14 @@ void JSONNodeDumper::Visit(const Decl *D) {
if (const auto *ND = dyn_cast<NamedDecl>(D))
attributeOnlyIfTrue("isHidden", ND->isHidden());
- if (D->getLexicalDeclContext() != D->getDeclContext())
- JOS.attribute("parentDeclContext",
- createPointerRepresentation(D->getDeclContext()));
+ if (D->getLexicalDeclContext() != D->getDeclContext()) {
+ // Because of multiple inheritance, a DeclContext pointer does not produce
+ // the same pointer representation as a Decl pointer that references the
+ // same AST Node.
+ const auto *ParentDeclContextDecl = dyn_cast<Decl>(D->getDeclContext());
+ JOS.attribute("parentDeclContextId",
+ createPointerRepresentation(ParentDeclContextDecl));
+ }
addPreviousDeclaration(D);
InnerDeclVisitor::Visit(D);
@@ -171,18 +180,42 @@ void JSONNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) {
attributeOnlyIfTrue("selected", A.isSelected());
}
+void JSONNodeDumper::writeIncludeStack(PresumedLoc Loc, bool JustFirst) {
+ if (Loc.isInvalid())
+ return;
+
+ JOS.attributeBegin("includedFrom");
+ JOS.objectBegin();
+
+ if (!JustFirst) {
+ // Walk the stack recursively, then print out the presumed location.
+ writeIncludeStack(SM.getPresumedLoc(Loc.getIncludeLoc()));
+ }
+
+ JOS.attribute("file", Loc.getFilename());
+ JOS.objectEnd();
+ JOS.attributeEnd();
+}
+
void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc,
bool IsSpelling) {
PresumedLoc Presumed = SM.getPresumedLoc(Loc);
unsigned ActualLine = IsSpelling ? SM.getSpellingLineNumber(Loc)
: SM.getExpansionLineNumber(Loc);
+ StringRef ActualFile = SM.getBufferName(Loc);
+
if (Presumed.isValid()) {
- if (LastLocFilename != Presumed.getFilename()) {
- JOS.attribute("file", Presumed.getFilename());
+ JOS.attribute("offset", SM.getDecomposedLoc(Loc).second);
+ if (LastLocFilename != ActualFile) {
+ JOS.attribute("file", ActualFile);
JOS.attribute("line", ActualLine);
} else if (LastLocLine != ActualLine)
JOS.attribute("line", ActualLine);
+ StringRef PresumedFile = Presumed.getFilename();
+ if (PresumedFile != ActualFile && LastLocPresumedFilename != PresumedFile)
+ JOS.attribute("presumedFile", PresumedFile);
+
unsigned PresumedLine = Presumed.getLine();
if (ActualLine != PresumedLine && LastLocPresumedLine != PresumedLine)
JOS.attribute("presumedLine", PresumedLine);
@@ -190,9 +223,16 @@ void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc,
JOS.attribute("col", Presumed.getColumn());
JOS.attribute("tokLen",
Lexer::MeasureTokenLength(Loc, SM, Ctx.getLangOpts()));
- LastLocFilename = Presumed.getFilename();
+ LastLocFilename = ActualFile;
+ LastLocPresumedFilename = PresumedFile;
LastLocPresumedLine = PresumedLine;
LastLocLine = ActualLine;
+
+ // Orthogonal to the file, line, and column de-duplication is whether the
+ // given location was a result of an include. If so, print where the
+ // include location came from.
+ writeIncludeStack(SM.getPresumedLoc(Presumed.getIncludeLoc()),
+ /*JustFirst*/ true);
}
}
@@ -238,6 +278,8 @@ llvm::json::Object JSONNodeDumper::createQualType(QualType QT, bool Desugar) {
SplitQualType DSQT = QT.getSplitDesugaredType();
if (DSQT != SQT)
Ret["desugaredQualType"] = QualType::getAsString(DSQT, PrintPolicy);
+ if (const auto *TT = QT->getAs<TypedefType>())
+ Ret["typeAliasDeclId"] = createPointerRepresentation(TT->getDecl());
}
return Ret;
}
@@ -275,7 +317,7 @@ llvm::json::Array JSONNodeDumper::createCastPath(const CastExpr *C) {
for (auto I = C->path_begin(), E = C->path_end(); I != E; ++I) {
const CXXBaseSpecifier *Base = *I;
const auto *RD =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl());
llvm::json::Object Val{{"name", RD->getName()}};
if (Base->isVirtual())
@@ -653,8 +695,12 @@ void JSONNodeDumper::VisitMemberPointerType(const MemberPointerType *MPT) {
}
void JSONNodeDumper::VisitNamedDecl(const NamedDecl *ND) {
- if (ND && ND->getDeclName())
+ if (ND && ND->getDeclName()) {
JOS.attribute("name", ND->getNameAsString());
+ std::string MangledName = ASTNameGen.getName(ND);
+ if (!MangledName.empty())
+ JOS.attribute("mangledName", MangledName);
+ }
}
void JSONNodeDumper::VisitTypedefDecl(const TypedefDecl *TD) {
@@ -972,6 +1018,7 @@ void JSONNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
attributeOnlyIfTrue("unsafe_unretained",
Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
attributeOnlyIfTrue("class", Attrs & ObjCPropertyDecl::OBJC_PR_class);
+ attributeOnlyIfTrue("direct", Attrs & ObjCPropertyDecl::OBJC_PR_direct);
attributeOnlyIfTrue("nullability",
Attrs & ObjCPropertyDecl::OBJC_PR_nullability);
attributeOnlyIfTrue("null_resettable",
@@ -1471,6 +1518,9 @@ void JSONNodeDumper::visitInlineCommandComment(
case comments::InlineCommandComment::RenderMonospaced:
JOS.attribute("renderKind", "monospaced");
break;
+ case comments::InlineCommandComment::RenderAnchor:
+ JOS.attribute("renderKind", "anchor");
+ break;
}
llvm::json::Array Args;
diff --git a/contrib/llvm-project/clang/lib/AST/Mangle.cpp b/contrib/llvm-project/clang/lib/AST/Mangle.cpp
index 625282368a4d..e106b31f59f0 100644
--- a/contrib/llvm-project/clang/lib/AST/Mangle.cpp
+++ b/contrib/llvm-project/clang/lib/AST/Mangle.cpp
@@ -63,9 +63,7 @@ static CCMangling getCallingConvMangling(const ASTContext &Context,
const NamedDecl *ND) {
const TargetInfo &TI = Context.getTargetInfo();
const llvm::Triple &Triple = TI.getTriple();
- if (!Triple.isOSWindows() ||
- !(Triple.getArch() == llvm::Triple::x86 ||
- Triple.getArch() == llvm::Triple::x86_64))
+ if (!Triple.isOSWindows() || !Triple.isX86())
return CCM_Other;
if (Context.getLangOpts().CPlusPlus && !isExternC(ND) &&
@@ -122,15 +120,21 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
// If we have an asm name, then we use it as the mangling.
+ // If the label isn't literal, or if this is an alias for an LLVM intrinsic,
+ // do not add a "\01" prefix.
+ if (!ALA->getIsLiteralLabel() || ALA->getLabel().startswith("llvm.")) {
+ Out << ALA->getLabel();
+ return;
+ }
+
// Adding the prefix can cause problems when one file has a "foo" and
// another has a "\01foo". That is known to happen on ELF with the
// tricks normally used for producing aliases (PR9177). Fortunately the
// llvm mangler on ELF is a nop, so we can just avoid adding the \01
- // marker. We also avoid adding the marker if this is an alias for an
- // LLVM intrinsic.
+ // marker.
char GlobalPrefix =
getASTContext().getTargetInfo().getDataLayout().getGlobalPrefix();
- if (GlobalPrefix && !ALA->getLabel().startswith("llvm."))
+ if (GlobalPrefix)
Out << '\01'; // LLVM IR Marker for __asm("foo")
Out << ALA->getLabel();
@@ -380,7 +384,7 @@ public:
auto hasDefaultCXXMethodCC = [](ASTContext &C, const CXXMethodDecl *MD) {
auto DefaultCC = C.getDefaultCallingConvention(/*IsVariadic=*/false,
/*IsCXXMethod=*/true);
- auto CC = MD->getType()->getAs<FunctionProtoType>()->getCallConv();
+ auto CC = MD->getType()->castAs<FunctionProtoType>()->getCallConv();
return CC == DefaultCC;
};
@@ -470,7 +474,7 @@ private:
};
ASTNameGenerator::ASTNameGenerator(ASTContext &Ctx)
- : Impl(llvm::make_unique<Implementation>(Ctx)) {}
+ : Impl(std::make_unique<Implementation>(Ctx)) {}
ASTNameGenerator::~ASTNameGenerator() {}
diff --git a/contrib/llvm-project/clang/lib/AST/MicrosoftCXXABI.cpp b/contrib/llvm-project/clang/lib/AST/MicrosoftCXXABI.cpp
index 444e55f777fa..f9f9fe985b6f 100644
--- a/contrib/llvm-project/clang/lib/AST/MicrosoftCXXABI.cpp
+++ b/contrib/llvm-project/clang/lib/AST/MicrosoftCXXABI.cpp
@@ -14,6 +14,7 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
@@ -132,7 +133,7 @@ public:
std::unique_ptr<MangleNumberingContext>
createMangleNumberingContext() const override {
- return llvm::make_unique<MicrosoftNumberingContext>();
+ return std::make_unique<MicrosoftNumberingContext>();
}
};
}
@@ -154,27 +155,32 @@ static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
return false;
}
-MSInheritanceAttr::Spelling CXXRecordDecl::calculateInheritanceModel() const {
+MSInheritanceModel CXXRecordDecl::calculateInheritanceModel() const {
if (!hasDefinition() || isParsingBaseSpecifiers())
- return MSInheritanceAttr::Keyword_unspecified_inheritance;
+ return MSInheritanceModel::Unspecified;
if (getNumVBases() > 0)
- return MSInheritanceAttr::Keyword_virtual_inheritance;
+ return MSInheritanceModel::Virtual;
if (usesMultipleInheritanceModel(this))
- return MSInheritanceAttr::Keyword_multiple_inheritance;
- return MSInheritanceAttr::Keyword_single_inheritance;
+ return MSInheritanceModel::Multiple;
+ return MSInheritanceModel::Single;
}
-MSInheritanceAttr::Spelling
-CXXRecordDecl::getMSInheritanceModel() const {
+MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const {
MSInheritanceAttr *IA = getAttr<MSInheritanceAttr>();
assert(IA && "Expected MSInheritanceAttr on the CXXRecordDecl!");
- return IA->getSemanticSpelling();
+ return IA->getInheritanceModel();
}
-MSVtorDispAttr::Mode CXXRecordDecl::getMSVtorDispMode() const {
+bool CXXRecordDecl::nullFieldOffsetIsZero() const {
+ return !inheritanceModelHasOnlyOneField(/*IsMemberFunction=*/false,
+ getMSInheritanceModel()) ||
+ (hasDefinition() && isPolymorphic());
+}
+
+MSVtorDispMode CXXRecordDecl::getMSVtorDispMode() const {
if (MSVtorDispAttr *VDA = getAttr<MSVtorDispAttr>())
return VDA->getVtorDispMode();
- return MSVtorDispAttr::Mode(getASTContext().getLangOpts().VtorDispMode);
+ return getASTContext().getLangOpts().getVtorDispMode();
}
// Returns the number of pointer and integer slots used to represent a member
@@ -209,19 +215,19 @@ MSVtorDispAttr::Mode CXXRecordDecl::getMSVtorDispMode() const {
static std::pair<unsigned, unsigned>
getMSMemberPointerSlots(const MemberPointerType *MPT) {
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
unsigned Ptrs = 0;
unsigned Ints = 0;
if (MPT->isMemberFunctionPointer())
Ptrs = 1;
else
Ints = 1;
- if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
+ if (inheritanceModelHasNVOffsetField(MPT->isMemberFunctionPointer(),
Inheritance))
Ints++;
- if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
+ if (inheritanceModelHasVBPtrOffsetField(Inheritance))
Ints++;
- if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
+ if (inheritanceModelHasVBTableOffsetField(Inheritance))
Ints++;
return std::make_pair(Ptrs, Ints);
}
diff --git a/contrib/llvm-project/clang/lib/AST/MicrosoftMangle.cpp b/contrib/llvm-project/clang/lib/AST/MicrosoftMangle.cpp
index 5e9358e24fc9..a286c5335584 100644
--- a/contrib/llvm-project/clang/lib/AST/MicrosoftMangle.cpp
+++ b/contrib/llvm-project/clang/lib/AST/MicrosoftMangle.cpp
@@ -27,11 +27,11 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/JamCRC.h"
-#include "llvm/Support/xxhash.h"
+#include "llvm/Support/CRC.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/xxhash.h"
using namespace clang;
@@ -279,8 +279,6 @@ class MicrosoftCXXNameMangler {
ASTContext &getASTContext() const { return Context.getASTContext(); }
- // FIXME: If we add support for __ptr32/64 qualifiers, then we should push
- // this check into mangleQualifiers().
const bool PointersAre64Bit;
public:
@@ -335,6 +333,13 @@ private:
return ND == Structor || getStructor(ND) == Structor;
}
+ bool is64BitPointer(Qualifiers Quals) const {
+ LangAS AddrSpace = Quals.getAddressSpace();
+ return AddrSpace == LangAS::ptr64 ||
+ (PointersAre64Bit && !(AddrSpace == LangAS::ptr32_sptr ||
+ AddrSpace == LangAS::ptr32_uptr));
+ }
+
void mangleUnqualifiedName(const NamedDecl *ND) {
mangleUnqualifiedName(ND, ND->getDeclName());
}
@@ -364,7 +369,7 @@ private:
#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T, \
Qualifiers Quals, \
SourceRange Range);
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
#undef ABSTRACT_TYPE
#undef NON_CANONICAL_TYPE
#undef TYPE
@@ -592,7 +597,7 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
int64_t FieldOffset;
int64_t VBTableOffset;
- MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel();
+ MSInheritanceModel IM = RD->getMSInheritanceModel();
if (VD) {
FieldOffset = getASTContext().getFieldOffset(VD);
assert(FieldOffset % getASTContext().getCharWidth() == 0 &&
@@ -601,7 +606,7 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
VBTableOffset = 0;
- if (IM == MSInheritanceAttr::Keyword_virtual_inheritance)
+ if (IM == MSInheritanceModel::Virtual)
FieldOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity();
} else {
FieldOffset = RD->nullFieldOffsetIsZero() ? 0 : -1;
@@ -611,10 +616,10 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
char Code = '\0';
switch (IM) {
- case MSInheritanceAttr::Keyword_single_inheritance: Code = '0'; break;
- case MSInheritanceAttr::Keyword_multiple_inheritance: Code = '0'; break;
- case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'F'; break;
- case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'G'; break;
+ case MSInheritanceModel::Single: Code = '0'; break;
+ case MSInheritanceModel::Multiple: Code = '0'; break;
+ case MSInheritanceModel::Virtual: Code = 'F'; break;
+ case MSInheritanceModel::Unspecified: Code = 'G'; break;
}
Out << '$' << Code;
@@ -624,9 +629,9 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
// The C++ standard doesn't allow base-to-derived member pointer conversions
// in template parameter contexts, so the vbptr offset of data member pointers
// is always zero.
- if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
+ if (inheritanceModelHasVBPtrOffsetField(IM))
mangleNumber(0);
- if (MSInheritanceAttr::hasVBTableOffsetField(IM))
+ if (inheritanceModelHasVBTableOffsetField(IM))
mangleNumber(VBTableOffset);
}
@@ -638,14 +643,14 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
// ::= $I? <name> <number> <number>
// ::= $J? <name> <number> <number> <number>
- MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel();
+ MSInheritanceModel IM = RD->getMSInheritanceModel();
char Code = '\0';
switch (IM) {
- case MSInheritanceAttr::Keyword_single_inheritance: Code = '1'; break;
- case MSInheritanceAttr::Keyword_multiple_inheritance: Code = 'H'; break;
- case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'I'; break;
- case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'J'; break;
+ case MSInheritanceModel::Single: Code = '1'; break;
+ case MSInheritanceModel::Multiple: Code = 'H'; break;
+ case MSInheritanceModel::Virtual: Code = 'I'; break;
+ case MSInheritanceModel::Unspecified: Code = 'J'; break;
}
// If non-virtual, mangle the name. If virtual, mangle as a virtual memptr
@@ -672,25 +677,24 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
mangleFunctionEncoding(MD, /*ShouldMangle=*/true);
}
- if (VBTableOffset == 0 &&
- IM == MSInheritanceAttr::Keyword_virtual_inheritance)
+ if (VBTableOffset == 0 && IM == MSInheritanceModel::Virtual)
NVOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity();
} else {
// Null single inheritance member functions are encoded as a simple nullptr.
- if (IM == MSInheritanceAttr::Keyword_single_inheritance) {
+ if (IM == MSInheritanceModel::Single) {
Out << "$0A@";
return;
}
- if (IM == MSInheritanceAttr::Keyword_unspecified_inheritance)
+ if (IM == MSInheritanceModel::Unspecified)
VBTableOffset = -1;
Out << '$' << Code;
}
- if (MSInheritanceAttr::hasNVOffsetField(/*IsMemberFunction=*/true, IM))
+ if (inheritanceModelHasNVOffsetField(/*IsMemberFunction=*/true, IM))
mangleNumber(static_cast<uint32_t>(NVOffset));
- if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
+ if (inheritanceModelHasVBPtrOffsetField(IM))
mangleNumber(VBPtrOffset);
- if (MSInheritanceAttr::hasVBTableOffsetField(IM))
+ if (inheritanceModelHasVBTableOffsetField(IM))
mangleNumber(VBTableOffset);
}
@@ -706,7 +710,7 @@ void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk(
Out << "$B";
mangleNumber(OffsetInVFTable);
Out << 'A';
- mangleCallingConvention(MD->getType()->getAs<FunctionProtoType>());
+ mangleCallingConvention(MD->getType()->castAs<FunctionProtoType>());
}
void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
@@ -842,7 +846,7 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
TemplateArgStringStorage.save(TemplateMangling.str());
}
} else {
- Out << Found->second; // Outputs a StringRef.
+ Out << Found->second << '@'; // Outputs a StringRef.
}
} else {
Out << Found->second; // Outputs a back reference (an int).
@@ -868,16 +872,11 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
}
if (const DecompositionDecl *DD = dyn_cast<DecompositionDecl>(ND)) {
- // FIXME: Invented mangling for decomposition declarations:
- // [X,Y,Z]
- // where X,Y,Z are the names of the bindings.
- llvm::SmallString<128> Name("[");
- for (auto *BD : DD->bindings()) {
- if (Name.size() > 1)
- Name += ',';
- Name += BD->getDeclName().getAsIdentifierInfo()->getName();
- }
- Name += ']';
+ // Decomposition declarations are considered anonymous, and get
+ // numbered with a $S prefix.
+ llvm::SmallString<64> Name("$S");
+ // Get a unique id for the anonymous struct.
+ Name += llvm::utostr(Context.getAnonymousStructId(DD) + 1);
mangleSourceName(Name);
break;
}
@@ -1709,8 +1708,10 @@ MicrosoftCXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
void MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals,
QualType PointeeType) {
- if (PointersAre64Bit &&
- (PointeeType.isNull() || !PointeeType->isFunctionType()))
+ // Check if this is a default 64-bit pointer or has __ptr64 qualifier.
+ bool is64Bit = PointeeType.isNull() ? PointersAre64Bit :
+ is64BitPointer(PointeeType.getQualifiers());
+ if (is64Bit && (PointeeType.isNull() || !PointeeType->isFunctionType()))
Out << 'E';
if (Quals.hasRestrict())
@@ -1870,6 +1871,10 @@ void MicrosoftCXXNameMangler::mangleAddressSpaceType(QualType T,
case LangAS::cuda_shared:
Extra.mangleSourceName("_ASCUshared");
break;
+ case LangAS::ptr32_sptr:
+ case LangAS::ptr32_uptr:
+ case LangAS::ptr64:
+ llvm_unreachable("don't mangle ptr address spaces with _AS");
}
}
@@ -1942,7 +1947,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
case Type::CLASS: \
mangleType(cast<CLASS##Type>(ty), Quals, Range); \
break;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
#undef ABSTRACT_TYPE
#undef NON_CANONICAL_TYPE
#undef TYPE
@@ -2109,6 +2114,9 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
mangleArtificialTagType(TTK_Struct, "_Half", {"__clang"});
break;
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::ShortAccum:
case BuiltinType::Accum:
case BuiltinType::LongAccum:
@@ -2600,10 +2608,13 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Qualifiers Quals,
manglePointerCVQualifiers(Quals);
manglePointerExtQualifiers(Quals, PointeeType);
- if (PointeeType.getQualifiers().hasAddressSpace())
- mangleAddressSpaceType(PointeeType, PointeeType.getQualifiers(), Range);
- else
+ // For pointer size address spaces, go down the same type mangling path as
+ // non address space types.
+ LangAS AddrSpace = PointeeType.getQualifiers().getAddressSpace();
+ if (isPtrSizeAddressSpace(AddrSpace) || AddrSpace == LangAS::Default)
mangleType(PointeeType, Range);
+ else
+ mangleAddressSpaceType(PointeeType, PointeeType.getQualifiers(), Range);
}
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
@@ -2690,9 +2701,7 @@ void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals,
// doesn't match the Intel types uses a custom mangling below.
size_t OutSizeBefore = Out.tell();
if (!isa<ExtVectorType>(T)) {
- llvm::Triple::ArchType AT =
- getASTContext().getTargetInfo().getTriple().getArch();
- if (AT == llvm::Triple::x86 || AT == llvm::Triple::x86_64) {
+ if (getASTContext().getTargetInfo().getTriple().isX86()) {
if (Width == 64 && ET->getKind() == BuiltinType::LongLong) {
mangleArtificialTagType(TTK_Union, "__m64");
} else if (Width >= 128) {
diff --git a/contrib/llvm-project/clang/lib/AST/NSAPI.cpp b/contrib/llvm-project/clang/lib/AST/NSAPI.cpp
index 5104dc59d621..ae6ff04f5126 100644
--- a/contrib/llvm-project/clang/lib/AST/NSAPI.cpp
+++ b/contrib/llvm-project/clang/lib/AST/NSAPI.cpp
@@ -75,17 +75,6 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
return NSStringSelectors[MK];
}
-Optional<NSAPI::NSStringMethodKind>
-NSAPI::getNSStringMethodKind(Selector Sel) const {
- for (unsigned i = 0; i != NumNSStringMethods; ++i) {
- NSStringMethodKind MK = NSStringMethodKind(i);
- if (Sel == getNSStringSelector(MK))
- return MK;
- }
-
- return None;
-}
-
Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
if (NSArraySelectors[MK].isNull()) {
Selector Sel;
@@ -482,6 +471,9 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::BoundMember:
case BuiltinType::Dependent:
case BuiltinType::Overload:
diff --git a/contrib/llvm-project/clang/lib/AST/NestedNameSpecifier.cpp b/contrib/llvm-project/clang/lib/AST/NestedNameSpecifier.cpp
index 09d85102585b..137953fa8203 100644
--- a/contrib/llvm-project/clang/lib/AST/NestedNameSpecifier.cpp
+++ b/contrib/llvm-project/clang/lib/AST/NestedNameSpecifier.cpp
@@ -472,7 +472,7 @@ TypeLoc NestedNameSpecifierLoc::getTypeLoc() const {
}
static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
- unsigned &BufferCapacity) {
+ unsigned &BufferCapacity) {
if (Start == End)
return;
@@ -489,9 +489,9 @@ static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
Buffer = NewBuffer;
BufferCapacity = NewCapacity;
}
-
+ assert(Buffer && Start && End && End > Start && "Illegal memory buffer copy");
memcpy(Buffer + BufferSize, Start, End - Start);
- BufferSize += End-Start;
+ BufferSize += End - Start;
}
/// Save a source location to the given buffer.
diff --git a/contrib/llvm-project/clang/lib/AST/ODRHash.cpp b/contrib/llvm-project/clang/lib/AST/ODRHash.cpp
index 3b89c630b451..1f9ff9e407dc 100644
--- a/contrib/llvm-project/clang/lib/AST/ODRHash.cpp
+++ b/contrib/llvm-project/clang/lib/AST/ODRHash.cpp
@@ -380,6 +380,11 @@ public:
}
Hash.AddBoolean(D->isParameterPack());
+ const TypeConstraint *TC = D->getTypeConstraint();
+ Hash.AddBoolean(TC != nullptr);
+ if (TC)
+ AddStmt(TC->getImmediatelyDeclaredConstraint());
+
Inherited::VisitTemplateTypeParmDecl(D);
}
@@ -852,6 +857,13 @@ public:
void VisitAutoType(const AutoType *T) {
ID.AddInteger((unsigned)T->getKeyword());
+ ID.AddInteger(T->isConstrained());
+ if (T->isConstrained()) {
+ AddDecl(T->getTypeConstraintConcept());
+ ID.AddInteger(T->getNumArgs());
+ for (const auto &TA : T->getTypeConstraintArguments())
+ Hash.AddTemplateArgument(TA);
+ }
VisitDeducedType(T);
}
diff --git a/contrib/llvm-project/clang/lib/AST/OpenMPClause.cpp b/contrib/llvm-project/clang/lib/AST/OpenMPClause.cpp
index 9d8a7ebc3023..5ef82648c89d 100644
--- a/contrib/llvm-project/clang/lib/AST/OpenMPClause.cpp
+++ b/contrib/llvm-project/clang/lib/AST/OpenMPClause.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/OpenMPKinds.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
@@ -43,6 +44,8 @@ OMPClause::child_range OMPClause::used_children() {
#include "clang/Basic/OpenMPKinds.def"
case OMPC_threadprivate:
case OMPC_uniform:
+ case OMPC_device_type:
+ case OMPC_match:
case OMPC_unknown:
break;
}
@@ -82,9 +85,16 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
return static_cast<const OMPThreadLimitClause *>(C);
case OMPC_device:
return static_cast<const OMPDeviceClause *>(C);
+ case OMPC_grainsize:
+ return static_cast<const OMPGrainsizeClause *>(C);
+ case OMPC_num_tasks:
+ return static_cast<const OMPNumTasksClause *>(C);
+ case OMPC_final:
+ return static_cast<const OMPFinalClause *>(C);
+ case OMPC_priority:
+ return static_cast<const OMPPriorityClause *>(C);
case OMPC_default:
case OMPC_proc_bind:
- case OMPC_final:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_allocator:
@@ -110,10 +120,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
- case OMPC_priority:
- case OMPC_grainsize:
case OMPC_nogroup:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_defaultmap:
case OMPC_unknown:
@@ -127,6 +134,9 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
+ case OMPC_nontemporal:
break;
}
@@ -203,6 +213,9 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
+ case OMPC_nontemporal:
break;
}
@@ -228,6 +241,30 @@ OMPClause::child_range OMPIfClause::used_children() {
return child_range(&Condition, &Condition + 1);
}
+OMPClause::child_range OMPGrainsizeClause::used_children() {
+ if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
+ return child_range(C, C + 1);
+ return child_range(&Grainsize, &Grainsize + 1);
+}
+
+OMPClause::child_range OMPNumTasksClause::used_children() {
+ if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
+ return child_range(C, C + 1);
+ return child_range(&NumTasks, &NumTasks + 1);
+}
+
+OMPClause::child_range OMPFinalClause::used_children() {
+ if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
+ return child_range(C, C + 1);
+ return child_range(&Condition, &Condition + 1);
+}
+
+OMPClause::child_range OMPPriorityClause::used_children() {
+ if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
+ return child_range(C, C + 1);
+ return child_range(&Priority, &Priority + 1);
+}
+
OMPOrderedClause *OMPOrderedClause::Create(const ASTContext &C, Expr *Num,
unsigned NumLoops,
SourceLocation StartLoc,
@@ -368,11 +405,12 @@ void OMPLastprivateClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) {
OMPLastprivateClause *OMPLastprivateClause::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
- ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps, Stmt *PreInit,
- Expr *PostUpdate) {
+ ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps,
+ OpenMPLastprivateModifier LPKind, SourceLocation LPKindLoc,
+ SourceLocation ColonLoc, Stmt *PreInit, Expr *PostUpdate) {
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size()));
- OMPLastprivateClause *Clause =
- new (Mem) OMPLastprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
+ OMPLastprivateClause *Clause = new (Mem) OMPLastprivateClause(
+ StartLoc, LParenLoc, EndLoc, LPKind, LPKindLoc, ColonLoc, VL.size());
Clause->setVarRefs(VL);
Clause->setSourceExprs(SrcExprs);
Clause->setDestinationExprs(DstExprs);
@@ -429,15 +467,23 @@ void OMPLinearClause::setFinals(ArrayRef<Expr *> FL) {
std::copy(FL.begin(), FL.end(), getUpdates().end());
}
+void OMPLinearClause::setUsedExprs(ArrayRef<Expr *> UE) {
+ assert(
+ UE.size() == varlist_size() + 1 &&
+ "Number of used expressions is not the same as the preallocated buffer");
+ std::copy(UE.begin(), UE.end(), getFinals().end() + 2);
+}
+
OMPLinearClause *OMPLinearClause::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
OpenMPLinearClauseKind Modifier, SourceLocation ModifierLoc,
SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
ArrayRef<Expr *> PL, ArrayRef<Expr *> IL, Expr *Step, Expr *CalcStep,
Stmt *PreInit, Expr *PostUpdate) {
- // Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions
- // (Step and CalcStep).
- void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size() + 2));
+ // Allocate space for 5 lists (Vars, Inits, Updates, Finals), 2 expressions
+ // (Step and CalcStep), list of used expression + step.
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size() + 2 + VL.size() + 1));
OMPLinearClause *Clause = new (Mem) OMPLinearClause(
StartLoc, LParenLoc, Modifier, ModifierLoc, ColonLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -449,6 +495,8 @@ OMPLinearClause *OMPLinearClause::Create(
nullptr);
std::fill(Clause->getUpdates().end(), Clause->getUpdates().end() + VL.size(),
nullptr);
+ std::fill(Clause->getUsedExprs().begin(), Clause->getUsedExprs().end(),
+ nullptr);
Clause->setStep(Step);
Clause->setCalcStep(CalcStep);
Clause->setPreInitStmt(PreInit);
@@ -458,12 +506,19 @@ OMPLinearClause *OMPLinearClause::Create(
OMPLinearClause *OMPLinearClause::CreateEmpty(const ASTContext &C,
unsigned NumVars) {
- // Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions
- // (Step and CalcStep).
- void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * NumVars + 2));
+ // Allocate space for 5 lists (Vars, Inits, Updates, Finals), 2 expressions
+ // (Step and CalcStep), list of used expression + step.
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * NumVars + 2 + NumVars +1));
return new (Mem) OMPLinearClause(NumVars);
}
+OMPClause::child_range OMPLinearClause::used_children() {
+ // Range includes only non-nullptr elements.
+ return child_range(
+ reinterpret_cast<Stmt **>(getUsedExprs().begin()),
+ reinterpret_cast<Stmt **>(llvm::find(getUsedExprs(), nullptr)));
+}
+
OMPAlignedClause *
OMPAlignedClause::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation ColonLoc,
@@ -1104,13 +1159,38 @@ OMPIsDevicePtrClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPIsDevicePtrClause(Sizes);
}
+OMPNontemporalClause *OMPNontemporalClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ // Allocate space for nontemporal variables + private references.
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * VL.size()));
+ auto *Clause =
+ new (Mem) OMPNontemporalClause(StartLoc, LParenLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPNontemporalClause *OMPNontemporalClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * N));
+ return new (Mem) OMPNontemporalClause(N);
+}
+
+void OMPNontemporalClause::setPrivateRefs(ArrayRef<Expr *> VL) {
+ assert(VL.size() == varlist_size() && "Number of private references is not "
+ "the same as the preallocated buffer");
+ std::copy(VL.begin(), VL.end(), varlist_end());
+}
+
//===----------------------------------------------------------------------===//
// OpenMP clauses printing methods
//===----------------------------------------------------------------------===//
void OMPClausePrinter::VisitOMPIfClause(OMPIfClause *Node) {
OS << "if(";
- if (Node->getNameModifier() != OMPD_unknown)
+ if (Node->getNameModifier() != llvm::omp::OMPD_unknown)
OS << getOpenMPDirectiveName(Node->getNameModifier()) << ": ";
Node->getCondition()->printPretty(OS, nullptr, Policy, 0);
OS << ")";
@@ -1160,7 +1240,8 @@ void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) {
void OMPClausePrinter::VisitOMPProcBindClause(OMPProcBindClause *Node) {
OS << "proc_bind("
- << getOpenMPSimpleClauseTypeName(OMPC_proc_bind, Node->getProcBindKind())
+ << getOpenMPSimpleClauseTypeName(OMPC_proc_bind,
+ unsigned(Node->getProcBindKind()))
<< ")";
}
@@ -1350,7 +1431,13 @@ void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) {
void OMPClausePrinter::VisitOMPLastprivateClause(OMPLastprivateClause *Node) {
if (!Node->varlist_empty()) {
OS << "lastprivate";
- VisitOMPClauseList(Node, '(');
+ OpenMPLastprivateModifier LPKind = Node->getKind();
+ if (LPKind != OMPC_LASTPRIVATE_unknown) {
+ OS << "("
+ << getOpenMPSimpleClauseTypeName(OMPC_lastprivate, Node->getKind())
+ << ":";
+ }
+ VisitOMPClauseList(Node, LPKind == OMPC_LASTPRIVATE_unknown ? '(' : ' ');
OS << ")";
}
}
@@ -1597,3 +1684,10 @@ void OMPClausePrinter::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *Node) {
}
}
+void OMPClausePrinter::VisitOMPNontemporalClause(OMPNontemporalClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "nontemporal";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
diff --git a/contrib/llvm-project/clang/lib/AST/PrintfFormatString.cpp b/contrib/llvm-project/clang/lib/AST/PrintfFormatString.cpp
index a1207aae5aa2..bae60d464407 100644
--- a/contrib/llvm-project/clang/lib/AST/PrintfFormatString.cpp
+++ b/contrib/llvm-project/clang/lib/AST/PrintfFormatString.cpp
@@ -463,6 +463,23 @@ bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
return false;
}
+bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers(
+ const char *Begin, const char *End, const LangOptions &LO,
+ const TargetInfo &Target) {
+ unsigned ArgIndex = 0;
+ // Keep looking for a formatting specifier until we have exhausted the string.
+ FormatStringHandler H;
+ while (Begin != End) {
+ const PrintfSpecifierResult &FSR =
+ ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false);
+ if (FSR.shouldStop())
+ break;
+ if (FSR.hasValue())
+ return true;
+ }
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Methods on PrintfSpecifier.
//===----------------------------------------------------------------------===//
@@ -769,6 +786,9 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
#define SIGNED_TYPE(Id, SingletonId)
#define UNSIGNED_TYPE(Id, SingletonId)
#define FLOATING_TYPE(Id, SingletonId)
diff --git a/contrib/llvm-project/clang/lib/AST/QualTypeNames.cpp b/contrib/llvm-project/clang/lib/AST/QualTypeNames.cpp
index f28f00171cce..73a33a208233 100644
--- a/contrib/llvm-project/clang/lib/AST/QualTypeNames.cpp
+++ b/contrib/llvm-project/clang/lib/AST/QualTypeNames.cpp
@@ -192,7 +192,7 @@ static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
// Ignore inline namespace;
NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
}
- if (NS->getDeclName()) {
+ if (NS && NS->getDeclName()) {
return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
}
return nullptr; // no starting '::', no anonymous
diff --git a/contrib/llvm-project/clang/lib/AST/RawCommentList.cpp b/contrib/llvm-project/clang/lib/AST/RawCommentList.cpp
index df53b7fa1004..83e8a0b942a4 100644
--- a/contrib/llvm-project/clang/lib/AST/RawCommentList.cpp
+++ b/contrib/llvm-project/clang/lib/AST/RawCommentList.cpp
@@ -275,27 +275,25 @@ void RawCommentList::addComment(const RawComment &RC,
if (RC.isInvalid())
return;
- // Check if the comments are not in source order.
- while (!Comments.empty() &&
- !SourceMgr.isBeforeInTranslationUnit(Comments.back()->getBeginLoc(),
- RC.getBeginLoc())) {
- // If they are, just pop a few last comments that don't fit.
- // This happens if an \#include directive contains comments.
- Comments.pop_back();
- }
-
// Ordinary comments are not interesting for us.
if (RC.isOrdinary() && !CommentOpts.ParseAllComments)
return;
+ std::pair<FileID, unsigned> Loc =
+ SourceMgr.getDecomposedLoc(RC.getBeginLoc());
+
+ const FileID CommentFile = Loc.first;
+ const unsigned CommentOffset = Loc.second;
+
// If this is the first Doxygen comment, save it (because there isn't
// anything to merge it with).
- if (Comments.empty()) {
- Comments.push_back(new (Allocator) RawComment(RC));
+ if (OrderedComments[CommentFile].empty()) {
+ OrderedComments[CommentFile][CommentOffset] =
+ new (Allocator) RawComment(RC);
return;
}
- const RawComment &C1 = *Comments.back();
+ const RawComment &C1 = *OrderedComments[CommentFile].rbegin()->second;
const RawComment &C2 = RC;
// Merge comments only if there is only whitespace between them.
@@ -318,21 +316,43 @@ void RawCommentList::addComment(const RawComment &RC,
onlyWhitespaceBetween(SourceMgr, C1.getEndLoc(), C2.getBeginLoc(),
/*MaxNewlinesAllowed=*/1)) {
SourceRange MergedRange(C1.getBeginLoc(), C2.getEndLoc());
- *Comments.back() = RawComment(SourceMgr, MergedRange, CommentOpts, true);
+ *OrderedComments[CommentFile].rbegin()->second =
+ RawComment(SourceMgr, MergedRange, CommentOpts, true);
} else {
- Comments.push_back(new (Allocator) RawComment(RC));
+ OrderedComments[CommentFile][CommentOffset] =
+ new (Allocator) RawComment(RC);
}
}
-void RawCommentList::addDeserializedComments(ArrayRef<RawComment *> DeserializedComments) {
- std::vector<RawComment *> MergedComments;
- MergedComments.reserve(Comments.size() + DeserializedComments.size());
+const std::map<unsigned, RawComment *> *
+RawCommentList::getCommentsInFile(FileID File) const {
+ auto CommentsInFile = OrderedComments.find(File);
+ if (CommentsInFile == OrderedComments.end())
+ return nullptr;
+
+ return &CommentsInFile->second;
+}
+
+bool RawCommentList::empty() const { return OrderedComments.empty(); }
+
+unsigned RawCommentList::getCommentBeginLine(RawComment *C, FileID File,
+ unsigned Offset) const {
+ auto Cached = CommentBeginLine.find(C);
+ if (Cached != CommentBeginLine.end())
+ return Cached->second;
+ const unsigned Line = SourceMgr.getLineNumber(File, Offset);
+ CommentBeginLine[C] = Line;
+ return Line;
+}
- std::merge(Comments.begin(), Comments.end(),
- DeserializedComments.begin(), DeserializedComments.end(),
- std::back_inserter(MergedComments),
- BeforeThanCompare<RawComment>(SourceMgr));
- std::swap(Comments, MergedComments);
+unsigned RawCommentList::getCommentEndOffset(RawComment *C) const {
+ auto Cached = CommentEndOffset.find(C);
+ if (Cached != CommentEndOffset.end())
+ return Cached->second;
+ const unsigned Offset =
+ SourceMgr.getDecomposedLoc(C->getSourceRange().getEnd()).second;
+ CommentEndOffset[C] = Offset;
+ return Offset;
}
std::string RawComment::getFormattedText(const SourceManager &SourceMgr,
diff --git a/contrib/llvm-project/clang/lib/AST/RecordLayoutBuilder.cpp b/contrib/llvm-project/clang/lib/AST/RecordLayoutBuilder.cpp
index 2a3419a0cec3..9a21732b63e3 100644
--- a/contrib/llvm-project/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/contrib/llvm-project/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2956,7 +2956,7 @@ void MicrosoftRecordLayoutBuilder::computeVtorDispSet(
const CXXRecordDecl *RD) const {
// /vd2 or #pragma vtordisp(2): Always use vtordisps for virtual bases with
// vftables.
- if (RD->getMSVtorDispMode() == MSVtorDispAttr::ForVFTable) {
+ if (RD->getMSVtorDispMode() == MSVtorDispMode::ForVFTable) {
for (const CXXBaseSpecifier &Base : RD->vbases()) {
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
@@ -2979,12 +2979,12 @@ void MicrosoftRecordLayoutBuilder::computeVtorDispSet(
// * A user declared constructor or destructor aren't declared.
// * #pragma vtordisp(0) or the /vd0 flag are in use.
if ((!RD->hasUserDeclaredConstructor() && !RD->hasUserDeclaredDestructor()) ||
- RD->getMSVtorDispMode() == MSVtorDispAttr::Never)
+ RD->getMSVtorDispMode() == MSVtorDispMode::Never)
return;
// /vd1 or #pragma vtordisp(1): Try to guess based on whether we think it's
// possible for a partially constructed object with virtual base overrides to
// escape a non-trivial constructor.
- assert(RD->getMSVtorDispMode() == MSVtorDispAttr::ForVBaseOverride);
+ assert(RD->getMSVtorDispMode() == MSVtorDispMode::ForVBaseOverride);
// Compute a set of base classes which define methods we override. A virtual
// base in this set will require a vtordisp. A virtual base that transitively
// contains one of these bases as a non-virtual base will also require a
diff --git a/contrib/llvm-project/clang/lib/AST/Stmt.cpp b/contrib/llvm-project/clang/lib/AST/Stmt.cpp
index 0a4d403106bd..7409ae7ddc9e 100644
--- a/contrib/llvm-project/clang/lib/AST/Stmt.cpp
+++ b/contrib/llvm-project/clang/lib/AST/Stmt.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
@@ -41,6 +42,7 @@
#include <cstring>
#include <string>
#include <utility>
+#include <type_traits>
using namespace clang;
@@ -83,6 +85,16 @@ const char *Stmt::getStmtClassName() const {
#CLASS " should not be polymorphic!");
#include "clang/AST/StmtNodes.inc"
+// Check that no statement / expression class has a non-trival destructor.
+// Statements and expressions are allocated with the BumpPtrAllocator from
+// ASTContext and therefore their destructor is not executed.
+#define STMT(CLASS, PARENT) \
+ static_assert(std::is_trivially_destructible<CLASS>::value, \
+ #CLASS " should be trivially destructible!");
+// FIXME: InitListExpr is not trivially destructible due to its ASTVector.
+#define INITLISTEXPR(CLASS, PARENT)
+#include "clang/AST/StmtNodes.inc"
+
void Stmt::PrintStats() {
// Ensure the table is primed.
getStmtInfoTableEntry(Stmt::NullStmtClass);
@@ -897,6 +909,12 @@ bool IfStmt::isObjCAvailabilityCheck() const {
return isa<ObjCAvailabilityCheckExpr>(getCond());
}
+Optional<const Stmt*> IfStmt::getNondiscardedCase(const ASTContext &Ctx) const {
+ if (!isConstexpr() || getCond()->isValueDependent())
+ return None;
+ return !getCond()->EvaluateKnownConstInt(Ctx) ? getElse() : getThen();
+}
+
ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
SourceLocation RP)
diff --git a/contrib/llvm-project/clang/lib/AST/StmtOpenMP.cpp b/contrib/llvm-project/clang/lib/AST/StmtOpenMP.cpp
index 4e829897cebe..da6d308ad15b 100644
--- a/contrib/llvm-project/clang/lib/AST/StmtOpenMP.cpp
+++ b/contrib/llvm-project/clang/lib/AST/StmtOpenMP.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
using namespace clang;
+using namespace llvm::omp;
void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) {
assert(Clauses.size() == getNumClauses() &&
@@ -41,6 +42,74 @@ const Stmt *OMPExecutableDirective::getStructuredBlock() const {
return getInnermostCapturedStmt()->getCapturedStmt();
}
+Stmt *OMPLoopDirective::tryToFindNextInnerLoop(Stmt *CurStmt,
+ bool TryImperfectlyNestedLoops) {
+ Stmt *OrigStmt = CurStmt;
+ CurStmt = CurStmt->IgnoreContainers();
+ // Additional work for imperfectly nested loops, introduced in OpenMP 5.0.
+ if (TryImperfectlyNestedLoops) {
+ if (auto *CS = dyn_cast<CompoundStmt>(CurStmt)) {
+ CurStmt = nullptr;
+ SmallVector<CompoundStmt *, 4> Statements(1, CS);
+ SmallVector<CompoundStmt *, 4> NextStatements;
+ while (!Statements.empty()) {
+ CS = Statements.pop_back_val();
+ if (!CS)
+ continue;
+ for (Stmt *S : CS->body()) {
+ if (!S)
+ continue;
+ if (isa<ForStmt>(S) || isa<CXXForRangeStmt>(S)) {
+ // Only single loop construct is allowed.
+ if (CurStmt) {
+ CurStmt = OrigStmt;
+ break;
+ }
+ CurStmt = S;
+ continue;
+ }
+ S = S->IgnoreContainers();
+ if (auto *InnerCS = dyn_cast_or_null<CompoundStmt>(S))
+ NextStatements.push_back(InnerCS);
+ }
+ if (Statements.empty()) {
+ // Found single inner loop or multiple loops - exit.
+ if (CurStmt)
+ break;
+ Statements.swap(NextStatements);
+ }
+ }
+ if (!CurStmt)
+ CurStmt = OrigStmt;
+ }
+ }
+ return CurStmt;
+}
+
+Stmt *OMPLoopDirective::getBody() {
+ // This relies on the loop form is already checked by Sema.
+ Stmt *Body =
+ getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
+ if (auto *For = dyn_cast<ForStmt>(Body)) {
+ Body = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(Body) &&
+ "Expected canonical for loop or range-based for loop.");
+ Body = cast<CXXForRangeStmt>(Body)->getBody();
+ }
+ for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) {
+ Body = tryToFindNextInnerLoop(Body, /*TryImperfectlyNestedLoops=*/true);
+ if (auto *For = dyn_cast<ForStmt>(Body)) {
+ Body = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(Body) &&
+ "Expected canonical for loop or range-based for loop.");
+ Body = cast<CXXForRangeStmt>(Body)->getBody();
+ }
+ }
+ return Body;
+}
+
void OMPLoopDirective::setCounters(ArrayRef<Expr *> A) {
assert(A.size() == getCollapsedNumber() &&
"Number of loop counters is not the same as the collapsed number");
@@ -72,6 +141,25 @@ void OMPLoopDirective::setFinals(ArrayRef<Expr *> A) {
std::copy(A.begin(), A.end(), getFinals().begin());
}
+void OMPLoopDirective::setDependentCounters(ArrayRef<Expr *> A) {
+ assert(
+ A.size() == getCollapsedNumber() &&
+ "Number of dependent counters is not the same as the collapsed number");
+ llvm::copy(A, getDependentCounters().begin());
+}
+
+void OMPLoopDirective::setDependentInits(ArrayRef<Expr *> A) {
+ assert(A.size() == getCollapsedNumber() &&
+ "Number of dependent inits is not the same as the collapsed number");
+ llvm::copy(A, getDependentInits().begin());
+}
+
+void OMPLoopDirective::setFinalsConditions(ArrayRef<Expr *> A) {
+ assert(A.size() == getCollapsedNumber() &&
+ "Number of finals conditions is not the same as the collapsed number");
+ llvm::copy(A, getFinalsConditions().begin());
+}
+
OMPParallelDirective *OMPParallelDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, bool HasCancel) {
@@ -122,6 +210,9 @@ OMPSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -170,6 +261,9 @@ OMPForDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setHasCancel(HasCancel);
return Dir;
@@ -220,6 +314,9 @@ OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -383,6 +480,9 @@ OMPParallelForDirective *OMPParallelForDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setHasCancel(HasCancel);
return Dir;
@@ -432,6 +532,9 @@ OMPParallelForSimdDirective *OMPParallelForSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -448,6 +551,30 @@ OMPParallelForSimdDirective::CreateEmpty(const ASTContext &C,
return new (Mem) OMPParallelForSimdDirective(CollapsedNum, NumClauses);
}
+OMPParallelMasterDirective *OMPParallelMasterDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPParallelMasterDirective), alignof(OMPClause *));
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ auto *Dir =
+ new (Mem) OMPParallelMasterDirective(StartLoc, EndLoc, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPParallelMasterDirective *OMPParallelMasterDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPParallelMasterDirective), alignof(OMPClause *));
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPParallelMasterDirective(NumClauses);
+}
+
OMPParallelSectionsDirective *OMPParallelSectionsDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, bool HasCancel) {
@@ -772,6 +899,9 @@ OMPTargetParallelForDirective *OMPTargetParallelForDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setHasCancel(HasCancel);
return Dir;
@@ -914,6 +1044,9 @@ OMPTaskLoopDirective *OMPTaskLoopDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -963,6 +1096,9 @@ OMPTaskLoopSimdDirective *OMPTaskLoopSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -978,6 +1114,224 @@ OMPTaskLoopSimdDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
return new (Mem) OMPTaskLoopSimdDirective(CollapsedNum, NumClauses);
}
+OMPMasterTaskLoopDirective *OMPMasterTaskLoopDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPMasterTaskLoopDirective), alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_master_taskloop));
+ OMPMasterTaskLoopDirective *Dir = new (Mem) OMPMasterTaskLoopDirective(
+ StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setNumIterations(Exprs.NumIterations);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setPrivateCounters(Exprs.PrivateCounters);
+ Dir->setInits(Exprs.Inits);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
+ Dir->setPreInits(Exprs.PreInits);
+ return Dir;
+}
+
+OMPMasterTaskLoopDirective *
+OMPMasterTaskLoopDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum, EmptyShell) {
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPMasterTaskLoopDirective), alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_master_taskloop));
+ return new (Mem) OMPMasterTaskLoopDirective(CollapsedNum, NumClauses);
+}
+
+OMPMasterTaskLoopSimdDirective *OMPMasterTaskLoopSimdDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size = llvm::alignTo(sizeof(OMPMasterTaskLoopSimdDirective),
+ alignof(OMPClause *));
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_master_taskloop_simd));
+ auto *Dir = new (Mem) OMPMasterTaskLoopSimdDirective(
+ StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setNumIterations(Exprs.NumIterations);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setPrivateCounters(Exprs.PrivateCounters);
+ Dir->setInits(Exprs.Inits);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
+ Dir->setPreInits(Exprs.PreInits);
+ return Dir;
+}
+
+OMPMasterTaskLoopSimdDirective *
+OMPMasterTaskLoopSimdDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum, EmptyShell) {
+ unsigned Size = llvm::alignTo(sizeof(OMPMasterTaskLoopSimdDirective),
+ alignof(OMPClause *));
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_master_taskloop_simd));
+ return new (Mem) OMPMasterTaskLoopSimdDirective(CollapsedNum, NumClauses);
+}
+
+OMPParallelMasterTaskLoopDirective *OMPParallelMasterTaskLoopDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelMasterTaskLoopDirective),
+ alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_parallel_master_taskloop));
+ auto *Dir = new (Mem) OMPParallelMasterTaskLoopDirective(
+ StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setNumIterations(Exprs.NumIterations);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setPrivateCounters(Exprs.PrivateCounters);
+ Dir->setInits(Exprs.Inits);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
+ Dir->setPreInits(Exprs.PreInits);
+ return Dir;
+}
+
+OMPParallelMasterTaskLoopDirective *
+OMPParallelMasterTaskLoopDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell) {
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelMasterTaskLoopDirective),
+ alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_parallel_master_taskloop));
+ return new (Mem) OMPParallelMasterTaskLoopDirective(CollapsedNum, NumClauses);
+}
+
+OMPParallelMasterTaskLoopSimdDirective *
+OMPParallelMasterTaskLoopSimdDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelMasterTaskLoopSimdDirective),
+ alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_parallel_master_taskloop_simd));
+ auto *Dir = new (Mem) OMPParallelMasterTaskLoopSimdDirective(
+ StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setNumIterations(Exprs.NumIterations);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setPrivateCounters(Exprs.PrivateCounters);
+ Dir->setInits(Exprs.Inits);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
+ Dir->setPreInits(Exprs.PreInits);
+ return Dir;
+}
+
+OMPParallelMasterTaskLoopSimdDirective *
+OMPParallelMasterTaskLoopSimdDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell) {
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelMasterTaskLoopSimdDirective),
+ alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_parallel_master_taskloop_simd));
+ return new (Mem)
+ OMPParallelMasterTaskLoopSimdDirective(CollapsedNum, NumClauses);
+}
+
OMPDistributeDirective *OMPDistributeDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
@@ -1011,6 +1365,9 @@ OMPDistributeDirective *OMPDistributeDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1089,6 +1446,9 @@ OMPDistributeParallelForDirective *OMPDistributeParallelForDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1157,6 +1517,9 @@ OMPDistributeParallelForSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1219,6 +1582,9 @@ OMPDistributeSimdDirective *OMPDistributeSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1271,6 +1637,9 @@ OMPTargetParallelForSimdDirective *OMPTargetParallelForSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1315,6 +1684,9 @@ OMPTargetSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1363,6 +1735,9 @@ OMPTeamsDistributeDirective *OMPTeamsDistributeDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1414,6 +1789,9 @@ OMPTeamsDistributeSimdDirective *OMPTeamsDistributeSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1471,6 +1849,9 @@ OMPTeamsDistributeParallelForSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1540,6 +1921,9 @@ OMPTeamsDistributeParallelForDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1628,6 +2012,9 @@ OMPTargetTeamsDistributeDirective *OMPTargetTeamsDistributeDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1688,6 +2075,9 @@ OMPTargetTeamsDistributeParallelForDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1761,6 +2151,9 @@ OMPTargetTeamsDistributeParallelForSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1826,6 +2219,9 @@ OMPTargetTeamsDistributeSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
diff --git a/contrib/llvm-project/clang/lib/AST/StmtPrinter.cpp b/contrib/llvm-project/clang/lib/AST/StmtPrinter.cpp
index 46802d765e1f..45fd8ceae8d3 100644
--- a/contrib/llvm-project/clang/lib/AST/StmtPrinter.cpp
+++ b/contrib/llvm-project/clang/lib/AST/StmtPrinter.cpp
@@ -697,7 +697,7 @@ void StmtPrinter::VisitOMPCriticalDirective(OMPCriticalDirective *Node) {
Indent() << "#pragma omp critical";
if (Node->getDirectiveName().getName()) {
OS << " (";
- Node->getDirectiveName().printName(OS);
+ Node->getDirectiveName().printName(OS, Policy);
OS << ")";
}
PrintOMPExecutableDirective(Node);
@@ -714,6 +714,12 @@ void StmtPrinter::VisitOMPParallelForSimdDirective(
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPParallelMasterDirective(
+ OMPParallelMasterDirective *Node) {
+ Indent() << "#pragma omp parallel master";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPParallelSectionsDirective(
OMPParallelSectionsDirective *Node) {
Indent() << "#pragma omp parallel sections";
@@ -823,6 +829,30 @@ void StmtPrinter::VisitOMPTaskLoopSimdDirective(
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPMasterTaskLoopDirective(
+ OMPMasterTaskLoopDirective *Node) {
+ Indent() << "#pragma omp master taskloop";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPMasterTaskLoopSimdDirective(
+ OMPMasterTaskLoopSimdDirective *Node) {
+ Indent() << "#pragma omp master taskloop simd";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPParallelMasterTaskLoopDirective(
+ OMPParallelMasterTaskLoopDirective *Node) {
+ Indent() << "#pragma omp parallel master taskloop";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPParallelMasterTaskLoopSimdDirective(
+ OMPParallelMasterTaskLoopSimdDirective *Node) {
+ Indent() << "#pragma omp parallel master taskloop simd";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) {
Indent() << "#pragma omp distribute";
PrintOMPExecutableDirective(Node);
@@ -1102,7 +1132,7 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
OS << Node->getValue().toString(10, isSigned);
// Emit suffixes. Integer literals are always a builtin integer type.
- switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
+ switch (Node->getType()->castAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for integer literal!");
case BuiltinType::Char_S:
case BuiltinType::Char_U: OS << "i8"; break;
@@ -1123,7 +1153,7 @@ void StmtPrinter::VisitFixedPointLiteral(FixedPointLiteral *Node) {
return;
OS << Node->getValueAsString(/*Radix=*/10);
- switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
+ switch (Node->getType()->castAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for fixed point literal!");
case BuiltinType::ShortFract: OS << "hr"; break;
case BuiltinType::ShortAccum: OS << "hk"; break;
@@ -1152,7 +1182,7 @@ static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node,
return;
// Emit suffixes. Float literals are always a builtin float type.
- switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
+ switch (Node->getType()->castAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for float literal!");
case BuiltinType::Half: break; // FIXME: suffix?
case BuiltinType::Double: break; // no suffix.
@@ -1280,7 +1310,7 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
OS << "_Generic(";
PrintExpr(Node->getControllingExpr());
- for (const GenericSelectionExpr::Association &Assoc : Node->associations()) {
+ for (const GenericSelectionExpr::Association Assoc : Node->associations()) {
OS << ", ";
QualType T = Assoc.getType();
if (T.isNull())
@@ -1679,6 +1709,15 @@ void StmtPrinter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *Node) {
OS << ")";
}
+void StmtPrinter::VisitCXXRewrittenBinaryOperator(
+ CXXRewrittenBinaryOperator *Node) {
+ CXXRewrittenBinaryOperator::DecomposedForm Decomposed =
+ Node->getDecomposedForm();
+ PrintExpr(const_cast<Expr*>(Decomposed.LHS));
+ OS << ' ' << BinaryOperator::getOpcodeStr(Decomposed.Opcode) << ' ';
+ PrintExpr(const_cast<Expr*>(Decomposed.RHS));
+}
+
void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
OS << Node->getCastName() << '<';
Node->getTypeAsWritten().print(OS, Policy);
@@ -1952,7 +1991,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
if (Node->isMutable())
OS << " mutable";
- auto *Proto = Method->getType()->getAs<FunctionProtoType>();
+ auto *Proto = Method->getType()->castAs<FunctionProtoType>();
Proto->printExceptionSpecification(OS, Policy);
// FIXME: Attributes
@@ -2202,7 +2241,7 @@ void StmtPrinter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
}
void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){
- PrintExpr(Node->GetTemporaryExpr());
+ PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) {
@@ -2219,6 +2258,71 @@ void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) {
OS << ")";
}
+void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
+ NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc();
+ if (NNS)
+ NNS.getNestedNameSpecifier()->print(OS, Policy);
+ if (E->getTemplateKWLoc().isValid())
+ OS << "template ";
+ OS << E->getFoundDecl()->getName();
+ printTemplateArgumentList(OS, E->getTemplateArgsAsWritten()->arguments(),
+ Policy);
+}
+
+void StmtPrinter::VisitRequiresExpr(RequiresExpr *E) {
+ OS << "requires ";
+ auto LocalParameters = E->getLocalParameters();
+ if (!LocalParameters.empty()) {
+ OS << "(";
+ for (ParmVarDecl *LocalParam : LocalParameters) {
+ PrintRawDecl(LocalParam);
+ if (LocalParam != LocalParameters.back())
+ OS << ", ";
+ }
+
+ OS << ") ";
+ }
+ OS << "{ ";
+ auto Requirements = E->getRequirements();
+ for (concepts::Requirement *Req : Requirements) {
+ if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) {
+ if (TypeReq->isSubstitutionFailure())
+ OS << "<<error-type>>";
+ else
+ TypeReq->getType()->getType().print(OS, Policy);
+ } else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) {
+ if (ExprReq->isCompound())
+ OS << "{ ";
+ if (ExprReq->isExprSubstitutionFailure())
+ OS << "<<error-expression>>";
+ else
+ PrintExpr(ExprReq->getExpr());
+ if (ExprReq->isCompound()) {
+ OS << " }";
+ if (ExprReq->getNoexceptLoc().isValid())
+ OS << " noexcept";
+ const auto &RetReq = ExprReq->getReturnTypeRequirement();
+ if (!RetReq.isEmpty()) {
+ OS << " -> ";
+ if (RetReq.isSubstitutionFailure())
+ OS << "<<error-type>>";
+ else if (RetReq.isTypeConstraint())
+ RetReq.getTypeConstraint()->print(OS, Policy);
+ }
+ }
+ } else {
+ auto *NestedReq = cast<concepts::NestedRequirement>(Req);
+ OS << "requires ";
+ if (NestedReq->isSubstitutionFailure())
+ OS << "<<error-expression>>";
+ else
+ PrintExpr(NestedReq->getConstraintExpr());
+ }
+ OS << "; ";
+ }
+ OS << "}";
+}
+
// C++ Coroutines TS
void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
diff --git a/contrib/llvm-project/clang/lib/AST/StmtProfile.cpp b/contrib/llvm-project/clang/lib/AST/StmtProfile.cpp
index f92c3dc60ba5..60dec50d53da 100644
--- a/contrib/llvm-project/clang/lib/AST/StmtProfile.cpp
+++ b/contrib/llvm-project/clang/lib/AST/StmtProfile.cpp
@@ -440,6 +440,7 @@ void OMPClauseProfiler::VisitOMPIfClause(const OMPIfClause *C) {
}
void OMPClauseProfiler::VisitOMPFinalClause(const OMPFinalClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getCondition())
Profiler->VisitStmt(C->getCondition());
}
@@ -736,14 +737,17 @@ void OMPClauseProfiler::VisitOMPThreadLimitClause(
Profiler->VisitStmt(C->getThreadLimit());
}
void OMPClauseProfiler::VisitOMPPriorityClause(const OMPPriorityClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getPriority())
Profiler->VisitStmt(C->getPriority());
}
void OMPClauseProfiler::VisitOMPGrainsizeClause(const OMPGrainsizeClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getGrainsize())
Profiler->VisitStmt(C->getGrainsize());
}
void OMPClauseProfiler::VisitOMPNumTasksClause(const OMPNumTasksClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getNumTasks())
Profiler->VisitStmt(C->getNumTasks());
}
@@ -765,7 +769,13 @@ void OMPClauseProfiler::VisitOMPIsDevicePtrClause(
const OMPIsDevicePtrClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseProfiler::VisitOMPNontemporalClause(
+ const OMPNontemporalClause *C) {
+ VisitOMPClauseList(C);
+ for (auto *E : C->private_refs())
+ Profiler->VisitStmt(E);
}
+} // namespace
void
StmtProfiler::VisitOMPExecutableDirective(const OMPExecutableDirective *S) {
@@ -829,6 +839,11 @@ void StmtProfiler::VisitOMPParallelForSimdDirective(
VisitOMPLoopDirective(S);
}
+void StmtProfiler::VisitOMPParallelMasterDirective(
+ const OMPParallelMasterDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
void StmtProfiler::VisitOMPParallelSectionsDirective(
const OMPParallelSectionsDirective *S) {
VisitOMPExecutableDirective(S);
@@ -918,6 +933,26 @@ void StmtProfiler::VisitOMPTaskLoopSimdDirective(
VisitOMPLoopDirective(S);
}
+void StmtProfiler::VisitOMPMasterTaskLoopDirective(
+ const OMPMasterTaskLoopDirective *S) {
+ VisitOMPLoopDirective(S);
+}
+
+void StmtProfiler::VisitOMPMasterTaskLoopSimdDirective(
+ const OMPMasterTaskLoopSimdDirective *S) {
+ VisitOMPLoopDirective(S);
+}
+
+void StmtProfiler::VisitOMPParallelMasterTaskLoopDirective(
+ const OMPParallelMasterTaskLoopDirective *S) {
+ VisitOMPLoopDirective(S);
+}
+
+void StmtProfiler::VisitOMPParallelMasterTaskLoopSimdDirective(
+ const OMPParallelMasterTaskLoopSimdDirective *S) {
+ VisitOMPLoopDirective(S);
+}
+
void StmtProfiler::VisitOMPDistributeDirective(
const OMPDistributeDirective *S) {
VisitOMPLoopDirective(S);
@@ -1272,7 +1307,7 @@ void StmtProfiler::VisitBlockExpr(const BlockExpr *S) {
void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) {
VisitExpr(S);
- for (const GenericSelectionExpr::ConstAssociation &Assoc :
+ for (const GenericSelectionExpr::ConstAssociation Assoc :
S->associations()) {
QualType T = Assoc.getType();
if (T.isNull())
@@ -1297,6 +1332,57 @@ void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) {
ID.AddInteger(S->getOp());
}
+void StmtProfiler::VisitConceptSpecializationExpr(
+ const ConceptSpecializationExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getNamedConcept());
+ for (const TemplateArgument &Arg : S->getTemplateArguments())
+ VisitTemplateArgument(Arg);
+}
+
+void StmtProfiler::VisitRequiresExpr(const RequiresExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getLocalParameters().size());
+ for (ParmVarDecl *LocalParam : S->getLocalParameters())
+ VisitDecl(LocalParam);
+ ID.AddInteger(S->getRequirements().size());
+ for (concepts::Requirement *Req : S->getRequirements()) {
+ if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) {
+ ID.AddInteger(concepts::Requirement::RK_Type);
+ ID.AddBoolean(TypeReq->isSubstitutionFailure());
+ if (!TypeReq->isSubstitutionFailure())
+ VisitType(TypeReq->getType()->getType());
+ } else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) {
+ ID.AddInteger(concepts::Requirement::RK_Compound);
+ ID.AddBoolean(ExprReq->isExprSubstitutionFailure());
+ if (!ExprReq->isExprSubstitutionFailure())
+ Visit(ExprReq->getExpr());
+ // C++2a [expr.prim.req.compound]p1 Example:
+ // [...] The compound-requirement in C1 requires that x++ is a valid
+ // expression. It is equivalent to the simple-requirement x++; [...]
+ // We therefore do not profile isSimple() here.
+ ID.AddBoolean(ExprReq->getNoexceptLoc().isValid());
+ const concepts::ExprRequirement::ReturnTypeRequirement &RetReq =
+ ExprReq->getReturnTypeRequirement();
+ if (RetReq.isEmpty()) {
+ ID.AddInteger(0);
+ } else if (RetReq.isTypeConstraint()) {
+ ID.AddInteger(1);
+ Visit(RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint());
+ } else {
+ assert(RetReq.isSubstitutionFailure());
+ ID.AddInteger(2);
+ }
+ } else {
+ ID.AddInteger(concepts::Requirement::RK_Nested);
+ auto *NestedReq = cast<concepts::NestedRequirement>(Req);
+ ID.AddBoolean(NestedReq->isSubstitutionFailure());
+ if (!NestedReq->isSubstitutionFailure())
+ Visit(NestedReq->getConstraintExpr());
+ }
+ }
+}
+
static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
UnaryOperatorKind &UnaryOp,
BinaryOperatorKind &BinaryOp) {
@@ -1449,8 +1535,8 @@ static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
return Stmt::BinaryOperatorClass;
case OO_Spaceship:
- // FIXME: Update this once we support <=> expressions.
- llvm_unreachable("<=> expressions not supported yet");
+ BinaryOp = BO_Cmp;
+ return Stmt::BinaryOperatorClass;
case OO_AmpAmp:
BinaryOp = BO_LAnd;
@@ -1530,6 +1616,16 @@ void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
ID.AddInteger(S->getOperator());
}
+void StmtProfiler::VisitCXXRewrittenBinaryOperator(
+ const CXXRewrittenBinaryOperator *S) {
+ // If a rewritten operator were ever to be type-dependent, we should profile
+ // it following its syntactic operator.
+ assert(!S->isTypeDependent() &&
+ "resolved rewritten operator should never be type-dependent");
+ ID.AddBoolean(S->isReversed());
+ VisitExpr(S->getSemanticForm());
+}
+
#if defined(_MSC_VER) && !defined(__clang__)
#if _MSC_VER == 1911
#pragma optimize("", on)
diff --git a/contrib/llvm-project/clang/lib/AST/TemplateBase.cpp b/contrib/llvm-project/clang/lib/AST/TemplateBase.cpp
index cb4cbd2f76a1..6f0ebf232e77 100644
--- a/contrib/llvm-project/clang/lib/AST/TemplateBase.cpp
+++ b/contrib/llvm-project/clang/lib/AST/TemplateBase.cpp
@@ -370,7 +370,7 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
switch (getKind()) {
case Type:
- return getAsType()->getAs<PackExpansionType>()->getPattern();
+ return getAsType()->castAs<PackExpansionType>()->getPattern();
case Expression:
return cast<PackExpansionExpr>(getAsExpr())->getPattern();
@@ -561,7 +561,7 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
}
const ASTTemplateArgumentListInfo *
-ASTTemplateArgumentListInfo::Create(ASTContext &C,
+ASTTemplateArgumentListInfo::Create(const ASTContext &C,
const TemplateArgumentListInfo &List) {
std::size_t size = totalSizeToAlloc<TemplateArgumentLoc>(List.size());
void *Mem = C.Allocate(size, alignof(ASTTemplateArgumentListInfo));
diff --git a/contrib/llvm-project/clang/lib/AST/TextNodeDumper.cpp b/contrib/llvm-project/clang/lib/AST/TextNodeDumper.cpp
index cba9091b1065..c9b571862c19 100644
--- a/contrib/llvm-project/clang/lib/AST/TextNodeDumper.cpp
+++ b/contrib/llvm-project/clang/lib/AST/TextNodeDumper.cpp
@@ -223,7 +223,6 @@ void TextNodeDumper::Visit(const Decl *D) {
return;
}
- Context = &D->getASTContext();
{
ColorScope Color(OS, ShowColors, DeclKindNameColor);
OS << D->getDeclKindName() << "Decl";
@@ -490,6 +489,9 @@ void TextNodeDumper::visitInlineCommandComment(
case comments::InlineCommandComment::RenderEmphasized:
OS << " RenderEmphasized";
break;
+ case comments::InlineCommandComment::RenderAnchor:
+ OS << " RenderAnchor";
+ break;
}
for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
@@ -637,8 +639,8 @@ static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
if (!First)
OS << " -> ";
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ const auto *RD =
+ cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl());
if (Base->isVirtual())
OS << "virtual ";
@@ -688,7 +690,7 @@ void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) {
if (Node->getResultAPValueKind() != APValue::None) {
ColorScope Color(OS, ShowColors, ValueColor);
OS << " ";
- Node->getAPValueResult().printPretty(OS, *Context, Node->getType());
+ Node->getAPValueResult().dump(OS);
}
}
@@ -1199,6 +1201,11 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) {
OS << " decltype(auto)";
if (!T->isDeduced())
OS << " undeduced";
+ if (T->isConstrained()) {
+ dumpDeclRef(T->getTypeConstraintConcept());
+ for (const auto &Arg : T->getTypeConstraintArguments())
+ VisitTemplateArgument(Arg);
+ }
}
void TextNodeDumper::VisitTemplateSpecializationType(
@@ -1339,6 +1346,17 @@ void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) {
OS << " <<<NULL params x " << D->getNumParams() << ">>>";
}
+void TextNodeDumper::VisitLifetimeExtendedTemporaryDecl(
+ const LifetimeExtendedTemporaryDecl *D) {
+ OS << " extended by ";
+ dumpBareDeclRef(D->getExtendingDecl());
+ OS << " mangling ";
+ {
+ ColorScope Color(OS, ShowColors, ValueColor);
+ OS << D->getManglingNumber();
+ }
+}
+
void TextNodeDumper::VisitFieldDecl(const FieldDecl *D) {
dumpName(D);
dumpType(D->getType());
@@ -1385,6 +1403,8 @@ void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
break;
}
}
+ if (D->needsDestruction(D->getASTContext()))
+ OS << " destroyed";
if (D->isParameterPack())
OS << " pack";
}
@@ -1537,6 +1557,7 @@ void TextNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
FLAG(isGenericLambda, generic);
FLAG(isLambda, lambda);
+ FLAG(isAnonymousStructOrUnion, is_anonymous);
FLAG(canPassInRegisters, pass_in_registers);
FLAG(isEmpty, empty);
FLAG(isAggregate, aggregate);
@@ -1641,6 +1662,7 @@ void TextNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
FLAG(hasTrivialDestructor, trivial);
FLAG(hasNonTrivialDestructor, non_trivial);
FLAG(hasUserDeclaredDestructor, user_declared);
+ FLAG(hasConstexprDestructor, constexpr);
FLAG(needsImplicitDestructor, needs_implicit);
FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution);
if (!D->needsOverloadResolutionForDestructor())
@@ -1677,7 +1699,16 @@ void TextNodeDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) {
}
void TextNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
- if (D->wasDeclaredWithTypename())
+ if (const auto *TC = D->getTypeConstraint()) {
+ OS << " ";
+ dumpBareDeclRef(TC->getNamedConcept());
+ if (TC->getNamedConcept() != TC->getFoundDecl()) {
+ OS << " (";
+ dumpBareDeclRef(TC->getFoundDecl());
+ OS << ")";
+ }
+ Visit(TC->getImmediatelyDeclaredConstraint());
+ } else if (D->wasDeclaredWithTypename())
OS << " typename";
else
OS << " class";
@@ -1912,6 +1943,8 @@ void TextNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
OS << " unsafe_unretained";
if (Attrs & ObjCPropertyDecl::OBJC_PR_class)
OS << " class";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_direct)
+ OS << " direct";
if (Attrs & ObjCPropertyDecl::OBJC_PR_getter)
dumpDeclRef(D->getGetterMethodDecl(), "getter");
if (Attrs & ObjCPropertyDecl::OBJC_PR_setter)
diff --git a/contrib/llvm-project/clang/lib/AST/Type.cpp b/contrib/llvm-project/clang/lib/AST/Type.cpp
index ed75a0b5bcd8..5099494da5fd 100644
--- a/contrib/llvm-project/clang/lib/AST/Type.cpp
+++ b/contrib/llvm-project/clang/lib/AST/Type.cpp
@@ -50,6 +50,7 @@
#include <cassert>
#include <cstdint>
#include <cstring>
+#include <type_traits>
using namespace clang;
@@ -74,11 +75,11 @@ const IdentifierInfo* QualType::getBaseTypeIdentifier() const {
if (ty->isPointerType() || ty->isReferenceType())
return ty->getPointeeType().getBaseTypeIdentifier();
else if (ty->isRecordType())
- ND = ty->getAs<RecordType>()->getDecl();
+ ND = ty->castAs<RecordType>()->getDecl();
else if (ty->isEnumeralType())
- ND = ty->getAs<EnumType>()->getDecl();
+ ND = ty->castAs<EnumType>()->getDecl();
else if (ty->getTypeClass() == Type::Typedef)
- ND = ty->getAs<TypedefType>()->getDecl();
+ ND = ty->castAs<TypedefType>()->getDecl();
else if (ty->isArrayType())
return ty->castAsArrayTypeUnsafe()->
getElementType().getBaseTypeIdentifier();
@@ -108,6 +109,33 @@ bool QualType::isConstant(QualType T, const ASTContext &Ctx) {
return T.getAddressSpace() == LangAS::opencl_constant;
}
+// C++ [temp.dep.type]p1:
+// A type is dependent if it is...
+// - an array type constructed from any dependent type or whose
+// size is specified by a constant expression that is
+// value-dependent,
+ArrayType::ArrayType(TypeClass tc, QualType et, QualType can,
+ ArraySizeModifier sm, unsigned tq, const Expr *sz)
+ // Note, we need to check for DependentSizedArrayType explicitly here
+ // because we use a DependentSizedArrayType with no size expression as the
+ // type of a dependent array of unknown bound with a dependent braced
+ // initializer:
+ //
+ // template<int ...N> int arr[] = {N...};
+ : Type(tc, can,
+ et->isDependentType() || (sz && sz->isValueDependent()) ||
+ tc == DependentSizedArray,
+ et->isInstantiationDependentType() ||
+ (sz && sz->isInstantiationDependent()) ||
+ tc == DependentSizedArray,
+ (tc == VariableArray || et->isVariablyModifiedType()),
+ et->containsUnexpandedParameterPack() ||
+ (sz && sz->containsUnexpandedParameterPack())),
+ ElementType(et) {
+ ArrayTypeBits.IndexTypeQuals = tq;
+ ArrayTypeBits.SizeModifier = sm;
+}
+
unsigned ConstantArrayType::getNumAddressingBits(const ASTContext &Context,
QualType ElementType,
const llvm::APInt &NumElements) {
@@ -155,14 +183,26 @@ unsigned ConstantArrayType::getMaxSizeBits(const ASTContext &Context) {
return Bits;
}
+void ConstantArrayType::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &Context, QualType ET,
+ const llvm::APInt &ArraySize,
+ const Expr *SizeExpr, ArraySizeModifier SizeMod,
+ unsigned TypeQuals) {
+ ID.AddPointer(ET.getAsOpaquePtr());
+ ID.AddInteger(ArraySize.getZExtValue());
+ ID.AddInteger(SizeMod);
+ ID.AddInteger(TypeQuals);
+ ID.AddBoolean(SizeExpr != 0);
+ if (SizeExpr)
+ SizeExpr->Profile(ID, Context, true);
+}
+
DependentSizedArrayType::DependentSizedArrayType(const ASTContext &Context,
QualType et, QualType can,
Expr *e, ArraySizeModifier sm,
unsigned tq,
SourceRange brackets)
- : ArrayType(DependentSizedArray, et, can, sm, tq,
- (et->containsUnexpandedParameterPack() ||
- (e && e->containsUnexpandedParameterPack()))),
+ : ArrayType(DependentSizedArray, et, can, sm, tq, e),
Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) {}
void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID,
@@ -297,7 +337,19 @@ QualType QualType::getSingleStepDesugaredTypeImpl(QualType type,
#define TYPE(CLASS, BASE) \
static_assert(!std::is_polymorphic<CLASS##Type>::value, \
#CLASS "Type should not be polymorphic!");
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
+
+// Check that no type class has a non-trival destructor. Types are
+// allocated with the BumpPtrAllocator from ASTContext and therefore
+// their destructor is not executed.
+//
+// FIXME: ConstantArrayType is not trivially destructible because of its
+// APInt member. It should be replaced in favor of ASTContext allocation.
+#define TYPE(CLASS, BASE) \
+ static_assert(std::is_trivially_destructible<CLASS##Type>::value || \
+ std::is_same<CLASS##Type, ConstantArrayType>::value, \
+ #CLASS "Type should be trivially destructible!");
+#include "clang/AST/TypeNodes.inc"
QualType Type::getLocallyUnqualifiedSingleStepDesugaredType() const {
switch (getTypeClass()) {
@@ -308,7 +360,7 @@ QualType Type::getLocallyUnqualifiedSingleStepDesugaredType() const {
if (!ty->isSugared()) return QualType(ty, 0); \
return ty->desugar(); \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
llvm_unreachable("bad type kind!");
}
@@ -329,7 +381,7 @@ SplitQualType QualType::getSplitDesugaredType(QualType T) {
Cur = Ty->desugar(); \
break; \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
}
}
@@ -357,7 +409,7 @@ SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) {
next = ty->desugar(); \
break; \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
// Otherwise, split the underlying type. If that yields qualifiers,
@@ -396,7 +448,7 @@ template<typename T> static const T *getAsSugar(const Type *Cur) {
Cur = Ty->desugar().getTypePtr(); \
break; \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
}
}
@@ -429,7 +481,7 @@ const Type *Type::getUnqualifiedDesugaredType() const {
Cur = Ty->desugar().getTypePtr(); \
break; \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
}
}
@@ -753,7 +805,7 @@ public:
#define TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) \
QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); }
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
#define TRIVIAL_TYPE_CLASS(Class) \
QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); }
@@ -847,7 +899,7 @@ public:
if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
return QualType(T, 0);
- return Ctx.getConstantArrayType(elementType, T->getSize(),
+ return Ctx.getConstantArrayType(elementType, T->getSize(), T->getSizeExpr(),
T->getSizeModifier(),
T->getIndexTypeCVRQualifiers());
}
@@ -1062,7 +1114,9 @@ public:
return QualType(T, 0);
return Ctx.getAutoType(deducedType, T->getKeyword(),
- T->isDependentType());
+ T->isDependentType(), /*IsPack=*/false,
+ T->getTypeConstraintConcept(),
+ T->getTypeConstraintArguments());
}
// FIXME: Non-trivial to implement, but important for C++
@@ -1804,13 +1858,12 @@ bool Type::isIntegralOrUnscopedEnumerationType() const {
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::Int128;
+ return isUnscopedEnumerationType();
+}
- // Check for a complete enum type; incomplete enum types are not properly an
- // enumeration type in the sense required here.
- // C++0x: However, if the underlying type of the enum is fixed, it is
- // considered complete.
+bool Type::isUnscopedEnumerationType() const {
if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
- return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
+ return !ET->getDecl()->isScoped();
return false;
}
@@ -2477,6 +2530,15 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const {
return false;
}
+bool Type::isNothrowT() const {
+ if (const auto *RD = getAsCXXRecordDecl()) {
+ IdentifierInfo *II = RD->getIdentifier();
+ if (II && II->isStr("nothrow_t") && RD->isInStdNamespace())
+ return true;
+ }
+ return false;
+}
+
bool Type::isAlignValT() const {
if (const auto *ET = getAs<EnumType>()) {
IdentifierInfo *II = ET->getDecl()->getIdentifier();
@@ -2690,7 +2752,7 @@ const char *Type::getTypeClassName() const {
switch (TypeBits.TC) {
#define ABSTRACT_TYPE(Derived, Base)
#define TYPE(Derived, Base) case Derived: return #Derived;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
llvm_unreachable("Invalid type class.");
@@ -2841,6 +2903,10 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case Id: \
return #ExtType;
#include "clang/Basic/OpenCLExtensionTypes.def"
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case Id: \
+ return Name;
+#include "clang/Basic/AArch64SVEACLETypes.def"
}
llvm_unreachable("Invalid builtin type.");
@@ -3000,6 +3066,12 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
} else {
FunctionTypeBits.HasExtQuals = 0;
}
+
+ // Fill in the Ellipsis location info if present.
+ if (epi.Variadic) {
+ auto &EllipsisLoc = *getTrailingObjects<SourceLocation>();
+ EllipsisLoc = epi.EllipsisLoc;
+ }
}
bool FunctionProtoType::hasDependentExceptionSpec() const {
@@ -3556,14 +3628,15 @@ static CachedProperties computeCachedProperties(const Type *T) {
switch (T->getTypeClass()) {
#define TYPE(Class,Base)
#define NON_CANONICAL_TYPE(Class,Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("didn't expect a non-canonical type here");
#define TYPE(Class,Base)
#define DEPENDENT_TYPE(Class,Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
// Treat instantiation-dependent types as external.
+ if (!T->isInstantiationDependentType()) T->dump();
assert(T->isInstantiationDependentType());
return CachedProperties(ExternalLinkage, false);
@@ -3659,13 +3732,13 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
switch (T->getTypeClass()) {
#define TYPE(Class,Base)
#define NON_CANONICAL_TYPE(Class,Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("didn't expect a non-canonical type here");
#define TYPE(Class,Base)
#define DEPENDENT_TYPE(Class,Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
// Treat instantiation-dependent types as external.
assert(T->isInstantiationDependentType());
return LinkageInfo::external();
@@ -3774,7 +3847,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
case Type::Class: \
llvm_unreachable("non-canonical type");
#define TYPE(Class, Parent)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
// Pointer types.
case Type::Pointer:
@@ -3842,6 +3915,9 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::BuiltinFn:
case BuiltinType::NullPtr:
case BuiltinType::OMPArraySection:
@@ -4084,3 +4160,35 @@ void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,
/*HasUnsignedPadding=*/false);
APFixedPoint(Val, FXSema).toString(Str);
}
+
+AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
+ bool IsDeducedAsDependent, bool IsDeducedAsPack,
+ ConceptDecl *TypeConstraintConcept,
+ ArrayRef<TemplateArgument> TypeConstraintArgs)
+ : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
+ IsDeducedAsDependent, IsDeducedAsPack) {
+ AutoTypeBits.Keyword = (unsigned)Keyword;
+ AutoTypeBits.NumArgs = TypeConstraintArgs.size();
+ this->TypeConstraintConcept = TypeConstraintConcept;
+ if (TypeConstraintConcept) {
+ TemplateArgument *ArgBuffer = getArgBuffer();
+ for (const TemplateArgument &Arg : TypeConstraintArgs) {
+ if (Arg.containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
+
+ new (ArgBuffer++) TemplateArgument(Arg);
+ }
+ }
+}
+
+void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType Deduced, AutoTypeKeyword Keyword,
+ bool IsDependent, ConceptDecl *CD,
+ ArrayRef<TemplateArgument> Arguments) {
+ ID.AddPointer(Deduced.getAsOpaquePtr());
+ ID.AddInteger((unsigned)Keyword);
+ ID.AddBoolean(IsDependent);
+ ID.AddPointer(CD);
+ for (const TemplateArgument &Arg : Arguments)
+ Arg.Profile(ID, Context);
+}
diff --git a/contrib/llvm-project/clang/lib/AST/TypeLoc.cpp b/contrib/llvm-project/clang/lib/AST/TypeLoc.cpp
index abe4c4eb25e6..665a86f2c143 100644
--- a/contrib/llvm-project/clang/lib/AST/TypeLoc.cpp
+++ b/contrib/llvm-project/clang/lib/AST/TypeLoc.cpp
@@ -11,7 +11,9 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/TypeLoc.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateBase.h"
@@ -293,6 +295,12 @@ bool TypeSpecTypeLoc::isKind(const TypeLoc &TL) {
return TSTChecker().Visit(TL);
}
+bool TagTypeLoc::isDefinition() const {
+ TagDecl *D = getDecl();
+ return D->isCompleteDefinition() &&
+ (D->getIdentifier() == nullptr || D->getLocation() == getNameLoc());
+}
+
// Reimplemented to account for GNU/C++ extension
// typeof unary-expression
// where there are no parentheses.
@@ -391,6 +399,9 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::BuiltinFn:
case BuiltinType::OMPArraySection:
return TST_unspecified;
@@ -464,6 +475,19 @@ void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context,
setProtocolLoc(i, Loc);
}
+SourceRange AttributedTypeLoc::getLocalSourceRange() const {
+ // Note that this does *not* include the range of the attribute
+ // enclosure, e.g.:
+ // __attribute__((foo(bar)))
+ // ^~~~~~~~~~~~~~~ ~~
+ // or
+ // [[foo(bar)]]
+ // ^~ ~~
+ // That enclosure doesn't necessarily belong to a single attribute
+ // anyway.
+ return getAttr() ? getAttr()->getRange() : SourceRange();
+}
+
void TypeOfTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo>
@@ -566,3 +590,97 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
}
}
}
+
+DeclarationNameInfo AutoTypeLoc::getConceptNameInfo() const {
+ return DeclarationNameInfo(getNamedConcept()->getDeclName(),
+ getLocalData()->ConceptNameLoc);
+}
+
+void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ setNestedNameSpecifierLoc(NestedNameSpecifierLoc());
+ setTemplateKWLoc(Loc);
+ setConceptNameLoc(Loc);
+ setFoundDecl(nullptr);
+ setRAngleLoc(Loc);
+ setLAngleLoc(Loc);
+ TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
+ getTypePtr()->getArgs(),
+ getArgInfos(), Loc);
+ setNameLoc(Loc);
+}
+
+
+namespace {
+
+ class GetContainedAutoTypeLocVisitor :
+ public TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc> {
+ public:
+ using TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc>::Visit;
+
+ TypeLoc VisitAutoTypeLoc(AutoTypeLoc TL) {
+ return TL;
+ }
+
+ // Only these types can contain the desired 'auto' type.
+
+ TypeLoc VisitElaboratedTypeLoc(ElaboratedTypeLoc T) {
+ return Visit(T.getNamedTypeLoc());
+ }
+
+ TypeLoc VisitQualifiedTypeLoc(QualifiedTypeLoc T) {
+ return Visit(T.getUnqualifiedLoc());
+ }
+
+ TypeLoc VisitPointerTypeLoc(PointerTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitReferenceTypeLoc(ReferenceTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitArrayTypeLoc(ArrayTypeLoc T) {
+ return Visit(T.getElementLoc());
+ }
+
+ TypeLoc VisitFunctionTypeLoc(FunctionTypeLoc T) {
+ return Visit(T.getReturnLoc());
+ }
+
+ TypeLoc VisitParenTypeLoc(ParenTypeLoc T) {
+ return Visit(T.getInnerLoc());
+ }
+
+ TypeLoc VisitAttributedTypeLoc(AttributedTypeLoc T) {
+ return Visit(T.getModifiedLoc());
+ }
+
+ TypeLoc VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc T) {
+ return Visit(T.getInnerLoc());
+ }
+
+ TypeLoc VisitAdjustedTypeLoc(AdjustedTypeLoc T) {
+ return Visit(T.getOriginalLoc());
+ }
+
+ TypeLoc VisitPackExpansionTypeLoc(PackExpansionTypeLoc T) {
+ return Visit(T.getPatternLoc());
+ }
+ };
+
+} // namespace
+
+AutoTypeLoc TypeLoc::getContainedAutoTypeLoc() const {
+ TypeLoc Res = GetContainedAutoTypeLocVisitor().Visit(*this);
+ if (Res.isNull())
+ return AutoTypeLoc();
+ return Res.getAs<AutoTypeLoc>();
+}
diff --git a/contrib/llvm-project/clang/lib/AST/TypePrinter.cpp b/contrib/llvm-project/clang/lib/AST/TypePrinter.cpp
index 8d5c37299e5f..4a7e765a2bd8 100644
--- a/contrib/llvm-project/clang/lib/AST/TypePrinter.cpp
+++ b/contrib/llvm-project/clang/lib/AST/TypePrinter.cpp
@@ -125,7 +125,7 @@ namespace {
#define TYPE(CLASS, PARENT) \
void print##CLASS##Before(const CLASS##Type *T, raw_ostream &OS); \
void print##CLASS##After(const CLASS##Type *T, raw_ostream &OS);
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
private:
void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS);
@@ -321,7 +321,7 @@ void TypePrinter::printBefore(const Type *T,Qualifiers Quals, raw_ostream &OS) {
#define TYPE(CLASS, PARENT) case Type::CLASS: \
print##CLASS##Before(cast<CLASS##Type>(T), OS); \
break;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
if (hasAfterQuals) {
@@ -347,7 +347,7 @@ void TypePrinter::printAfter(const Type *T, Qualifiers Quals, raw_ostream &OS) {
#define TYPE(CLASS, PARENT) case Type::CLASS: \
print##CLASS##After(cast<CLASS##Type>(T), OS); \
break;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
}
@@ -1046,6 +1046,13 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {
if (!T->getDeducedType().isNull()) {
printBefore(T->getDeducedType(), OS);
} else {
+ if (T->isConstrained()) {
+ OS << T->getTypeConstraintConcept()->getName();
+ auto Args = T->getTypeConstraintArguments();
+ if (!Args.empty())
+ printTemplateArgumentList(OS, Args, Policy);
+ OS << ' ';
+ }
switch (T->getKeyword()) {
case AutoTypeKeyword::Auto: OS << "auto"; break;
case AutoTypeKeyword::DecltypeAuto: OS << "decltype(auto)"; break;
@@ -1189,8 +1196,8 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
if (PLoc.isValid()) {
OS << " at ";
StringRef File = PLoc.getFilename();
- if (Policy.RemapFilePaths)
- OS << Policy.remapPath(File);
+ if (auto *Callbacks = Policy.Callbacks)
+ OS << Callbacks->remapPath(File);
else
OS << File;
OS << ':' << PLoc.getLine() << ':' << PLoc.getColumn();
@@ -1204,7 +1211,8 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
// arguments.
if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
ArrayRef<TemplateArgument> Args;
- if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) {
+ TypeSourceInfo *TAW = Spec->getTypeAsWritten();
+ if (!Policy.PrintCanonicalTypes && TAW) {
const TemplateSpecializationType *TST =
cast<TemplateSpecializationType>(TAW->getType());
Args = TST->template_arguments();
@@ -1233,20 +1241,18 @@ void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) {}
void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T,
raw_ostream &OS) {
- if (IdentifierInfo *Id = T->getIdentifier())
- OS << Id->getName();
- else {
- bool IsLambdaAutoParam = false;
- if (auto D = T->getDecl()) {
- if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext()))
- IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda();
+ TemplateTypeParmDecl *D = T->getDecl();
+ if (D && D->isImplicit()) {
+ if (auto *TC = D->getTypeConstraint()) {
+ TC->print(OS, Policy);
+ OS << ' ';
}
+ OS << "auto";
+ } else if (IdentifierInfo *Id = T->getIdentifier())
+ OS << Id->getName();
+ else
+ OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
- if (IsLambdaAutoParam)
- OS << "auto";
- else
- OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
- }
spaceBeforePlaceHolder(OS);
}
@@ -1537,7 +1543,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
QualType t = T->getEquivalentType();
while (!t->isFunctionType())
t = t->getPointeeType();
- OS << (t->getAs<FunctionType>()->getCallConv() == CC_AAPCS ?
+ OS << (t->castAs<FunctionType>()->getCallConv() == CC_AAPCS ?
"\"aapcs\"" : "\"aapcs-vfp\"");
OS << ')';
break;
@@ -1554,6 +1560,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::NoDeref:
OS << "noderef";
break;
+ case attr::AcquireHandle:
+ OS << "acquire_handle";
+ break;
}
OS << "))";
}
@@ -1771,6 +1780,37 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const {
return true;
}
+std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
+ switch (AS) {
+ case LangAS::Default:
+ return "";
+ case LangAS::opencl_global:
+ return "__global";
+ case LangAS::opencl_local:
+ return "__local";
+ case LangAS::opencl_private:
+ return "__private";
+ case LangAS::opencl_constant:
+ return "__constant";
+ case LangAS::opencl_generic:
+ return "__generic";
+ case LangAS::cuda_device:
+ return "__device__";
+ case LangAS::cuda_constant:
+ return "__constant__";
+ case LangAS::cuda_shared:
+ return "__shared__";
+ case LangAS::ptr32_sptr:
+ return "__sptr __ptr32";
+ case LangAS::ptr32_uptr:
+ return "__uptr __ptr32";
+ case LangAS::ptr64:
+ return "__ptr64";
+ default:
+ return std::to_string(toTargetAddressSpace(AS));
+ }
+}
+
// Appends qualifiers to the given string, separated by spaces. Will
// prefix a space if the string is non-empty. Will not append a final
// space.
@@ -1789,43 +1829,18 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
OS << "__unaligned";
addSpace = true;
}
- LangAS addrspace = getAddressSpace();
- if (addrspace != LangAS::Default) {
- if (addrspace != LangAS::opencl_private) {
- if (addSpace)
- OS << ' ';
- addSpace = true;
- switch (addrspace) {
- case LangAS::opencl_global:
- OS << "__global";
- break;
- case LangAS::opencl_local:
- OS << "__local";
- break;
- case LangAS::opencl_private:
- break;
- case LangAS::opencl_constant:
- OS << "__constant";
- break;
- case LangAS::opencl_generic:
- OS << "__generic";
- break;
- case LangAS::cuda_device:
- OS << "__device__";
- break;
- case LangAS::cuda_constant:
- OS << "__constant__";
- break;
- case LangAS::cuda_shared:
- OS << "__shared__";
- break;
- default:
- OS << "__attribute__((address_space(";
- OS << toTargetAddressSpace(addrspace);
- OS << ")))";
- }
- }
+ auto ASStr = getAddrSpaceAsString(getAddressSpace());
+ if (!ASStr.empty()) {
+ if (addSpace)
+ OS << ' ';
+ addSpace = true;
+ // Wrap target address space into an attribute syntax
+ if (isTargetAddressSpace(getAddressSpace()))
+ OS << "__attribute__((address_space(" << ASStr << ")))";
+ else
+ OS << ASStr;
}
+
if (Qualifiers::GC gc = getObjCGCAttr()) {
if (addSpace)
OS << ' ';
diff --git a/contrib/llvm-project/clang/lib/AST/VTTBuilder.cpp b/contrib/llvm-project/clang/lib/AST/VTTBuilder.cpp
index 53d0ef09f14c..d58e87517785 100644
--- a/contrib/llvm-project/clang/lib/AST/VTTBuilder.cpp
+++ b/contrib/llvm-project/clang/lib/AST/VTTBuilder.cpp
@@ -64,8 +64,8 @@ void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
if (I.isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const auto *BaseDecl =
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
CharUnits BaseOffset = Base.getBaseOffset() +
@@ -90,8 +90,8 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
return;
for (const auto &I : RD->bases()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const auto *BaseDecl =
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
// Itanium C++ ABI 2.6.2:
// Secondary virtual pointers are present for all bases with either
@@ -154,8 +154,8 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases) {
for (const auto &I : RD->bases()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const auto *BaseDecl =
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
// Check if this is a virtual base.
if (I.isVirtual()) {
diff --git a/contrib/llvm-project/clang/lib/AST/VTableBuilder.cpp b/contrib/llvm-project/clang/lib/AST/VTableBuilder.cpp
index 0c699571555d..2b5b74be5961 100644
--- a/contrib/llvm-project/clang/lib/AST/VTableBuilder.cpp
+++ b/contrib/llvm-project/clang/lib/AST/VTableBuilder.cpp
@@ -270,8 +270,8 @@ static BaseOffset
ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
const CXXMethodDecl *DerivedMD,
const CXXMethodDecl *BaseMD) {
- const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>();
- const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>();
+ const auto *BaseFT = BaseMD->getType()->castAs<FunctionType>();
+ const auto *DerivedFT = DerivedMD->getType()->castAs<FunctionType>();
// Canonicalize the return types.
CanQualType CanDerivedReturnType =
@@ -2268,7 +2268,7 @@ CreateVTableLayout(const ItaniumVTableBuilder &Builder) {
SmallVector<VTableLayout::VTableThunkTy, 1>
VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
- return llvm::make_unique<VTableLayout>(
+ return std::make_unique<VTableLayout>(
Builder.VTableIndices, Builder.vtable_components(), VTableThunks,
Builder.getAddressPoints());
}
@@ -3253,7 +3253,7 @@ void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
// Base case: this subobject has its own vptr.
if (ForVBTables ? Layout.hasOwnVBPtr() : Layout.hasOwnVFPtr())
- Paths.push_back(llvm::make_unique<VPtrInfo>(RD));
+ Paths.push_back(std::make_unique<VPtrInfo>(RD));
// Recursive case: get all the vbtables from our bases and remove anything
// that shares a virtual base.
@@ -3276,7 +3276,7 @@ void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
continue;
// Copy the path and adjust it as necessary.
- auto P = llvm::make_unique<VPtrInfo>(*BaseInfo);
+ auto P = std::make_unique<VPtrInfo>(*BaseInfo);
// We mangle Base into the path if the path would've been ambiguous and it
// wasn't already extended with Base.
@@ -3562,7 +3562,7 @@ void MicrosoftVTableContext::computeVTableRelatedInformation(
const VTableLayout::AddressPointsMapTy EmptyAddressPointsMap;
{
- auto VFPtrs = llvm::make_unique<VPtrInfoVector>();
+ auto VFPtrs = std::make_unique<VPtrInfoVector>();
computeVTablePaths(/*ForVBTables=*/false, RD, *VFPtrs);
computeFullPathsForVFTables(Context, RD, *VFPtrs);
VFPtrLocations[RD] = std::move(VFPtrs);
@@ -3576,7 +3576,7 @@ void MicrosoftVTableContext::computeVTableRelatedInformation(
assert(VFTableLayouts.count(id) == 0);
SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks(
Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
- VFTableLayouts[id] = llvm::make_unique<VTableLayout>(
+ VFTableLayouts[id] = std::make_unique<VTableLayout>(
ArrayRef<size_t>{0}, Builder.vtable_components(), VTableThunks,
EmptyAddressPointsMap);
Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
@@ -3668,7 +3668,7 @@ const VirtualBaseInfo &MicrosoftVTableContext::computeVBTableRelatedInformation(
std::unique_ptr<VirtualBaseInfo> &Entry = VBaseInfo[RD];
if (Entry)
return *Entry;
- Entry = llvm::make_unique<VirtualBaseInfo>();
+ Entry = std::make_unique<VirtualBaseInfo>();
VBI = Entry.get();
}