summaryrefslogtreecommitdiff
path: root/lib/AST
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:49 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:49 +0000
commit2298981669bf3bd63335a4be179bc0f96823a8f4 (patch)
tree1cbe2eb27f030d2d70b80ee5ca3c86bee7326a9f /lib/AST
parent9a83721404652cea39e9f02ae3e3b5c964602a5c (diff)
Notes
Diffstat (limited to 'lib/AST')
-rw-r--r--lib/AST/APValue.cpp166
-rw-r--r--lib/AST/ASTConsumer.cpp7
-rw-r--r--lib/AST/ASTContext.cpp584
-rw-r--r--lib/AST/ASTDiagnostic.cpp12
-rw-r--r--lib/AST/ASTDumper.cpp1455
-rw-r--r--lib/AST/ASTImporter.cpp1888
-rw-r--r--lib/AST/ASTImporterLookupTable.cpp32
-rw-r--r--lib/AST/ASTStructuralEquivalence.cpp387
-rw-r--r--lib/AST/ASTTypeTraits.cpp25
-rw-r--r--lib/AST/AttrImpl.cpp7
-rw-r--r--lib/AST/CXXABI.h7
-rw-r--r--lib/AST/CXXInheritance.cpp25
-rw-r--r--lib/AST/Comment.cpp7
-rw-r--r--lib/AST/CommentBriefParser.cpp7
-rw-r--r--lib/AST/CommentCommandTraits.cpp7
-rw-r--r--lib/AST/CommentLexer.cpp7
-rw-r--r--lib/AST/CommentParser.cpp7
-rw-r--r--lib/AST/CommentSema.cpp7
-rw-r--r--lib/AST/ComparisonCategories.cpp7
-rw-r--r--lib/AST/DataCollection.cpp7
-rw-r--r--lib/AST/Decl.cpp465
-rw-r--r--lib/AST/DeclBase.cpp61
-rw-r--r--lib/AST/DeclCXX.cpp264
-rw-r--r--lib/AST/DeclFriend.cpp7
-rw-r--r--lib/AST/DeclGroup.cpp7
-rw-r--r--lib/AST/DeclObjC.cpp9
-rw-r--r--lib/AST/DeclOpenMP.cpp110
-rw-r--r--lib/AST/DeclPrinter.cpp229
-rw-r--r--lib/AST/DeclTemplate.cpp50
-rw-r--r--lib/AST/DeclarationName.cpp15
-rw-r--r--lib/AST/Expr.cpp880
-rw-r--r--lib/AST/ExprCXX.cpp57
-rw-r--r--lib/AST/ExprClassification.cpp9
-rw-r--r--lib/AST/ExprConstant.cpp2310
-rw-r--r--lib/AST/ExprObjC.cpp38
-rw-r--r--lib/AST/ExternalASTMerger.cpp67
-rw-r--r--lib/AST/ExternalASTSource.cpp7
-rw-r--r--lib/AST/FormatString.cpp41
-rw-r--r--lib/AST/InheritViz.cpp7
-rw-r--r--lib/AST/ItaniumCXXABI.cpp7
-rw-r--r--lib/AST/ItaniumMangle.cpp139
-rw-r--r--lib/AST/JSONNodeDumper.cpp1569
-rw-r--r--lib/AST/Linkage.h7
-rw-r--r--lib/AST/Mangle.cpp212
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp7
-rw-r--r--lib/AST/MicrosoftMangle.cpp176
-rw-r--r--lib/AST/NSAPI.cpp7
-rw-r--r--lib/AST/NestedNameSpecifier.cpp7
-rw-r--r--lib/AST/ODRHash.cpp90
-rw-r--r--lib/AST/OpenMPClause.cpp360
-rw-r--r--lib/AST/ParentMap.cpp19
-rw-r--r--lib/AST/PrintfFormatString.cpp41
-rw-r--r--lib/AST/QualTypeNames.cpp22
-rw-r--r--lib/AST/RawCommentList.cpp7
-rw-r--r--lib/AST/RecordLayout.cpp7
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp167
-rw-r--r--lib/AST/ScanfFormatString.cpp18
-rw-r--r--lib/AST/SelectorLocationsKind.cpp7
-rw-r--r--lib/AST/Stmt.cpp91
-rw-r--r--lib/AST/StmtCXX.cpp7
-rw-r--r--lib/AST/StmtIterator.cpp7
-rw-r--r--lib/AST/StmtObjC.cpp7
-rw-r--r--lib/AST/StmtOpenMP.cpp26
-rw-r--r--lib/AST/StmtPrinter.cpp102
-rw-r--r--lib/AST/StmtProfile.cpp36
-rw-r--r--lib/AST/StmtViz.cpp7
-rw-r--r--lib/AST/TemplateBase.cpp7
-rw-r--r--lib/AST/TemplateName.cpp37
-rw-r--r--lib/AST/TextNodeDumper.cpp802
-rw-r--r--lib/AST/Type.cpp542
-rw-r--r--lib/AST/TypeLoc.cpp7
-rw-r--r--lib/AST/TypePrinter.cpp80
-rw-r--r--lib/AST/VTTBuilder.cpp7
-rw-r--r--lib/AST/VTableBuilder.cpp25
74 files changed, 9362 insertions, 4581 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index c05b160b8e3d9..1993bba9bd1a1 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -1,9 +1,8 @@
//===--- APValue.cpp - Union class for APFloat/APSInt/Complex -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -21,6 +20,61 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+/// The identity of a type_info object depends on the canonical unqualified
+/// type only.
+TypeInfoLValue::TypeInfoLValue(const Type *T)
+ : T(T->getCanonicalTypeUnqualified().getTypePtr()) {}
+
+void TypeInfoLValue::print(llvm::raw_ostream &Out,
+ const PrintingPolicy &Policy) const {
+ Out << "typeid(";
+ QualType(getType(), 0).print(Out, Policy);
+ Out << ")";
+}
+
+static_assert(
+ 1 << llvm::PointerLikeTypeTraits<TypeInfoLValue>::NumLowBitsAvailable <=
+ alignof(Type),
+ "Type is insufficiently aligned");
+
+APValue::LValueBase::LValueBase(const ValueDecl *P, unsigned I, unsigned V)
+ : Ptr(P), Local{I, V} {}
+APValue::LValueBase::LValueBase(const Expr *P, unsigned I, unsigned V)
+ : Ptr(P), Local{I, V} {}
+
+APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV,
+ QualType TypeInfo) {
+ LValueBase Base;
+ Base.Ptr = LV;
+ Base.TypeInfoType = TypeInfo.getAsOpaquePtr();
+ return Base;
+}
+
+unsigned APValue::LValueBase::getCallIndex() const {
+ return is<TypeInfoLValue>() ? 0 : Local.CallIndex;
+}
+
+unsigned APValue::LValueBase::getVersion() const {
+ return is<TypeInfoLValue>() ? 0 : Local.Version;
+}
+
+QualType APValue::LValueBase::getTypeInfoType() const {
+ assert(is<TypeInfoLValue>() && "not a type_info lvalue");
+ return QualType::getFromOpaquePtr(TypeInfoType);
+}
+
+namespace clang {
+bool operator==(const APValue::LValueBase &LHS,
+ const APValue::LValueBase &RHS) {
+ if (LHS.Ptr != RHS.Ptr)
+ return false;
+ if (LHS.is<TypeInfoLValue>())
+ return true;
+ return LHS.Local.CallIndex == RHS.Local.CallIndex &&
+ LHS.Local.Version == RHS.Local.Version;
+}
+}
+
namespace {
struct LVBase {
APValue::LValueBase Base;
@@ -46,26 +100,27 @@ APValue::LValueBase::operator bool () const {
clang::APValue::LValueBase
llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() {
return clang::APValue::LValueBase(
- DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getEmptyKey(),
- DenseMapInfo<unsigned>::getEmptyKey(),
- DenseMapInfo<unsigned>::getEmptyKey());
+ DenseMapInfo<const ValueDecl*>::getEmptyKey());
}
clang::APValue::LValueBase
llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() {
return clang::APValue::LValueBase(
- DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getTombstoneKey(),
- DenseMapInfo<unsigned>::getTombstoneKey(),
- DenseMapInfo<unsigned>::getTombstoneKey());
+ DenseMapInfo<const ValueDecl*>::getTombstoneKey());
+}
+
+namespace clang {
+llvm::hash_code hash_value(const APValue::LValueBase &Base) {
+ if (Base.is<TypeInfoLValue>())
+ return llvm::hash_value(Base.getOpaqueValue());
+ return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(),
+ Base.getVersion());
+}
}
unsigned llvm::DenseMapInfo<clang::APValue::LValueBase>::getHashValue(
const clang::APValue::LValueBase &Base) {
- llvm::FoldingSetNodeID ID;
- ID.AddPointer(Base.getOpaqueValue());
- ID.AddInteger(Base.getCallIndex());
- ID.AddInteger(Base.getVersion());
- return ID.ComputeHash();
+ return hash_value(Base);
}
bool llvm::DenseMapInfo<clang::APValue::LValueBase>::isEqual(
@@ -164,9 +219,11 @@ APValue::UnionData::~UnionData () {
delete Value;
}
-APValue::APValue(const APValue &RHS) : Kind(Uninitialized) {
+APValue::APValue(const APValue &RHS) : Kind(None) {
switch (RHS.getKind()) {
- case Uninitialized:
+ case None:
+ case Indeterminate:
+ Kind = RHS.getKind();
break;
case Int:
MakeInt();
@@ -176,6 +233,11 @@ APValue::APValue(const APValue &RHS) : Kind(Uninitialized) {
MakeFloat();
setFloat(RHS.getFloat());
break;
+ case FixedPoint: {
+ APFixedPoint FXCopy = RHS.getFixedPoint();
+ MakeFixedPoint(std::move(FXCopy));
+ break;
+ }
case Vector:
MakeVector();
setVector(((const Vec *)(const char *)RHS.Data.buffer)->Elts,
@@ -233,6 +295,8 @@ void APValue::DestroyDataAndMakeUninit() {
((APSInt*)(char*)Data.buffer)->~APSInt();
else if (Kind == Float)
((APFloat*)(char*)Data.buffer)->~APFloat();
+ else if (Kind == FixedPoint)
+ ((APFixedPoint *)(char *)Data.buffer)->~APFixedPoint();
else if (Kind == Vector)
((Vec*)(char*)Data.buffer)->~Vec();
else if (Kind == ComplexInt)
@@ -251,12 +315,13 @@ void APValue::DestroyDataAndMakeUninit() {
((MemberPointerData*)(char*)Data.buffer)->~MemberPointerData();
else if (Kind == AddrLabelDiff)
((AddrLabelDiffData*)(char*)Data.buffer)->~AddrLabelDiffData();
- Kind = Uninitialized;
+ Kind = None;
}
bool APValue::needsCleanup() const {
switch (getKind()) {
- case Uninitialized:
+ case None:
+ case Indeterminate:
case AddrLabelDiff:
return false;
case Struct:
@@ -268,6 +333,8 @@ bool APValue::needsCleanup() const {
return getInt().needsCleanup();
case Float:
return getFloat().needsCleanup();
+ case FixedPoint:
+ return getFixedPoint().getValue().needsCleanup();
case ComplexFloat:
assert(getComplexFloatImag().needsCleanup() ==
getComplexFloatReal().needsCleanup() &&
@@ -312,8 +379,11 @@ static double GetApproxValue(const llvm::APFloat &F) {
void APValue::dump(raw_ostream &OS) const {
switch (getKind()) {
- case Uninitialized:
- OS << "Uninitialized";
+ case None:
+ OS << "None";
+ return;
+ case Indeterminate:
+ OS << "Indeterminate";
return;
case Int:
OS << "Int: " << getInt();
@@ -321,6 +391,9 @@ void APValue::dump(raw_ostream &OS) const {
case Float:
OS << "Float: " << GetApproxValue(getFloat());
return;
+ case FixedPoint:
+ OS << "FixedPoint : " << getFixedPoint();
+ return;
case Vector:
OS << "Vector: ";
getVectorElt(0).dump(OS);
@@ -383,9 +456,13 @@ void APValue::dump(raw_ostream &OS) const {
llvm_unreachable("Unknown APValue kind!");
}
-void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
+void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx,
+ QualType Ty) const {
switch (getKind()) {
- case APValue::Uninitialized:
+ case APValue::None:
+ Out << "<out of lifetime>";
+ return;
+ case APValue::Indeterminate:
Out << "<uninitialized>";
return;
case APValue::Int:
@@ -397,6 +474,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
case APValue::Float:
Out << GetApproxValue(getFloat());
return;
+ case APValue::FixedPoint:
+ Out << getFixedPoint();
+ return;
case APValue::Vector: {
Out << '{';
QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
@@ -453,7 +533,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
Out << *VD;
- else {
+ else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
+ TI.print(Out, Ctx.getPrintingPolicy());
+ } else {
assert(Base.get<const Expr *>() != nullptr &&
"Expecting non-null Expr");
Base.get<const Expr*>()->printPretty(Out, nullptr,
@@ -478,6 +560,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
Out << *VD;
ElemTy = VD->getType();
+ } else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
+ TI.print(Out, Ctx.getPrintingPolicy());
+ ElemTy = Base.getTypeInfoType();
} else {
const Expr *E = Base.get<const Expr*>();
assert(E != nullptr && "Expecting non-null Expr");
@@ -491,8 +576,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
if (ElemTy->getAs<RecordType>()) {
// The lvalue refers to a class type, so the next path entry is a base
// or member.
- const Decl *BaseOrMember =
- BaseOrMemberType::getFromOpaqueValue(Path[I].BaseOrMember).getPointer();
+ const Decl *BaseOrMember = Path[I].getAsBaseOrMember().getPointer();
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
CastToBase = RD;
ElemTy = Ctx.getRecordType(RD);
@@ -506,7 +590,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
}
} else {
// The lvalue must refer to an array.
- Out << '[' << Path[I].ArrayIndex << ']';
+ Out << '[' << Path[I].getAsArrayIndex() << ']';
ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType();
}
}
@@ -592,7 +676,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
llvm_unreachable("Unknown APValue kind!");
}
-std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const {
+std::string APValue::getAsString(const ASTContext &Ctx, QualType Ty) const {
std::string Result;
llvm::raw_string_ostream Out(Result);
printPretty(Out, Ctx, Ty);
@@ -600,6 +684,26 @@ std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const {
return Result;
}
+bool APValue::toIntegralConstant(APSInt &Result, QualType SrcTy,
+ const ASTContext &Ctx) const {
+ if (isInt()) {
+ Result = getInt();
+ return true;
+ }
+
+ if (isLValue() && isNullPointer()) {
+ Result = Ctx.MakeIntValue(Ctx.getTargetNullPointerValue(SrcTy), SrcTy);
+ return true;
+ }
+
+ if (isLValue() && !getLValueBase()) {
+ Result = Ctx.MakeIntValue(getLValueOffset().getQuantity(), SrcTy);
+ return true;
+ }
+
+ return false;
+}
+
const APValue::LValueBase APValue::getLValueBase() const {
assert(isLValue() && "Invalid accessor");
return ((const LV*)(const void*)Data.buffer)->Base;
@@ -687,21 +791,21 @@ ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
}
void APValue::MakeLValue() {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
static_assert(sizeof(LV) <= DataSize, "LV too big");
new ((void*)(char*)Data.buffer) LV();
Kind = LValue;
}
void APValue::MakeArray(unsigned InitElts, unsigned Size) {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
new ((void*)(char*)Data.buffer) Arr(InitElts, Size);
Kind = Array;
}
void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
ArrayRef<const CXXRecordDecl*> Path) {
- assert(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData;
Kind = MemberPointer;
MPD->MemberAndIsDerivedMember.setPointer(Member);
diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp
index 55033b238c660..6bba8f1f80a93 100644
--- a/lib/AST/ASTConsumer.cpp
+++ b/lib/AST/ASTConsumer.cpp
@@ -1,9 +1,8 @@
//===--- ASTConsumer.cpp - Abstract interface for reading ASTs --*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 21b6f36e9aa77..0d69eb90abaf6 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1,9 +1,8 @@
//===- ASTContext.cpp - Context to hold long-lived AST nodes --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -95,38 +94,18 @@
using namespace clang;
-unsigned ASTContext::NumImplicitDefaultConstructors;
-unsigned ASTContext::NumImplicitDefaultConstructorsDeclared;
-unsigned ASTContext::NumImplicitCopyConstructors;
-unsigned ASTContext::NumImplicitCopyConstructorsDeclared;
-unsigned ASTContext::NumImplicitMoveConstructors;
-unsigned ASTContext::NumImplicitMoveConstructorsDeclared;
-unsigned ASTContext::NumImplicitCopyAssignmentOperators;
-unsigned ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
-unsigned ASTContext::NumImplicitMoveAssignmentOperators;
-unsigned ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
-unsigned ASTContext::NumImplicitDestructors;
-unsigned ASTContext::NumImplicitDestructorsDeclared;
-
enum FloatingRank {
Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank
};
RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
- 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;
- }
-
assert(D);
+ // If we already tried to load comments but there are none,
+ // we won't find anything.
+ if (CommentsLoaded && Comments.getComments().empty())
+ return nullptr;
+
// User can not attach documentation to implicit declarations.
if (D->isImplicit())
return nullptr;
@@ -176,12 +155,6 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
isa<TemplateTemplateParmDecl>(D))
return nullptr;
- ArrayRef<RawComment *> RawComments = Comments.getComments();
-
- // If there are no comments anywhere, we won't find anything.
- if (RawComments.empty())
- return nullptr;
-
// Find declaration location.
// For Objective-C declarations we generally don't expect to have multiple
// declarators, thus use declaration starting location as the "declaration
@@ -220,6 +193,23 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
if (DeclLoc.isInvalid() || !DeclLoc.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())
+ return nullptr;
+
// Find the comment that occurs just after this declaration.
ArrayRef<RawComment *>::iterator Comment;
{
@@ -238,12 +228,11 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
if (Found) {
Comment = MaybeBeforeDecl + 1;
- assert(Comment == std::lower_bound(RawComments.begin(), RawComments.end(),
- &CommentAtDeclLoc, Compare));
+ assert(Comment ==
+ llvm::lower_bound(RawComments, &CommentAtDeclLoc, Compare));
} else {
// Slow path.
- Comment = std::lower_bound(RawComments.begin(), RawComments.end(),
- &CommentAtDeclLoc, Compare);
+ Comment = llvm::lower_bound(RawComments, &CommentAtDeclLoc, Compare);
}
}
@@ -265,6 +254,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
SourceMgr.getLineNumber(DeclLocDecomp.first, DeclLocDecomp.second)
== SourceMgr.getLineNumber(CommentBeginDecomp.first,
CommentBeginDecomp.second)) {
+ (**Comment).setAttached();
return *Comment;
}
}
@@ -306,6 +296,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
if (Text.find_first_of(";{}#@") != StringRef::npos)
return nullptr;
+ (**Comment).setAttached();
return *Comment;
}
@@ -835,6 +826,9 @@ ASTContext::~ASTContext() {
for (const auto &Value : ModuleInitializers)
Value.second->~PerModuleInitializers();
+
+ for (APValue *Value : APValueCleanups)
+ Value->~APValue();
}
class ASTContext::ParentMap {
@@ -913,7 +907,7 @@ void ASTContext::setTraversalScope(const std::vector<Decl *> &TopLevelDecls) {
Parents.reset();
}
-void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) {
+void ASTContext::AddDeallocation(void (*Callback)(void *), void *Data) const {
Deallocations.push_back({Callback, Data});
}
@@ -1391,24 +1385,6 @@ ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst,
TemplateOrInstantiation[Inst] = TSI;
}
-FunctionDecl *ASTContext::getClassScopeSpecializationPattern(
- const FunctionDecl *FD){
- assert(FD && "Specialization is 0");
- llvm::DenseMap<const FunctionDecl*, FunctionDecl *>::const_iterator Pos
- = ClassScopeSpecializationPattern.find(FD);
- if (Pos == ClassScopeSpecializationPattern.end())
- return nullptr;
-
- return Pos->second;
-}
-
-void ASTContext::setClassScopeSpecializationPattern(FunctionDecl *FD,
- FunctionDecl *Pattern) {
- assert(FD && "Specialization is 0");
- assert(Pattern && "Class scope specialization pattern is 0");
- ClassScopeSpecializationPattern[FD] = Pattern;
-}
-
NamedDecl *
ASTContext::getInstantiatedFromUsingDecl(NamedDecl *UUD) {
auto Pos = InstantiatedFromUsingDecl.find(UUD);
@@ -1548,8 +1524,14 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
return Target->getHalfFormat();
case BuiltinType::Float: return Target->getFloatFormat();
case BuiltinType::Double: return Target->getDoubleFormat();
- case BuiltinType::LongDouble: return Target->getLongDoubleFormat();
- case BuiltinType::Float128: return Target->getFloat128Format();
+ case BuiltinType::LongDouble:
+ if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice)
+ return AuxTarget->getLongDoubleFormat();
+ return Target->getLongDoubleFormat();
+ case BuiltinType::Float128:
+ if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice)
+ return AuxTarget->getFloat128Format();
+ return Target->getFloat128Format();
}
}
@@ -1610,8 +1592,10 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
if (BaseT.getQualifiers().hasUnaligned())
Align = Target->getCharWidth();
if (const auto *VD = dyn_cast<VarDecl>(D)) {
- if (VD->hasGlobalStorage() && !ForAlignof)
- Align = std::max(Align, getTargetInfo().getMinGlobalAlign());
+ if (VD->hasGlobalStorage() && !ForAlignof) {
+ uint64_t TypeSize = getTypeSize(T.getTypePtr());
+ Align = std::max(Align, getTargetInfo().getMinGlobalAlign(TypeSize));
+ }
}
}
@@ -1916,8 +1900,16 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
break;
case BuiltinType::Float16:
case BuiltinType::Half:
- Width = Target->getHalfWidth();
- Align = Target->getHalfAlign();
+ if (Target->hasFloat16Type() || !getLangOpts().OpenMP ||
+ !getLangOpts().OpenMPIsDevice) {
+ Width = Target->getHalfWidth();
+ Align = Target->getHalfAlign();
+ } else {
+ assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice &&
+ "Expected OpenMP device compilation.");
+ Width = AuxTarget->getHalfWidth();
+ Align = AuxTarget->getHalfAlign();
+ }
break;
case BuiltinType::Float:
Width = Target->getFloatWidth();
@@ -1928,12 +1920,27 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Align = Target->getDoubleAlign();
break;
case BuiltinType::LongDouble:
- Width = Target->getLongDoubleWidth();
- Align = Target->getLongDoubleAlign();
+ if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice &&
+ (Target->getLongDoubleWidth() != AuxTarget->getLongDoubleWidth() ||
+ Target->getLongDoubleAlign() != AuxTarget->getLongDoubleAlign())) {
+ Width = AuxTarget->getLongDoubleWidth();
+ Align = AuxTarget->getLongDoubleAlign();
+ } else {
+ Width = Target->getLongDoubleWidth();
+ Align = Target->getLongDoubleAlign();
+ }
break;
case BuiltinType::Float128:
- Width = Target->getFloat128Width();
- Align = Target->getFloat128Align();
+ if (Target->hasFloat128Type() || !getLangOpts().OpenMP ||
+ !getLangOpts().OpenMPIsDevice) {
+ Width = Target->getFloat128Width();
+ Align = Target->getFloat128Align();
+ } else {
+ assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice &&
+ "Expected OpenMP device compilation.");
+ Width = AuxTarget->getFloat128Width();
+ Align = AuxTarget->getFloat128Align();
+ }
break;
case BuiltinType::NullPtr:
Width = Target->getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t)
@@ -2057,6 +2064,10 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::Paren:
return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr());
+ case Type::MacroQualified:
+ return getTypeInfo(
+ cast<MacroQualifiedType>(T)->getUnderlyingType().getTypePtr());
+
case Type::ObjCTypeParam:
return getTypeInfo(cast<ObjCTypeParamType>(T)->desugar().getTypePtr());
@@ -2134,7 +2145,7 @@ unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const {
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
UnadjustedAlign = toBits(Layout.getUnadjustedAlignment());
} else {
- UnadjustedAlign = getTypeAlign(T);
+ UnadjustedAlign = getTypeAlign(T->getUnqualifiedDesugaredType());
}
MemoizedUnadjustedAlign[T] = UnadjustedAlign;
@@ -2233,7 +2244,8 @@ unsigned ASTContext::getTargetDefaultAlignForAttributeAligned() const {
/// getAlignOfGlobalVar - Return the alignment in bits that should be given
/// to a global variable of the specified type.
unsigned ASTContext::getAlignOfGlobalVar(QualType T) const {
- return std::max(getTypeAlign(T), getTargetInfo().getMinGlobalAlign());
+ uint64_t TypeSize = getTypeSize(T.getTypePtr());
+ return std::max(getTypeAlign(T), getTargetInfo().getMinGlobalAlign(TypeSize));
}
/// getAlignOfGlobalVarInChars - Return the alignment in characters that
@@ -2574,7 +2586,7 @@ ASTContext::getBlockVarCopyInit(const VarDecl*VD) const {
return {nullptr, false};
}
-/// Set the copy inialization expression of a block var decl.
+/// Set the copy initialization expression of a block var decl.
void ASTContext::setBlockVarCopyInit(const VarDecl*VD, Expr *CopyExpr,
bool CanThrow) {
assert(VD && CopyExpr && "Passed null params");
@@ -2763,6 +2775,12 @@ QualType ASTContext::getFunctionTypeWithExceptionSpec(
return getParenType(
getFunctionTypeWithExceptionSpec(PT->getInnerType(), ESI));
+ // Might be wrapped in a macro qualified type.
+ if (const auto *MQT = dyn_cast<MacroQualifiedType>(Orig))
+ return getMacroQualifiedType(
+ getFunctionTypeWithExceptionSpec(MQT->getUnderlyingType(), ESI),
+ MQT->getMacroIdentifier());
+
// Might have a calling-convention attribute.
if (const auto *AT = dyn_cast<AttributedType>(Orig))
return getAttributedType(
@@ -2772,7 +2790,7 @@ QualType ASTContext::getFunctionTypeWithExceptionSpec(
// Anything else must be a function type. Rebuild it with the new exception
// specification.
- const auto *Proto = cast<FunctionProtoType>(Orig);
+ const auto *Proto = Orig->getAs<FunctionProtoType>();
return getFunctionType(
Proto->getReturnType(), Proto->getParamTypes(),
Proto->getExtProtoInfo().withExceptionSpec(ESI));
@@ -3739,7 +3757,10 @@ QualType ASTContext::getFunctionTypeInternal(
break;
}
- case EST_DynamicNone: case EST_BasicNoexcept: case EST_NoexceptTrue:
+ case EST_DynamicNone:
+ case EST_BasicNoexcept:
+ case EST_NoexceptTrue:
+ case EST_NoThrow:
CanonicalEPI.ExceptionSpec.Type = EST_BasicNoexcept;
break;
@@ -3938,7 +3959,7 @@ QualType ASTContext::getAttributedType(attr::Kind attrKind,
QualType canon = getCanonicalType(equivalentType);
type = new (*this, TypeAlignment)
- AttributedType(canon, attrKind, modifiedType, equivalentType);
+ AttributedType(canon, attrKind, modifiedType, equivalentType);
Types.push_back(type);
AttributedTypes.InsertNode(type, insertPos);
@@ -4219,6 +4240,19 @@ ASTContext::getParenType(QualType InnerType) const {
return QualType(T, 0);
}
+QualType
+ASTContext::getMacroQualifiedType(QualType UnderlyingTy,
+ const IdentifierInfo *MacroII) const {
+ QualType Canon = UnderlyingTy;
+ if (!Canon.isCanonical())
+ Canon = getCanonicalType(UnderlyingTy);
+
+ auto *newType = new (*this, TypeAlignment)
+ MacroQualifiedType(UnderlyingTy, Canon, MacroII);
+ Types.push_back(newType);
+ return QualType(newType, 0);
+}
+
QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
@@ -4356,7 +4390,13 @@ QualType ASTContext::getPackExpansionType(QualType Pattern,
llvm::FoldingSetNodeID ID;
PackExpansionType::Profile(ID, Pattern, NumExpansions);
- assert(Pattern->containsUnexpandedParameterPack() &&
+ // A deduced type can deduce to a pack, eg
+ // auto ...x = some_pack;
+ // That declaration isn't (yet) valid, but is created as part of building an
+ // init-capture pack:
+ // [...x = some_pack] {}
+ assert((Pattern->containsUnexpandedParameterPack() ||
+ Pattern->getContainedDeducedType()) &&
"Pack expansions must expand one or more parameter packs");
void *InsertPos = nullptr;
PackExpansionType *T
@@ -4856,19 +4896,20 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
/// 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) const {
+ bool IsDependent, bool IsPack) const {
+ assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack");
if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent)
return getAutoDeductType();
// Look in the folding set for an existing type.
void *InsertPos = nullptr;
llvm::FoldingSetNodeID ID;
- AutoType::Profile(ID, DeducedType, Keyword, IsDependent);
+ AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack);
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(AT, 0);
auto *AT = new (*this, TypeAlignment)
- AutoType(DeducedType, Keyword, IsDependent);
+ AutoType(DeducedType, Keyword, IsDependent, IsPack);
Types.push_back(AT);
if (InsertPos)
AutoTypes.InsertNode(AT, InsertPos);
@@ -4930,7 +4971,7 @@ QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull())
AutoDeductTy = QualType(
new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto,
- /*dependent*/false),
+ /*dependent*/false, /*pack*/false),
0);
return AutoDeductTy;
}
@@ -5218,6 +5259,11 @@ ASTContext::getNameForTemplate(TemplateName Name,
return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc);
}
+ case TemplateName::AssumedTemplate: {
+ AssumedTemplateStorage *Storage = Name.getAsAssumedTemplateName();
+ return DeclarationNameInfo(Storage->getDeclName(), NameLoc);
+ }
+
case TemplateName::DependentTemplate: {
DependentTemplateName *DTN = Name.getAsDependentTemplateName();
DeclarationName DName;
@@ -5265,7 +5311,8 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const {
}
case TemplateName::OverloadedTemplate:
- llvm_unreachable("cannot canonicalize overloaded template");
+ case TemplateName::AssumedTemplate:
+ llvm_unreachable("cannot canonicalize unresolved template");
case TemplateName::DependentTemplate: {
DependentTemplateName *DTN = Name.getAsDependentTemplateName();
@@ -5609,6 +5656,12 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) const {
return -1;
}
+int ASTContext::getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const {
+ if (&getFloatTypeSemantics(LHS) == &getFloatTypeSemantics(RHS))
+ return 0;
+ return getFloatingTypeOrder(LHS, RHS);
+}
+
/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This
/// routine will assert if passed a built-in type that isn't an integer or enum,
/// or if it is not canonicalized.
@@ -6283,12 +6336,13 @@ void ASTContext::getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT,
// Encode type qualifer, 'in', 'inout', etc. for the parameter.
getObjCEncodingForTypeQualifier(QT, S);
// Encode parameter type.
- getObjCEncodingForTypeImpl(T, S, true, true, nullptr,
- true /*OutermostType*/,
- false /*EncodingProperty*/,
- false /*StructField*/,
- Extended /*EncodeBlockParameters*/,
- Extended /*EncodeClassNames*/);
+ ObjCEncOptions Options = ObjCEncOptions()
+ .setExpandPointedToStructures()
+ .setExpandStructures()
+ .setIsOutermostType();
+ if (Extended)
+ Options.setEncodeBlockParameters().setEncodeClassNames();
+ getObjCEncodingForTypeImpl(T, S, Options, /*Field=*/nullptr);
}
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
@@ -6480,9 +6534,12 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
// directly pointed to, and expanding embedded structures. Note that
// these rules are sufficient to prevent recursive encoding of the
// same type.
- getObjCEncodingForTypeImpl(T, S, true, true, Field,
- true /* outermost type */, false, false,
- false, false, false, NotEncodedT);
+ getObjCEncodingForTypeImpl(T, S,
+ ObjCEncOptions()
+ .setExpandPointedToStructures()
+ .setExpandStructures()
+ .setIsOutermostType(),
+ Field, NotEncodedT);
}
void ASTContext::getObjCEncodingForPropertyType(QualType T,
@@ -6490,9 +6547,13 @@ void ASTContext::getObjCEncodingForPropertyType(QualType T,
// Encode result type.
// GCC has some special rules regarding encoding of properties which
// closely resembles encoding of ivars.
- getObjCEncodingForTypeImpl(T, S, true, true, nullptr,
- true /* outermost type */,
- true /* encoding property */);
+ getObjCEncodingForTypeImpl(T, S,
+ ObjCEncOptions()
+ .setExpandPointedToStructures()
+ .setExpandStructures()
+ .setIsOutermostType()
+ .setEncodingProperty(),
+ /*Field=*/nullptr);
}
static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
@@ -6639,16 +6700,9 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
}
// FIXME: Use SmallString for accumulating string.
-void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
- bool ExpandPointedToStructures,
- bool ExpandStructures,
+void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
+ const ObjCEncOptions Options,
const FieldDecl *FD,
- bool OutermostType,
- bool EncodingProperty,
- bool StructField,
- bool EncodeBlockParameters,
- bool EncodeClassNames,
- bool EncodePointerToObjCTypedef,
QualType *NotEncodedT) const {
CanQualType CT = getCanonicalType(T);
switch (CT->getTypeClass()) {
@@ -6665,14 +6719,16 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
case Type::Complex: {
const auto *CT = T->castAs<ComplexType>();
S += 'j';
- getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, nullptr);
+ getObjCEncodingForTypeImpl(CT->getElementType(), S, ObjCEncOptions(),
+ /*Field=*/nullptr);
return;
}
case Type::Atomic: {
const auto *AT = T->castAs<AtomicType>();
S += 'A';
- getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, nullptr);
+ getObjCEncodingForTypeImpl(AT->getValueType(), S, ObjCEncOptions(),
+ /*Field=*/nullptr);
return;
}
@@ -6698,11 +6754,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// the pointer itself gets ignored, _unless_ we are looking at a typedef!
// Also, do not emit the 'r' for anything but the outermost type!
if (isa<TypedefType>(T.getTypePtr())) {
- if (OutermostType && T.isConstQualified()) {
+ if (Options.IsOutermostType() && T.isConstQualified()) {
isReadOnly = true;
S += 'r';
}
- } else if (OutermostType) {
+ } else if (Options.IsOutermostType()) {
QualType P = PointeeTy;
while (P->getAs<PointerType>())
P = P->getAs<PointerType>()->getPointeeType();
@@ -6742,9 +6798,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S += '^';
getLegacyIntegralTypeEncoding(PointeeTy);
- getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures,
- nullptr, false, false, false, false, false, false,
- NotEncodedT);
+ ObjCEncOptions NewOptions;
+ if (Options.ExpandPointedToStructures())
+ NewOptions.setExpandStructures();
+ getObjCEncodingForTypeImpl(PointeeTy, S, NewOptions,
+ /*Field=*/nullptr, NotEncodedT);
return;
}
@@ -6753,12 +6811,13 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
case Type::VariableArray: {
const auto *AT = cast<ArrayType>(CT);
- if (isa<IncompleteArrayType>(AT) && !StructField) {
+ if (isa<IncompleteArrayType>(AT) && !Options.IsStructField()) {
// Incomplete arrays are encoded as a pointer to the array element.
S += '^';
- getObjCEncodingForTypeImpl(AT->getElementType(), S,
- false, ExpandStructures, FD);
+ getObjCEncodingForTypeImpl(
+ AT->getElementType(), S,
+ Options.keepingOnly(ObjCEncOptions().setExpandStructures()), FD);
} else {
S += '[';
@@ -6771,10 +6830,10 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S += '0';
}
- getObjCEncodingForTypeImpl(AT->getElementType(), S,
- false, ExpandStructures, FD,
- false, false, false, false, false, false,
- NotEncodedT);
+ getObjCEncodingForTypeImpl(
+ AT->getElementType(), S,
+ Options.keepingOnly(ObjCEncOptions().setExpandStructures()), FD,
+ NotEncodedT);
S += ']';
}
return;
@@ -6800,7 +6859,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
} else {
S += '?';
}
- if (ExpandStructures) {
+ if (Options.ExpandStructures()) {
S += '=';
if (!RDecl->isUnion()) {
getObjCEncodingForStructureImpl(RDecl, S, FD, true, NotEncodedT);
@@ -6814,16 +6873,16 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// Special case bit-fields.
if (Field->isBitField()) {
- getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
+ getObjCEncodingForTypeImpl(Field->getType(), S,
+ ObjCEncOptions().setExpandStructures(),
Field);
} else {
QualType qt = Field->getType();
getLegacyIntegralTypeEncoding(qt);
- getObjCEncodingForTypeImpl(qt, S, false, true,
- FD, /*OutermostType*/false,
- /*EncodingProperty*/false,
- /*StructField*/true,
- false, false, false, NotEncodedT);
+ getObjCEncodingForTypeImpl(
+ qt, S,
+ ObjCEncOptions().setExpandStructures().setIsStructField(), FD,
+ NotEncodedT);
}
}
}
@@ -6835,26 +6894,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
case Type::BlockPointer: {
const auto *BT = T->castAs<BlockPointerType>();
S += "@?"; // Unlike a pointer-to-function, which is "^?".
- if (EncodeBlockParameters) {
+ if (Options.EncodeBlockParameters()) {
const auto *FT = BT->getPointeeType()->castAs<FunctionType>();
S += '<';
// Block return type
- getObjCEncodingForTypeImpl(
- FT->getReturnType(), S, ExpandPointedToStructures, ExpandStructures,
- FD, false /* OutermostType */, EncodingProperty,
- false /* StructField */, EncodeBlockParameters, EncodeClassNames, false,
- NotEncodedT);
+ getObjCEncodingForTypeImpl(FT->getReturnType(), S,
+ Options.forComponentType(), FD, NotEncodedT);
// Block self
S += "@?";
// Block parameters
if (const auto *FPT = dyn_cast<FunctionProtoType>(FT)) {
for (const auto &I : FPT->param_types())
- getObjCEncodingForTypeImpl(
- I, S, ExpandPointedToStructures, ExpandStructures, FD,
- false /* OutermostType */, EncodingProperty,
- false /* StructField */, EncodeBlockParameters, EncodeClassNames,
- false, NotEncodedT);
+ getObjCEncodingForTypeImpl(I, S, Options.forComponentType(), FD,
+ NotEncodedT);
}
S += '>';
}
@@ -6882,18 +6935,19 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
ObjCInterfaceDecl *OI = T->castAs<ObjCObjectType>()->getInterface();
S += '{';
S += OI->getObjCRuntimeNameAsString();
- if (ExpandStructures) {
+ if (Options.ExpandStructures()) {
S += '=';
SmallVector<const ObjCIvarDecl*, 32> Ivars;
DeepCollectObjCIvars(OI, true, Ivars);
for (unsigned i = 0, e = Ivars.size(); i != e; ++i) {
const FieldDecl *Field = Ivars[i];
if (Field->isBitField())
- getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field);
+ getObjCEncodingForTypeImpl(Field->getType(), S,
+ ObjCEncOptions().setExpandStructures(),
+ Field);
else
- getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD,
- false, false, false, false, false,
- EncodePointerToObjCTypedef,
+ getObjCEncodingForTypeImpl(Field->getType(), S,
+ ObjCEncOptions().setExpandStructures(), FD,
NotEncodedT);
}
}
@@ -6910,17 +6964,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) {
// FIXME: Consider if we need to output qualifiers for 'Class<p>'.
- // Since this is a binary compatibility issue, need to consult with runtime
- // folks. Fortunately, this is a *very* obscure construct.
+ // Since this is a binary compatibility issue, need to consult with
+ // runtime folks. Fortunately, this is a *very* obscure construct.
S += '#';
return;
}
if (OPT->isObjCQualifiedIdType()) {
- getObjCEncodingForTypeImpl(getObjCIdType(), S,
- ExpandPointedToStructures,
- ExpandStructures, FD);
- if (FD || EncodingProperty || EncodeClassNames) {
+ getObjCEncodingForTypeImpl(
+ getObjCIdType(), S,
+ Options.keepingOnly(ObjCEncOptions()
+ .setExpandPointedToStructures()
+ .setExpandStructures()),
+ FD);
+ if (FD || Options.EncodingProperty() || Options.EncodeClassNames()) {
// Note that we do extended encoding of protocol qualifer list
// Only when doing ivar or property encoding.
S += '"';
@@ -6934,39 +6991,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
- QualType PointeeTy = OPT->getPointeeType();
- if (!EncodingProperty &&
- isa<TypedefType>(PointeeTy.getTypePtr()) &&
- !EncodePointerToObjCTypedef) {
- // Another historical/compatibility reason.
- // We encode the underlying type which comes out as
- // {...};
- S += '^';
- if (FD && OPT->getInterfaceDecl()) {
- // Prevent recursive encoding of fields in some rare cases.
- ObjCInterfaceDecl *OI = OPT->getInterfaceDecl();
- SmallVector<const ObjCIvarDecl*, 32> Ivars;
- DeepCollectObjCIvars(OI, true, Ivars);
- for (unsigned i = 0, e = Ivars.size(); i != e; ++i) {
- if (Ivars[i] == FD) {
- S += '{';
- S += OI->getObjCRuntimeNameAsString();
- S += '}';
- return;
- }
- }
- }
- getObjCEncodingForTypeImpl(PointeeTy, S,
- false, ExpandPointedToStructures,
- nullptr,
- false, false, false, false, false,
- /*EncodePointerToObjCTypedef*/true);
- return;
- }
-
S += '@';
if (OPT->getInterfaceDecl() &&
- (FD || EncodingProperty || EncodeClassNames)) {
+ (FD || Options.EncodingProperty() || Options.EncodeClassNames())) {
S += '"';
S += OPT->getInterfaceDecl()->getObjCRuntimeNameAsString();
for (const auto *I : OPT->quals()) {
@@ -6980,7 +7007,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
}
// gcc just blithely ignores member pointers.
- // FIXME: we shoul do better than that. 'M' is available.
+ // FIXME: we should do better than that. 'M' is available.
case Type::MemberPointer:
// This matches gcc's encoding, even though technically it is insufficient.
//FIXME. We should do a better job than gcc.
@@ -7142,11 +7169,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
} else {
QualType qt = field->getType();
getLegacyIntegralTypeEncoding(qt);
- getObjCEncodingForTypeImpl(qt, S, false, true, FD,
- /*OutermostType*/false,
- /*EncodingProperty*/false,
- /*StructField*/true,
- false, false, false, NotEncodedT);
+ getObjCEncodingForTypeImpl(
+ qt, S, ObjCEncOptions().setExpandStructures().setIsStructField(),
+ FD, NotEncodedT);
#ifndef NDEBUG
CurOffs += getTypeSize(field->getType());
#endif
@@ -7606,6 +7631,13 @@ ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin,
return TemplateName(OT);
}
+/// Retrieve a template name representing an unqualified-id that has been
+/// assumed to name a template for ADL purposes.
+TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const {
+ auto *OT = new (*this) AssumedTemplateStorage(Name);
+ return TemplateName(OT);
+}
+
/// Retrieve the template name that represents a qualified
/// template name such as \c std::vector.
TemplateName
@@ -8581,7 +8613,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lproto->isVariadic() != rproto->isVariadic())
return {};
- if (lproto->getTypeQuals() != rproto->getTypeQuals())
+ if (lproto->getMethodQuals() != rproto->getMethodQuals())
return {};
SmallVector<FunctionProtoType::ExtParameterInfo, 4> newParamInfos;
@@ -9246,7 +9278,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
// Read the prefixed modifiers first.
bool Done = false;
#ifndef NDEBUG
- bool IsSpecialLong = false;
+ bool IsSpecial = false;
#endif
while (!Done) {
switch (*Str++) {
@@ -9265,26 +9297,26 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
Unsigned = true;
break;
case 'L':
- assert(!IsSpecialLong && "Can't use 'L' with 'W' or 'N' modifiers");
+ assert(!IsSpecial && "Can't use 'L' with 'W', 'N', 'Z' or 'O' modifiers");
assert(HowLong <= 2 && "Can't have LLLL modifier");
++HowLong;
break;
case 'N':
// 'N' behaves like 'L' for all non LP64 targets and 'int' otherwise.
- assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!");
+ assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!");
assert(HowLong == 0 && "Can't use both 'L' and 'N' modifiers!");
#ifndef NDEBUG
- IsSpecialLong = true;
+ IsSpecial = true;
#endif
if (Context.getTargetInfo().getLongWidth() == 32)
++HowLong;
break;
case 'W':
// This modifier represents int64 type.
- assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!");
+ assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!");
assert(HowLong == 0 && "Can't use both 'L' and 'W' modifiers!");
#ifndef NDEBUG
- IsSpecialLong = true;
+ IsSpecial = true;
#endif
switch (Context.getTargetInfo().getInt64Type()) {
default:
@@ -9297,6 +9329,38 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
break;
}
break;
+ case 'Z':
+ // This modifier represents int32 type.
+ assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!");
+ assert(HowLong == 0 && "Can't use both 'L' and 'Z' modifiers!");
+ #ifndef NDEBUG
+ IsSpecial = true;
+ #endif
+ switch (Context.getTargetInfo().getIntTypeByWidth(32, true)) {
+ default:
+ llvm_unreachable("Unexpected integer type");
+ case TargetInfo::SignedInt:
+ HowLong = 0;
+ break;
+ case TargetInfo::SignedLong:
+ HowLong = 1;
+ break;
+ case TargetInfo::SignedLongLong:
+ HowLong = 2;
+ break;
+ }
+ break;
+ case 'O':
+ assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!");
+ assert(HowLong == 0 && "Can't use both 'L' and 'O' modifiers!");
+ #ifndef NDEBUG
+ IsSpecial = true;
+ #endif
+ if (Context.getLangOpts().OpenCL)
+ HowLong = 1;
+ else
+ HowLong = 2;
+ break;
}
}
@@ -9518,6 +9582,10 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
GetBuiltinTypeError &Error,
unsigned *IntegerConstantArgs) const {
const char *TypeStr = BuiltinInfo.getTypeString(Id);
+ if (TypeStr[0] == '\0') {
+ Error = GE_Missing_type;
+ return {};
+ }
SmallVector<QualType, 8> ArgTypes;
@@ -9553,10 +9621,12 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
"'.' should only occur at end of builtin type list!");
- FunctionType::ExtInfo EI(CC_C);
+ bool Variadic = (TypeStr[0] == '.');
+
+ FunctionType::ExtInfo EI(getDefaultCallingConvention(
+ Variadic, /*IsCXXMethod=*/false, /*IsBuiltin=*/true));
if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true);
- bool Variadic = (TypeStr[0] == '.');
// We really shouldn't be making a no-proto type here.
if (ArgTypes.empty() && Variadic && !getLangOpts().CPlusPlus)
@@ -9784,12 +9854,12 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return false;
} else if (isa<PragmaCommentDecl>(D))
return true;
- else if (isa<OMPThreadPrivateDecl>(D))
- return true;
else if (isa<PragmaDetectMismatchDecl>(D))
return true;
else if (isa<OMPThreadPrivateDecl>(D))
return !D->getDeclContext()->isDependentContext();
+ else if (isa<OMPAllocateDecl>(D))
+ return !D->getDeclContext()->isDependentContext();
else if (isa<OMPDeclareReductionDecl>(D))
return !D->getDeclContext()->isDependentContext();
else if (isa<ImportDecl>(D))
@@ -9931,34 +10001,39 @@ void ASTContext::forEachMultiversionedFunctionVersion(
}
CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic,
- bool IsCXXMethod) const {
+ bool IsCXXMethod,
+ bool IsBuiltin) const {
// Pass through to the C++ ABI object
if (IsCXXMethod)
return ABI->getDefaultMethodCallConv(IsVariadic);
- switch (LangOpts.getDefaultCallingConv()) {
- case LangOptions::DCC_None:
- break;
- case LangOptions::DCC_CDecl:
- return CC_C;
- case LangOptions::DCC_FastCall:
- if (getTargetInfo().hasFeature("sse2") && !IsVariadic)
- return CC_X86FastCall;
- break;
- case LangOptions::DCC_StdCall:
- if (!IsVariadic)
- return CC_X86StdCall;
- break;
- case LangOptions::DCC_VectorCall:
- // __vectorcall cannot be applied to variadic functions.
- if (!IsVariadic)
- return CC_X86VectorCall;
- break;
- case LangOptions::DCC_RegCall:
- // __regcall cannot be applied to variadic functions.
- if (!IsVariadic)
- return CC_X86RegCall;
- break;
+ // Builtins ignore user-specified default calling convention and remain the
+ // Target's default calling convention.
+ if (!IsBuiltin) {
+ switch (LangOpts.getDefaultCallingConv()) {
+ case LangOptions::DCC_None:
+ break;
+ case LangOptions::DCC_CDecl:
+ return CC_C;
+ case LangOptions::DCC_FastCall:
+ if (getTargetInfo().hasFeature("sse2") && !IsVariadic)
+ return CC_X86FastCall;
+ break;
+ case LangOptions::DCC_StdCall:
+ if (!IsVariadic)
+ return CC_X86StdCall;
+ break;
+ case LangOptions::DCC_VectorCall:
+ // __vectorcall cannot be applied to variadic functions.
+ if (!IsVariadic)
+ return CC_X86VectorCall;
+ break;
+ case LangOptions::DCC_RegCall:
+ // __regcall cannot be applied to variadic functions.
+ if (!IsVariadic)
+ return CC_X86RegCall;
+ break;
+ }
}
return Target->getDefaultCallingConv(TargetInfo::CCMT_Unknown);
}
@@ -9978,8 +10053,10 @@ VTableContextBase *ASTContext::getVTableContext() {
return VTContext.get();
}
-MangleContext *ASTContext::createMangleContext() {
- switch (Target->getCXXABI().getKind()) {
+MangleContext *ASTContext::createMangleContext(const TargetInfo *T) {
+ if (!T)
+ T = Target;
+ switch (T->getCXXABI().getKind()) {
case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericItanium:
case TargetCXXABI::GenericARM:
@@ -10010,8 +10087,7 @@ size_t ASTContext::getSideTableAllocatedMemory() const {
llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) +
llvm::capacity_in_bytes(OverriddenMethods) +
llvm::capacity_in_bytes(Types) +
- llvm::capacity_in_bytes(VariableArrayTypes) +
- llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
+ llvm::capacity_in_bytes(VariableArrayTypes);
}
/// getIntTypeForBitwidth -
@@ -10140,6 +10216,31 @@ ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
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).
+ if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings)
+ EltTy = EltTy.withConst();
+
+ EltTy = adjustStringLiteralBaseType(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),
+ ArrayType::Normal, /*IndexTypeQuals*/ 0);
+}
+
+StringLiteral *
+ASTContext::getPredefinedStringLiteralFromCache(StringRef Key) const {
+ StringLiteral *&Result = StringLiteralCache[Key];
+ if (!Result)
+ Result = StringLiteral::Create(
+ *this, Key, StringLiteral::Ascii,
+ /*Pascal*/ false, getStringLiteralArrayType(CharTy, Key.size()),
+ SourceLocation());
+ return Result;
+}
+
bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const {
const llvm::Triple &T = getTargetInfo().getTriple();
if (!T.isOSDarwin())
@@ -10485,7 +10586,13 @@ unsigned char ASTContext::getFixedPointIBits(QualType Ty) const {
}
FixedPointSemantics ASTContext::getFixedPointSemantics(QualType Ty) const {
- assert(Ty->isFixedPointType());
+ assert((Ty->isFixedPointType() || Ty->isIntegerType()) &&
+ "Can only get the fixed point semantics for a "
+ "fixed point or integer type.");
+ if (Ty->isIntegerType())
+ return FixedPointSemantics::GetIntegerSemantics(getIntWidth(Ty),
+ Ty->isSignedIntegerType());
+
bool isSigned = Ty->isSignedFixedPointType();
return FixedPointSemantics(
static_cast<unsigned>(getTypeSize(Ty)), getFixedPointScale(Ty), isSigned,
@@ -10502,3 +10609,38 @@ APFixedPoint ASTContext::getFixedPointMin(QualType Ty) const {
assert(Ty->isFixedPointType());
return APFixedPoint::getMin(getFixedPointSemantics(Ty));
}
+
+QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
+ assert(Ty->isUnsignedFixedPointType() &&
+ "Expected unsigned fixed point type");
+ const auto *BTy = Ty->getAs<BuiltinType>();
+
+ switch (BTy->getKind()) {
+ case BuiltinType::UShortAccum:
+ return ShortAccumTy;
+ case BuiltinType::UAccum:
+ return AccumTy;
+ case BuiltinType::ULongAccum:
+ return LongAccumTy;
+ case BuiltinType::SatUShortAccum:
+ return SatShortAccumTy;
+ case BuiltinType::SatUAccum:
+ return SatAccumTy;
+ case BuiltinType::SatULongAccum:
+ return SatLongAccumTy;
+ case BuiltinType::UShortFract:
+ return ShortFractTy;
+ case BuiltinType::UFract:
+ return FractTy;
+ case BuiltinType::ULongFract:
+ return LongFractTy;
+ case BuiltinType::SatUShortFract:
+ return SatShortFractTy;
+ case BuiltinType::SatUFract:
+ return SatFractTy;
+ case BuiltinType::SatULongFract:
+ return SatLongFractTy;
+ default:
+ llvm_unreachable("Unexpected unsigned fixed point type");
+ }
+}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index dd05855585721..15df865852941 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -1,9 +1,8 @@
//===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -42,6 +41,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
QT = PT->desugar();
continue;
}
+ // ... or a macro defined type ...
+ if (const MacroQualifiedType *MDT = dyn_cast<MacroQualifiedType>(Ty)) {
+ QT = MDT->desugar();
+ continue;
+ }
// ...or a substituted template type parameter ...
if (const SubstTemplateTypeParmType *ST =
dyn_cast<SubstTemplateTypeParmType>(Ty)) {
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index b52ec21943e6d..22196a1a26004 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -1,9 +1,8 @@
//===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -12,21 +11,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTDumper.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTDumperUtils.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/AttrVisitor.h"
-#include "clang/AST/CommentVisitor.h"
-#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclLookups.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclOpenMP.h"
-#include "clang/AST/DeclVisitor.h"
-#include "clang/AST/LocInfoType.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/TemplateArgumentVisitor.h"
-#include "clang/AST/TextNodeDumper.h"
-#include "clang/AST/TypeVisitor.h"
+#include "clang/AST/JSONNodeDumper.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
@@ -34,345 +22,8 @@
using namespace clang;
using namespace clang::comments;
-//===----------------------------------------------------------------------===//
-// ASTDumper Visitor
-//===----------------------------------------------------------------------===//
-
-namespace {
-
- class ASTDumper
- : public ConstDeclVisitor<ASTDumper>,
- public ConstStmtVisitor<ASTDumper>,
- public ConstCommentVisitor<ASTDumper, void, const FullComment *>,
- public TypeVisitor<ASTDumper>,
- public ConstAttrVisitor<ASTDumper>,
- public ConstTemplateArgumentVisitor<ASTDumper> {
-
- TextNodeDumper NodeDumper;
-
- raw_ostream &OS;
-
- /// The policy to use for printing; can be defaulted.
- PrintingPolicy PrintPolicy;
-
- /// Indicates whether we should trigger deserialization of nodes that had
- /// not already been loaded.
- bool Deserialize = false;
-
- const bool ShowColors;
-
- /// Dump a child of the current node.
- template<typename Fn> void dumpChild(Fn DoDumpChild) {
- NodeDumper.AddChild(DoDumpChild);
- }
- template <typename Fn> void dumpChild(StringRef Label, Fn DoDumpChild) {
- NodeDumper.AddChild(Label, DoDumpChild);
- }
-
- public:
- ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
- const SourceManager *SM)
- : ASTDumper(OS, Traits, SM,
- SM && SM->getDiagnostics().getShowColors()) {}
-
- ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
- const SourceManager *SM, bool ShowColors)
- : ASTDumper(OS, Traits, SM, ShowColors, LangOptions()) {}
- ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
- const SourceManager *SM, bool ShowColors,
- const PrintingPolicy &PrintPolicy)
- : NodeDumper(OS, ShowColors, SM, PrintPolicy, Traits), OS(OS),
- PrintPolicy(PrintPolicy), ShowColors(ShowColors) {}
-
- void setDeserialize(bool D) { Deserialize = D; }
-
- void dumpDecl(const Decl *D);
- void dumpStmt(const Stmt *S, StringRef Label = {});
-
- // Utilities
- void dumpTypeAsChild(QualType T);
- void dumpTypeAsChild(const Type *T);
- void dumpDeclContext(const DeclContext *DC);
- void dumpLookups(const DeclContext *DC, bool DumpDecls);
- void dumpAttr(const Attr *A);
-
- // C++ Utilities
- void dumpCXXCtorInitializer(const CXXCtorInitializer *Init);
- void dumpTemplateParameters(const TemplateParameterList *TPL);
- void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI);
- void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A,
- const Decl *From = nullptr,
- const char *Label = nullptr);
- void dumpTemplateArgumentList(const TemplateArgumentList &TAL);
- void dumpTemplateArgument(const TemplateArgument &A,
- SourceRange R = SourceRange(),
- const Decl *From = nullptr,
- const char *Label = nullptr);
- template <typename SpecializationDecl>
- void dumpTemplateDeclSpecialization(const SpecializationDecl *D,
- bool DumpExplicitInst,
- bool DumpRefOnly);
- template <typename TemplateDecl>
- void dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst);
-
- // Objective-C utilities.
- void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams);
-
- // Types
- void VisitComplexType(const ComplexType *T) {
- dumpTypeAsChild(T->getElementType());
- }
- void VisitLocInfoType(const LocInfoType *T) {
- dumpTypeAsChild(T->getTypeSourceInfo()->getType());
- }
- void VisitPointerType(const PointerType *T) {
- dumpTypeAsChild(T->getPointeeType());
- }
- void VisitBlockPointerType(const BlockPointerType *T) {
- dumpTypeAsChild(T->getPointeeType());
- }
- void VisitReferenceType(const ReferenceType *T) {
- dumpTypeAsChild(T->getPointeeType());
- }
- void VisitMemberPointerType(const MemberPointerType *T) {
- dumpTypeAsChild(T->getClass());
- dumpTypeAsChild(T->getPointeeType());
- }
- void VisitArrayType(const ArrayType *T) {
- dumpTypeAsChild(T->getElementType());
- }
- void VisitVariableArrayType(const VariableArrayType *T) {
- VisitArrayType(T);
- dumpStmt(T->getSizeExpr());
- }
- void VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
- dumpTypeAsChild(T->getElementType());
- dumpStmt(T->getSizeExpr());
- }
- void VisitDependentSizedExtVectorType(
- const DependentSizedExtVectorType *T) {
- dumpTypeAsChild(T->getElementType());
- dumpStmt(T->getSizeExpr());
- }
- void VisitVectorType(const VectorType *T) {
- dumpTypeAsChild(T->getElementType());
- }
- void VisitFunctionType(const FunctionType *T) {
- dumpTypeAsChild(T->getReturnType());
- }
- void VisitFunctionProtoType(const FunctionProtoType *T) {
- VisitFunctionType(T);
- for (QualType PT : T->getParamTypes())
- dumpTypeAsChild(PT);
- if (T->getExtProtoInfo().Variadic)
- dumpChild([=] { OS << "..."; });
- }
- void VisitTypeOfExprType(const TypeOfExprType *T) {
- dumpStmt(T->getUnderlyingExpr());
- }
- void VisitDecltypeType(const DecltypeType *T) {
- dumpStmt(T->getUnderlyingExpr());
- }
- void VisitUnaryTransformType(const UnaryTransformType *T) {
- dumpTypeAsChild(T->getBaseType());
- }
- void VisitAttributedType(const AttributedType *T) {
- // FIXME: AttrKind
- dumpTypeAsChild(T->getModifiedType());
- }
- void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
- dumpTypeAsChild(T->getReplacedParameter());
- }
- void VisitSubstTemplateTypeParmPackType(
- const SubstTemplateTypeParmPackType *T) {
- dumpTypeAsChild(T->getReplacedParameter());
- dumpTemplateArgument(T->getArgumentPack());
- }
- void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
- for (auto &Arg : *T)
- dumpTemplateArgument(Arg);
- if (T->isTypeAlias())
- dumpTypeAsChild(T->getAliasedType());
- }
- void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
- dumpTypeAsChild(T->getPointeeType());
- }
- void VisitAtomicType(const AtomicType *T) {
- dumpTypeAsChild(T->getValueType());
- }
- void VisitPipeType(const PipeType *T) {
- dumpTypeAsChild(T->getElementType());
- }
- void VisitAdjustedType(const AdjustedType *T) {
- dumpTypeAsChild(T->getOriginalType());
- }
- void VisitPackExpansionType(const PackExpansionType *T) {
- if (!T->isSugared())
- dumpTypeAsChild(T->getPattern());
- }
- // FIXME: ElaboratedType, DependentNameType,
- // DependentTemplateSpecializationType, ObjCObjectType
-
- // Decls
- void VisitLabelDecl(const LabelDecl *D);
- void VisitTypedefDecl(const TypedefDecl *D);
- void VisitEnumDecl(const EnumDecl *D);
- void VisitRecordDecl(const RecordDecl *D);
- void VisitEnumConstantDecl(const EnumConstantDecl *D);
- void VisitIndirectFieldDecl(const IndirectFieldDecl *D);
- void VisitFunctionDecl(const FunctionDecl *D);
- void VisitFieldDecl(const FieldDecl *D);
- void VisitVarDecl(const VarDecl *D);
- void VisitDecompositionDecl(const DecompositionDecl *D);
- void VisitBindingDecl(const BindingDecl *D);
- void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D);
- void VisitImportDecl(const ImportDecl *D);
- void VisitPragmaCommentDecl(const PragmaCommentDecl *D);
- void VisitPragmaDetectMismatchDecl(const PragmaDetectMismatchDecl *D);
- void VisitCapturedDecl(const CapturedDecl *D);
-
- // OpenMP decls
- void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D);
- void VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D);
- void VisitOMPRequiresDecl(const OMPRequiresDecl *D);
- void VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D);
-
- // C++ Decls
- void VisitNamespaceDecl(const NamespaceDecl *D);
- void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D);
- void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D);
- void VisitTypeAliasDecl(const TypeAliasDecl *D);
- void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D);
- void VisitCXXRecordDecl(const CXXRecordDecl *D);
- void VisitStaticAssertDecl(const StaticAssertDecl *D);
- void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
- void VisitClassTemplateDecl(const ClassTemplateDecl *D);
- void VisitClassTemplateSpecializationDecl(
- const ClassTemplateSpecializationDecl *D);
- void VisitClassTemplatePartialSpecializationDecl(
- const ClassTemplatePartialSpecializationDecl *D);
- void VisitClassScopeFunctionSpecializationDecl(
- const ClassScopeFunctionSpecializationDecl *D);
- void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D);
- void VisitVarTemplateDecl(const VarTemplateDecl *D);
- void VisitVarTemplateSpecializationDecl(
- const VarTemplateSpecializationDecl *D);
- void VisitVarTemplatePartialSpecializationDecl(
- const VarTemplatePartialSpecializationDecl *D);
- void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
- void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
- void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
- void VisitUsingDecl(const UsingDecl *D);
- void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D);
- void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D);
- void VisitUsingShadowDecl(const UsingShadowDecl *D);
- void VisitConstructorUsingShadowDecl(const ConstructorUsingShadowDecl *D);
- void VisitLinkageSpecDecl(const LinkageSpecDecl *D);
- void VisitAccessSpecDecl(const AccessSpecDecl *D);
- void VisitFriendDecl(const FriendDecl *D);
-
- // ObjC Decls
- void VisitObjCIvarDecl(const ObjCIvarDecl *D);
- void VisitObjCMethodDecl(const ObjCMethodDecl *D);
- void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D);
- void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
- void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
- void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
- void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D);
- void VisitObjCImplementationDecl(const ObjCImplementationDecl *D);
- void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D);
- void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
- void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
- void Visit(const BlockDecl::Capture &C);
- void VisitBlockDecl(const BlockDecl *D);
-
- // Stmts.
- void VisitDeclStmt(const DeclStmt *Node);
- void VisitAttributedStmt(const AttributedStmt *Node);
- void VisitCXXCatchStmt(const CXXCatchStmt *Node);
- void VisitCapturedStmt(const CapturedStmt *Node);
-
- // OpenMP
- void Visit(const OMPClause *C);
- void VisitOMPExecutableDirective(const OMPExecutableDirective *Node);
-
- // Exprs
- void VisitInitListExpr(const InitListExpr *ILE);
- void VisitBlockExpr(const BlockExpr *Node);
- void VisitOpaqueValueExpr(const OpaqueValueExpr *Node);
- void VisitGenericSelectionExpr(const GenericSelectionExpr *E);
-
- // C++
- void VisitLambdaExpr(const LambdaExpr *Node) {
- dumpDecl(Node->getLambdaClass());
- }
- void VisitSizeOfPackExpr(const SizeOfPackExpr *Node);
-
- // ObjC
- void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node);
-
- // Comments.
- void dumpComment(const Comment *C, const FullComment *FC);
-
- void VisitExpressionTemplateArgument(const TemplateArgument &TA) {
- dumpStmt(TA.getAsExpr());
- }
- void VisitPackTemplateArgument(const TemplateArgument &TA) {
- for (const auto &TArg : TA.pack_elements())
- dumpTemplateArgument(TArg);
- }
-
-// Implements Visit methods for Attrs.
-#include "clang/AST/AttrNodeTraverse.inc"
- };
-}
-
-//===----------------------------------------------------------------------===//
-// Utilities
-//===----------------------------------------------------------------------===//
-
-void ASTDumper::dumpTypeAsChild(QualType T) {
- SplitQualType SQT = T.split();
- if (!SQT.Quals.hasQualifiers())
- return dumpTypeAsChild(SQT.Ty);
-
- dumpChild([=] {
- NodeDumper.Visit(T);
- dumpTypeAsChild(T.split().Ty);
- });
-}
-
-void ASTDumper::dumpTypeAsChild(const Type *T) {
- dumpChild([=] {
- NodeDumper.Visit(T);
- if (!T)
- return;
- TypeVisitor<ASTDumper>::Visit(T);
-
- QualType SingleStepDesugar =
- T->getLocallyUnqualifiedSingleStepDesugaredType();
- if (SingleStepDesugar != QualType(T, 0))
- dumpTypeAsChild(SingleStepDesugar);
- });
-}
-
-void ASTDumper::dumpDeclContext(const DeclContext *DC) {
- if (!DC)
- return;
-
- for (auto *D : (Deserialize ? DC->decls() : DC->noload_decls()))
- dumpDecl(D);
-
- if (DC->hasExternalLexicalStorage()) {
- dumpChild([=] {
- ColorScope Color(OS, ShowColors, UndeserializedColor);
- OS << "<undeserialized declarations>";
- });
- }
-}
-
void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
- dumpChild([=] {
+ NodeDumper.AddChild([=] {
OS << "StoredDeclsMap ";
NodeDumper.dumpBareDeclRef(cast<Decl>(DC));
@@ -384,14 +35,14 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
- auto Range = Deserialize
+ auto Range = getDeserialize()
? Primary->lookups()
: Primary->noload_lookups(/*PreserveInternalState=*/true);
for (auto I = Range.begin(), E = Range.end(); I != E; ++I) {
DeclarationName Name = I.getLookupName();
DeclContextLookupResult R = *I;
- dumpChild([=] {
+ NodeDumper.AddChild([=] {
OS << "DeclarationName ";
{
ColorScope Color(OS, ShowColors, DeclNameColor);
@@ -400,7 +51,7 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
RI != RE; ++RI) {
- dumpChild([=] {
+ NodeDumper.AddChild([=] {
NodeDumper.dumpBareDeclRef(*RI);
if ((*RI)->isHidden())
@@ -412,7 +63,7 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) {
if (Decl *Prev = D->getPreviousDecl())
DumpWithPrev(Prev);
- dumpDecl(D);
+ Visit(D);
};
DumpWithPrev(*RI);
}
@@ -422,7 +73,7 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
}
if (HasUndeserializedLookups) {
- dumpChild([=] {
+ NodeDumper.AddChild([=] {
ColorScope Color(OS, ShowColors, UndeserializedColor);
OS << "<undeserialized lookups>";
});
@@ -430,560 +81,12 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
});
}
-void ASTDumper::dumpAttr(const Attr *A) {
- dumpChild([=] {
- NodeDumper.Visit(A);
- ConstAttrVisitor<ASTDumper>::Visit(A);
- });
-}
-
-//===----------------------------------------------------------------------===//
-// C++ Utilities
-//===----------------------------------------------------------------------===//
-
-void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) {
- dumpChild([=] {
- NodeDumper.Visit(Init);
- dumpStmt(Init->getInit());
- });
-}
-
-void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) {
- if (!TPL)
- return;
-
- for (TemplateParameterList::const_iterator I = TPL->begin(), E = TPL->end();
- I != E; ++I)
- dumpDecl(*I);
-}
-
-void ASTDumper::dumpTemplateArgumentListInfo(
- const TemplateArgumentListInfo &TALI) {
- for (unsigned i = 0, e = TALI.size(); i < e; ++i)
- dumpTemplateArgumentLoc(TALI[i]);
-}
-
-void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A,
- const Decl *From, const char *Label) {
- dumpTemplateArgument(A.getArgument(), A.getSourceRange(), From, Label);
-}
-
-void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) {
- for (unsigned i = 0, e = TAL.size(); i < e; ++i)
- dumpTemplateArgument(TAL[i]);
-}
-
-void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R,
- const Decl *From, const char *Label) {
- dumpChild([=] {
- NodeDumper.Visit(A, R, From, Label);
- ConstTemplateArgumentVisitor<ASTDumper>::Visit(A);
- });
-}
-
-//===----------------------------------------------------------------------===//
-// Objective-C Utilities
-//===----------------------------------------------------------------------===//
-void ASTDumper::dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) {
- if (!typeParams)
- return;
-
- for (auto typeParam : *typeParams) {
- dumpDecl(typeParam);
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Decl dumping methods.
-//===----------------------------------------------------------------------===//
-
-void ASTDumper::dumpDecl(const Decl *D) {
- dumpChild([=] {
- NodeDumper.Visit(D);
- if (!D)
- return;
-
- ConstDeclVisitor<ASTDumper>::Visit(D);
-
- for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end(); I != E;
- ++I)
- dumpAttr(*I);
-
- if (const FullComment *Comment =
- D->getASTContext().getLocalCommentForDeclUncached(D))
- dumpComment(Comment, Comment);
-
- // Decls within functions are visited by the body.
- if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D)) {
- auto DC = dyn_cast<DeclContext>(D);
- if (DC &&
- (DC->hasExternalLexicalStorage() ||
- (Deserialize ? DC->decls_begin() != DC->decls_end()
- : DC->noload_decls_begin() != DC->noload_decls_end())))
- dumpDeclContext(DC);
- }
- });
-}
-
-void ASTDumper::VisitLabelDecl(const LabelDecl *D) { NodeDumper.dumpName(D); }
-
-void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getUnderlyingType());
- if (D->isModulePrivate())
- OS << " __module_private__";
- dumpTypeAsChild(D->getUnderlyingType());
-}
-
-void ASTDumper::VisitEnumDecl(const EnumDecl *D) {
- if (D->isScoped()) {
- if (D->isScopedUsingClassTag())
- OS << " class";
- else
- OS << " struct";
- }
- NodeDumper.dumpName(D);
- if (D->isModulePrivate())
- OS << " __module_private__";
- if (D->isFixed())
- NodeDumper.dumpType(D->getIntegerType());
-}
-
-void ASTDumper::VisitRecordDecl(const RecordDecl *D) {
- OS << ' ' << D->getKindName();
- NodeDumper.dumpName(D);
- if (D->isModulePrivate())
- OS << " __module_private__";
- if (D->isCompleteDefinition())
- OS << " definition";
-}
-
-void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getType());
- if (const Expr *Init = D->getInitExpr())
- dumpStmt(Init);
-}
-
-void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getType());
-
- for (auto *Child : D->chain())
- NodeDumper.dumpDeclRef(Child);
-}
-
-void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getType());
-
- StorageClass SC = D->getStorageClass();
- if (SC != SC_None)
- OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
- if (D->isInlineSpecified())
- OS << " inline";
- if (D->isVirtualAsWritten())
- OS << " virtual";
- if (D->isModulePrivate())
- OS << " __module_private__";
-
- if (D->isPure())
- OS << " pure";
- if (D->isDefaulted()) {
- OS << " default";
- if (D->isDeleted())
- OS << "_delete";
- }
- if (D->isDeletedAsWritten())
- OS << " delete";
- if (D->isTrivial())
- OS << " trivial";
-
- if (const auto *FPT = D->getType()->getAs<FunctionProtoType>()) {
- FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- switch (EPI.ExceptionSpec.Type) {
- default: break;
- case EST_Unevaluated:
- OS << " noexcept-unevaluated " << EPI.ExceptionSpec.SourceDecl;
- break;
- case EST_Uninstantiated:
- OS << " noexcept-uninstantiated " << EPI.ExceptionSpec.SourceTemplate;
- break;
- }
- }
-
- if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
- if (MD->size_overridden_methods() != 0) {
- auto dumpOverride = [=](const CXXMethodDecl *D) {
- SplitQualType T_split = D->getType().split();
- OS << D << " " << D->getParent()->getName()
- << "::" << D->getNameAsString() << " '"
- << QualType::getAsString(T_split, PrintPolicy) << "'";
- };
-
- dumpChild([=] {
- auto Overrides = MD->overridden_methods();
- OS << "Overrides: [ ";
- dumpOverride(*Overrides.begin());
- for (const auto *Override :
- llvm::make_range(Overrides.begin() + 1, Overrides.end())) {
- OS << ", ";
- dumpOverride(Override);
- }
- OS << " ]";
- });
- }
- }
-
- if (const auto *FTSI = D->getTemplateSpecializationInfo())
- dumpTemplateArgumentList(*FTSI->TemplateArguments);
-
- if (!D->param_begin() && D->getNumParams())
- dumpChild([=] { OS << "<<NULL params x " << D->getNumParams() << ">>"; });
- else
- for (const ParmVarDecl *Parameter : D->parameters())
- dumpDecl(Parameter);
-
- if (const auto *C = dyn_cast<CXXConstructorDecl>(D))
- for (const auto *I : C->inits())
- dumpCXXCtorInitializer(I);
-
- if (D->doesThisDeclarationHaveABody())
- dumpStmt(D->getBody());
-}
-
-void ASTDumper::VisitFieldDecl(const FieldDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getType());
- if (D->isMutable())
- OS << " mutable";
- if (D->isModulePrivate())
- OS << " __module_private__";
-
- if (D->isBitField())
- dumpStmt(D->getBitWidth());
- if (Expr *Init = D->getInClassInitializer())
- dumpStmt(Init);
-}
-
-void ASTDumper::VisitVarDecl(const VarDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getType());
- StorageClass SC = D->getStorageClass();
- if (SC != SC_None)
- OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
- switch (D->getTLSKind()) {
- case VarDecl::TLS_None: break;
- case VarDecl::TLS_Static: OS << " tls"; break;
- case VarDecl::TLS_Dynamic: OS << " tls_dynamic"; break;
- }
- if (D->isModulePrivate())
- OS << " __module_private__";
- if (D->isNRVOVariable())
- OS << " nrvo";
- if (D->isInline())
- OS << " inline";
- if (D->isConstexpr())
- OS << " constexpr";
- if (D->hasInit()) {
- switch (D->getInitStyle()) {
- case VarDecl::CInit: OS << " cinit"; break;
- case VarDecl::CallInit: OS << " callinit"; break;
- case VarDecl::ListInit: OS << " listinit"; break;
- }
- dumpStmt(D->getInit());
- }
-}
-
-void ASTDumper::VisitDecompositionDecl(const DecompositionDecl *D) {
- VisitVarDecl(D);
- for (auto *B : D->bindings())
- dumpDecl(B);
-}
-
-void ASTDumper::VisitBindingDecl(const BindingDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getType());
- if (auto *E = D->getBinding())
- dumpStmt(E);
-}
-
-void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {
- dumpStmt(D->getAsmString());
-}
-
-void ASTDumper::VisitImportDecl(const ImportDecl *D) {
- OS << ' ' << D->getImportedModule()->getFullModuleName();
-}
-
-void ASTDumper::VisitPragmaCommentDecl(const PragmaCommentDecl *D) {
- OS << ' ';
- switch (D->getCommentKind()) {
- case PCK_Unknown: llvm_unreachable("unexpected pragma comment kind");
- case PCK_Compiler: OS << "compiler"; break;
- case PCK_ExeStr: OS << "exestr"; break;
- case PCK_Lib: OS << "lib"; break;
- case PCK_Linker: OS << "linker"; break;
- case PCK_User: OS << "user"; break;
- }
- StringRef Arg = D->getArg();
- if (!Arg.empty())
- OS << " \"" << Arg << "\"";
-}
-
-void ASTDumper::VisitPragmaDetectMismatchDecl(
- const PragmaDetectMismatchDecl *D) {
- OS << " \"" << D->getName() << "\" \"" << D->getValue() << "\"";
-}
-
-void ASTDumper::VisitCapturedDecl(const CapturedDecl *D) {
- dumpStmt(D->getBody());
-}
-
-//===----------------------------------------------------------------------===//
-// OpenMP Declarations
-//===----------------------------------------------------------------------===//
-
-void ASTDumper::VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) {
- for (auto *E : D->varlists())
- dumpStmt(E);
-}
-
-void ASTDumper::VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getType());
- OS << " combiner";
- NodeDumper.dumpPointer(D->getCombiner());
- if (const auto *Initializer = D->getInitializer()) {
- OS << " initializer";
- NodeDumper.dumpPointer(Initializer);
- switch (D->getInitializerKind()) {
- case OMPDeclareReductionDecl::DirectInit:
- OS << " omp_priv = ";
- break;
- case OMPDeclareReductionDecl::CopyInit:
- OS << " omp_priv ()";
- break;
- case OMPDeclareReductionDecl::CallInit:
- break;
- }
- }
-
- dumpStmt(D->getCombiner());
- if (const auto *Initializer = D->getInitializer())
- dumpStmt(Initializer);
-}
-
-void ASTDumper::VisitOMPRequiresDecl(const OMPRequiresDecl *D) {
- for (auto *C : D->clauselists()) {
- dumpChild([=] {
- if (!C) {
- ColorScope Color(OS, ShowColors, NullColor);
- OS << "<<<NULL>>> OMPClause";
- return;
- }
- {
- ColorScope Color(OS, ShowColors, AttrColor);
- StringRef ClauseName(getOpenMPClauseName(C->getClauseKind()));
- OS << "OMP" << ClauseName.substr(/*Start=*/0, /*N=*/1).upper()
- << ClauseName.drop_front() << "Clause";
- }
- NodeDumper.dumpPointer(C);
- NodeDumper.dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc()));
- });
- }
-}
-
-void ASTDumper::VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getType());
- dumpStmt(D->getInit());
-}
-
-//===----------------------------------------------------------------------===//
-// C++ Declarations
-//===----------------------------------------------------------------------===//
-
-void ASTDumper::VisitNamespaceDecl(const NamespaceDecl *D) {
- NodeDumper.dumpName(D);
- if (D->isInline())
- OS << " inline";
- if (!D->isOriginalNamespace())
- NodeDumper.dumpDeclRef(D->getOriginalNamespace(), "original");
-}
-
-void ASTDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
- OS << ' ';
- NodeDumper.dumpBareDeclRef(D->getNominatedNamespace());
-}
-
-void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpDeclRef(D->getAliasedNamespace());
-}
-
-void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getUnderlyingType());
- dumpTypeAsChild(D->getUnderlyingType());
-}
-
-void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
- NodeDumper.dumpName(D);
- dumpTemplateParameters(D->getTemplateParameters());
- dumpDecl(D->getTemplatedDecl());
-}
-
-void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
- VisitRecordDecl(D);
- if (!D->isCompleteDefinition())
- return;
-
- dumpChild([=] {
- {
- ColorScope Color(OS, ShowColors, DeclKindNameColor);
- OS << "DefinitionData";
- }
-#define FLAG(fn, name) if (D->fn()) OS << " " #name;
- FLAG(isParsingBaseSpecifiers, parsing_base_specifiers);
-
- FLAG(isGenericLambda, generic);
- FLAG(isLambda, lambda);
-
- FLAG(canPassInRegisters, pass_in_registers);
- FLAG(isEmpty, empty);
- FLAG(isAggregate, aggregate);
- FLAG(isStandardLayout, standard_layout);
- FLAG(isTriviallyCopyable, trivially_copyable);
- FLAG(isPOD, pod);
- FLAG(isTrivial, trivial);
- FLAG(isPolymorphic, polymorphic);
- FLAG(isAbstract, abstract);
- FLAG(isLiteral, literal);
-
- FLAG(hasUserDeclaredConstructor, has_user_declared_ctor);
- FLAG(hasConstexprNonCopyMoveConstructor, has_constexpr_non_copy_move_ctor);
- FLAG(hasMutableFields, has_mutable_fields);
- FLAG(hasVariantMembers, has_variant_members);
- FLAG(allowConstDefaultInit, can_const_default_init);
-
- dumpChild([=] {
- {
- ColorScope Color(OS, ShowColors, DeclKindNameColor);
- OS << "DefaultConstructor";
- }
- FLAG(hasDefaultConstructor, exists);
- FLAG(hasTrivialDefaultConstructor, trivial);
- FLAG(hasNonTrivialDefaultConstructor, non_trivial);
- FLAG(hasUserProvidedDefaultConstructor, user_provided);
- FLAG(hasConstexprDefaultConstructor, constexpr);
- FLAG(needsImplicitDefaultConstructor, needs_implicit);
- FLAG(defaultedDefaultConstructorIsConstexpr, defaulted_is_constexpr);
- });
-
- dumpChild([=] {
- {
- ColorScope Color(OS, ShowColors, DeclKindNameColor);
- OS << "CopyConstructor";
- }
- FLAG(hasSimpleCopyConstructor, simple);
- FLAG(hasTrivialCopyConstructor, trivial);
- FLAG(hasNonTrivialCopyConstructor, non_trivial);
- FLAG(hasUserDeclaredCopyConstructor, user_declared);
- FLAG(hasCopyConstructorWithConstParam, has_const_param);
- FLAG(needsImplicitCopyConstructor, needs_implicit);
- FLAG(needsOverloadResolutionForCopyConstructor,
- needs_overload_resolution);
- if (!D->needsOverloadResolutionForCopyConstructor())
- FLAG(defaultedCopyConstructorIsDeleted, defaulted_is_deleted);
- FLAG(implicitCopyConstructorHasConstParam, implicit_has_const_param);
- });
-
- dumpChild([=] {
- {
- ColorScope Color(OS, ShowColors, DeclKindNameColor);
- OS << "MoveConstructor";
- }
- FLAG(hasMoveConstructor, exists);
- FLAG(hasSimpleMoveConstructor, simple);
- FLAG(hasTrivialMoveConstructor, trivial);
- FLAG(hasNonTrivialMoveConstructor, non_trivial);
- FLAG(hasUserDeclaredMoveConstructor, user_declared);
- FLAG(needsImplicitMoveConstructor, needs_implicit);
- FLAG(needsOverloadResolutionForMoveConstructor,
- needs_overload_resolution);
- if (!D->needsOverloadResolutionForMoveConstructor())
- FLAG(defaultedMoveConstructorIsDeleted, defaulted_is_deleted);
- });
-
- dumpChild([=] {
- {
- ColorScope Color(OS, ShowColors, DeclKindNameColor);
- OS << "CopyAssignment";
- }
- FLAG(hasTrivialCopyAssignment, trivial);
- FLAG(hasNonTrivialCopyAssignment, non_trivial);
- FLAG(hasCopyAssignmentWithConstParam, has_const_param);
- FLAG(hasUserDeclaredCopyAssignment, user_declared);
- FLAG(needsImplicitCopyAssignment, needs_implicit);
- FLAG(needsOverloadResolutionForCopyAssignment, needs_overload_resolution);
- FLAG(implicitCopyAssignmentHasConstParam, implicit_has_const_param);
- });
-
- dumpChild([=] {
- {
- ColorScope Color(OS, ShowColors, DeclKindNameColor);
- OS << "MoveAssignment";
- }
- FLAG(hasMoveAssignment, exists);
- FLAG(hasSimpleMoveAssignment, simple);
- FLAG(hasTrivialMoveAssignment, trivial);
- FLAG(hasNonTrivialMoveAssignment, non_trivial);
- FLAG(hasUserDeclaredMoveAssignment, user_declared);
- FLAG(needsImplicitMoveAssignment, needs_implicit);
- FLAG(needsOverloadResolutionForMoveAssignment, needs_overload_resolution);
- });
-
- dumpChild([=] {
- {
- ColorScope Color(OS, ShowColors, DeclKindNameColor);
- OS << "Destructor";
- }
- FLAG(hasSimpleDestructor, simple);
- FLAG(hasIrrelevantDestructor, irrelevant);
- FLAG(hasTrivialDestructor, trivial);
- FLAG(hasNonTrivialDestructor, non_trivial);
- FLAG(hasUserDeclaredDestructor, user_declared);
- FLAG(needsImplicitDestructor, needs_implicit);
- FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution);
- if (!D->needsOverloadResolutionForDestructor())
- FLAG(defaultedDestructorIsDeleted, defaulted_is_deleted);
- });
- });
-
- for (const auto &I : D->bases()) {
- dumpChild([=] {
- if (I.isVirtual())
- OS << "virtual ";
- NodeDumper.dumpAccessSpecifier(I.getAccessSpecifier());
- NodeDumper.dumpType(I.getType());
- if (I.isPackExpansion())
- OS << "...";
- });
- }
-}
-
-void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) {
- dumpStmt(D->getAssertExpr());
- dumpStmt(D->getMessage());
-}
-
template <typename SpecializationDecl>
void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
bool DumpExplicitInst,
bool DumpRefOnly) {
bool DumpedAny = false;
- for (auto *RedeclWithBadType : D->redecls()) {
+ for (const auto *RedeclWithBadType : D->redecls()) {
// FIXME: The redecls() range sometimes has elements of a less-specific
// type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
// us TagDecls, and should give CXXRecordDecls).
@@ -1007,7 +110,7 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
if (DumpRefOnly)
NodeDumper.dumpDeclRef(Redecl);
else
- dumpDecl(Redecl);
+ Visit(Redecl);
DumpedAny = true;
break;
case TSK_ExplicitSpecialization:
@@ -1022,12 +125,11 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
template <typename TemplateDecl>
void ASTDumper::dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) {
- NodeDumper.dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
- dumpDecl(D->getTemplatedDecl());
+ Visit(D->getTemplatedDecl());
- for (auto *Child : D->specializations())
+ for (const auto *Child : D->specializations())
dumpTemplateDeclSpecialization(Child, DumpExplicitInst,
!D->isCanonicalDecl());
}
@@ -1043,500 +145,10 @@ void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
dumpTemplateDecl(D, false);
}
-void ASTDumper::VisitClassTemplateSpecializationDecl(
- const ClassTemplateSpecializationDecl *D) {
- VisitCXXRecordDecl(D);
- dumpTemplateArgumentList(D->getTemplateArgs());
-}
-
-void ASTDumper::VisitClassTemplatePartialSpecializationDecl(
- const ClassTemplatePartialSpecializationDecl *D) {
- VisitClassTemplateSpecializationDecl(D);
- dumpTemplateParameters(D->getTemplateParameters());
-}
-
-void ASTDumper::VisitClassScopeFunctionSpecializationDecl(
- const ClassScopeFunctionSpecializationDecl *D) {
- dumpDecl(D->getSpecialization());
- if (D->hasExplicitTemplateArgs())
- dumpTemplateArgumentListInfo(D->templateArgs());
-}
-
void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
dumpTemplateDecl(D, false);
}
-void ASTDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) {
- NodeDumper.dumpName(D);
- dumpTemplateParameters(D->getTemplateParameters());
-}
-
-void ASTDumper::VisitVarTemplateSpecializationDecl(
- const VarTemplateSpecializationDecl *D) {
- dumpTemplateArgumentList(D->getTemplateArgs());
- VisitVarDecl(D);
-}
-
-void ASTDumper::VisitVarTemplatePartialSpecializationDecl(
- const VarTemplatePartialSpecializationDecl *D) {
- dumpTemplateParameters(D->getTemplateParameters());
- VisitVarTemplateSpecializationDecl(D);
-}
-
-void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
- if (D->wasDeclaredWithTypename())
- OS << " typename";
- else
- OS << " class";
- OS << " depth " << D->getDepth() << " index " << D->getIndex();
- if (D->isParameterPack())
- OS << " ...";
- NodeDumper.dumpName(D);
- if (D->hasDefaultArgument())
- dumpTemplateArgument(D->getDefaultArgument(), SourceRange(),
- D->getDefaultArgStorage().getInheritedFrom(),
- D->defaultArgumentWasInherited() ? "inherited from"
- : "previous");
-}
-
-void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
- NodeDumper.dumpType(D->getType());
- OS << " depth " << D->getDepth() << " index " << D->getIndex();
- if (D->isParameterPack())
- OS << " ...";
- NodeDumper.dumpName(D);
- if (D->hasDefaultArgument())
- dumpTemplateArgument(D->getDefaultArgument(), SourceRange(),
- D->getDefaultArgStorage().getInheritedFrom(),
- D->defaultArgumentWasInherited() ? "inherited from"
- : "previous");
-}
-
-void ASTDumper::VisitTemplateTemplateParmDecl(
- const TemplateTemplateParmDecl *D) {
- OS << " depth " << D->getDepth() << " index " << D->getIndex();
- if (D->isParameterPack())
- OS << " ...";
- NodeDumper.dumpName(D);
- dumpTemplateParameters(D->getTemplateParameters());
- if (D->hasDefaultArgument())
- dumpTemplateArgumentLoc(
- D->getDefaultArgument(), D->getDefaultArgStorage().getInheritedFrom(),
- D->defaultArgumentWasInherited() ? "inherited from" : "previous");
-}
-
-void ASTDumper::VisitUsingDecl(const UsingDecl *D) {
- OS << ' ';
- if (D->getQualifier())
- D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
- OS << D->getNameAsString();
-}
-
-void ASTDumper::VisitUnresolvedUsingTypenameDecl(
- const UnresolvedUsingTypenameDecl *D) {
- OS << ' ';
- if (D->getQualifier())
- D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
- OS << D->getNameAsString();
-}
-
-void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
- OS << ' ';
- if (D->getQualifier())
- D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
- OS << D->getNameAsString();
- NodeDumper.dumpType(D->getType());
-}
-
-void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) {
- OS << ' ';
- NodeDumper.dumpBareDeclRef(D->getTargetDecl());
- if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl()))
- dumpTypeAsChild(TD->getTypeForDecl());
-}
-
-void ASTDumper::VisitConstructorUsingShadowDecl(
- const ConstructorUsingShadowDecl *D) {
- if (D->constructsVirtualBase())
- OS << " virtual";
-
- dumpChild([=] {
- OS << "target ";
- NodeDumper.dumpBareDeclRef(D->getTargetDecl());
- });
-
- dumpChild([=] {
- OS << "nominated ";
- NodeDumper.dumpBareDeclRef(D->getNominatedBaseClass());
- OS << ' ';
- NodeDumper.dumpBareDeclRef(D->getNominatedBaseClassShadowDecl());
- });
-
- dumpChild([=] {
- OS << "constructed ";
- NodeDumper.dumpBareDeclRef(D->getConstructedBaseClass());
- OS << ' ';
- NodeDumper.dumpBareDeclRef(D->getConstructedBaseClassShadowDecl());
- });
-}
-
-void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
- switch (D->getLanguage()) {
- case LinkageSpecDecl::lang_c: OS << " C"; break;
- case LinkageSpecDecl::lang_cxx: OS << " C++"; break;
- }
-}
-
-void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) {
- OS << ' ';
- NodeDumper.dumpAccessSpecifier(D->getAccess());
-}
-
-void ASTDumper::VisitFriendDecl(const FriendDecl *D) {
- if (TypeSourceInfo *T = D->getFriendType())
- NodeDumper.dumpType(T->getType());
- else
- dumpDecl(D->getFriendDecl());
-}
-
-//===----------------------------------------------------------------------===//
-// Obj-C Declarations
-//===----------------------------------------------------------------------===//
-
-void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getType());
- if (D->getSynthesize())
- OS << " synthesize";
-
- switch (D->getAccessControl()) {
- case ObjCIvarDecl::None:
- OS << " none";
- break;
- case ObjCIvarDecl::Private:
- OS << " private";
- break;
- case ObjCIvarDecl::Protected:
- OS << " protected";
- break;
- case ObjCIvarDecl::Public:
- OS << " public";
- break;
- case ObjCIvarDecl::Package:
- OS << " package";
- break;
- }
-}
-
-void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
- if (D->isInstanceMethod())
- OS << " -";
- else
- OS << " +";
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getReturnType());
-
- if (D->isThisDeclarationADefinition()) {
- dumpDeclContext(D);
- } else {
- for (const ParmVarDecl *Parameter : D->parameters())
- dumpDecl(Parameter);
- }
-
- if (D->isVariadic())
- dumpChild([=] { OS << "..."; });
-
- if (D->hasBody())
- dumpStmt(D->getBody());
-}
-
-void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) {
- NodeDumper.dumpName(D);
- switch (D->getVariance()) {
- case ObjCTypeParamVariance::Invariant:
- break;
-
- case ObjCTypeParamVariance::Covariant:
- OS << " covariant";
- break;
-
- case ObjCTypeParamVariance::Contravariant:
- OS << " contravariant";
- break;
- }
-
- if (D->hasExplicitBound())
- OS << " bounded";
- NodeDumper.dumpType(D->getUnderlyingType());
-}
-
-void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpDeclRef(D->getClassInterface());
- NodeDumper.dumpDeclRef(D->getImplementation());
- for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
- E = D->protocol_end();
- I != E; ++I)
- NodeDumper.dumpDeclRef(*I);
- dumpObjCTypeParamList(D->getTypeParamList());
-}
-
-void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpDeclRef(D->getClassInterface());
- NodeDumper.dumpDeclRef(D->getCategoryDecl());
-}
-
-void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
- NodeDumper.dumpName(D);
-
- for (auto *Child : D->protocols())
- NodeDumper.dumpDeclRef(Child);
-}
-
-void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpDeclRef(D->getSuperClass(), "super");
-
- NodeDumper.dumpDeclRef(D->getImplementation());
- for (auto *Child : D->protocols())
- NodeDumper.dumpDeclRef(Child);
- dumpObjCTypeParamList(D->getTypeParamListAsWritten());
-}
-
-void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpDeclRef(D->getSuperClass(), "super");
- NodeDumper.dumpDeclRef(D->getClassInterface());
- for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(),
- E = D->init_end();
- I != E; ++I)
- dumpCXXCtorInitializer(*I);
-}
-
-void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpDeclRef(D->getClassInterface());
-}
-
-void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
- NodeDumper.dumpName(D);
- NodeDumper.dumpType(D->getType());
-
- if (D->getPropertyImplementation() == ObjCPropertyDecl::Required)
- OS << " required";
- else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional)
- OS << " optional";
-
- ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes();
- if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) {
- if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly)
- OS << " readonly";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
- OS << " assign";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite)
- OS << " readwrite";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_retain)
- OS << " retain";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_copy)
- OS << " copy";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic)
- OS << " nonatomic";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic)
- OS << " atomic";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_weak)
- OS << " weak";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_strong)
- OS << " strong";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained)
- OS << " unsafe_unretained";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_class)
- OS << " class";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_getter)
- NodeDumper.dumpDeclRef(D->getGetterMethodDecl(), "getter");
- if (Attrs & ObjCPropertyDecl::OBJC_PR_setter)
- NodeDumper.dumpDeclRef(D->getSetterMethodDecl(), "setter");
- }
-}
-
-void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
- NodeDumper.dumpName(D->getPropertyDecl());
- if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
- OS << " synthesize";
- else
- OS << " dynamic";
- NodeDumper.dumpDeclRef(D->getPropertyDecl());
- NodeDumper.dumpDeclRef(D->getPropertyIvarDecl());
-}
-
-void ASTDumper::Visit(const BlockDecl::Capture &C) {
- dumpChild([=] {
- NodeDumper.Visit(C);
- if (C.hasCopyExpr())
- dumpStmt(C.getCopyExpr());
- });
-}
-
-void ASTDumper::VisitBlockDecl(const BlockDecl *D) {
- for (auto I : D->parameters())
- dumpDecl(I);
-
- if (D->isVariadic())
- dumpChild([=]{ OS << "..."; });
-
- if (D->capturesCXXThis())
- dumpChild([=]{ OS << "capture this"; });
-
- for (const auto &I : D->captures())
- Visit(I);
- dumpStmt(D->getBody());
-}
-
-//===----------------------------------------------------------------------===//
-// Stmt dumping methods.
-//===----------------------------------------------------------------------===//
-
-void ASTDumper::dumpStmt(const Stmt *S, StringRef Label) {
- dumpChild(Label, [=] {
- NodeDumper.Visit(S);
-
- if (!S) {
- return;
- }
-
- ConstStmtVisitor<ASTDumper>::Visit(S);
-
- // Some statements have custom mechanisms for dumping their children.
- if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S)) {
- return;
- }
-
- for (const Stmt *SubStmt : S->children())
- dumpStmt(SubStmt);
- });
-}
-
-void ASTDumper::VisitDeclStmt(const DeclStmt *Node) {
- for (DeclStmt::const_decl_iterator I = Node->decl_begin(),
- E = Node->decl_end();
- I != E; ++I)
- dumpDecl(*I);
-}
-
-void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) {
- for (ArrayRef<const Attr *>::iterator I = Node->getAttrs().begin(),
- E = Node->getAttrs().end();
- I != E; ++I)
- dumpAttr(*I);
-}
-
-void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) {
- dumpDecl(Node->getExceptionDecl());
-}
-
-void ASTDumper::VisitCapturedStmt(const CapturedStmt *Node) {
- dumpDecl(Node->getCapturedDecl());
-}
-
-//===----------------------------------------------------------------------===//
-// OpenMP dumping methods.
-//===----------------------------------------------------------------------===//
-
-void ASTDumper::Visit(const OMPClause *C) {
- dumpChild([=] {
- NodeDumper.Visit(C);
- for (auto *S : C->children())
- dumpStmt(S);
- });
-}
-
-void ASTDumper::VisitOMPExecutableDirective(
- const OMPExecutableDirective *Node) {
- for (const auto *C : Node->clauses())
- Visit(C);
-}
-
-//===----------------------------------------------------------------------===//
-// Expr dumping methods.
-//===----------------------------------------------------------------------===//
-
-
-void ASTDumper::VisitInitListExpr(const InitListExpr *ILE) {
- if (auto *Filler = ILE->getArrayFiller()) {
- dumpStmt(Filler, "array_filler");
- }
-}
-
-void ASTDumper::VisitBlockExpr(const BlockExpr *Node) {
- dumpDecl(Node->getBlockDecl());
-}
-
-void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) {
- if (Expr *Source = Node->getSourceExpr())
- dumpStmt(Source);
-}
-
-void ASTDumper::VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
- if (E->isResultDependent())
- OS << " result_dependent";
- dumpStmt(E->getControllingExpr());
- dumpTypeAsChild(E->getControllingExpr()->getType()); // FIXME: remove
-
- for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) {
- dumpChild([=] {
- if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I)) {
- OS << "case ";
- NodeDumper.dumpType(TSI->getType());
- } else {
- OS << "default";
- }
-
- if (!E->isResultDependent() && E->getResultIndex() == I)
- OS << " selected";
-
- if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I))
- dumpTypeAsChild(TSI->getType());
- dumpStmt(E->getAssocExpr(I));
- });
- }
-}
-
-//===----------------------------------------------------------------------===//
-// C++ Expressions
-//===----------------------------------------------------------------------===//
-
-void ASTDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *Node) {
- if (Node->isPartiallySubstituted())
- for (const auto &A : Node->getPartialArguments())
- dumpTemplateArgument(A);
-}
-
-//===----------------------------------------------------------------------===//
-// Obj-C Expressions
-//===----------------------------------------------------------------------===//
-
-void ASTDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) {
- if (const VarDecl *CatchParam = Node->getCatchParamDecl())
- dumpDecl(CatchParam);
-}
-
-//===----------------------------------------------------------------------===//
-// Comments
-//===----------------------------------------------------------------------===//
-
-void ASTDumper::dumpComment(const Comment *C, const FullComment *FC) {
- dumpChild([=] {
- NodeDumper.Visit(C, FC);
- if (!C) {
- return;
- }
- ConstCommentVisitor<ASTDumper, void, const FullComment *>::visit(C, FC);
- for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
- I != E; ++I)
- dumpComment(*I, FC);
- });
-}
-
//===----------------------------------------------------------------------===//
// Type method implementations
//===----------------------------------------------------------------------===//
@@ -1551,7 +163,7 @@ LLVM_DUMP_METHOD void QualType::dump() const { dump(llvm::errs()); }
LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS) const {
ASTDumper Dumper(OS, nullptr, nullptr);
- Dumper.dumpTypeAsChild(*this);
+ Dumper.Visit(*this);
}
LLVM_DUMP_METHOD void Type::dump() const { dump(llvm::errs()); }
@@ -1566,13 +178,22 @@ LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS) const {
LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }
-LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize) const {
- const ASTContext &Ctx = getASTContext();
+LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize,
+ ASTDumpOutputFormat Format) const {
+ ASTContext &Ctx = getASTContext();
const SourceManager &SM = Ctx.getSourceManager();
- ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM,
- SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy());
- P.setDeserialize(Deserialize);
- P.dumpDecl(this);
+
+ if (ADOF_JSON == Format) {
+ JSONDumper P(OS, SM, Ctx, Ctx.getPrintingPolicy(),
+ &Ctx.getCommentCommandTraits());
+ (void)Deserialize; // FIXME?
+ P.Visit(this);
+ } else {
+ ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM,
+ SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy());
+ P.setDeserialize(Deserialize);
+ P.Visit(this);
+ }
}
LLVM_DUMP_METHOD void Decl::dumpColor() const {
@@ -1580,7 +201,7 @@ LLVM_DUMP_METHOD void Decl::dumpColor() const {
ASTDumper P(llvm::errs(), &Ctx.getCommentCommandTraits(),
&Ctx.getSourceManager(), /*ShowColors*/ true,
Ctx.getPrintingPolicy());
- P.dumpDecl(this);
+ P.Visit(this);
}
LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
@@ -1611,22 +232,22 @@ LLVM_DUMP_METHOD void Stmt::dump(SourceManager &SM) const {
LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
ASTDumper P(OS, nullptr, &SM);
- P.dumpStmt(this);
+ P.Visit(this);
}
LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS) const {
ASTDumper P(OS, nullptr, nullptr);
- P.dumpStmt(this);
+ P.Visit(this);
}
LLVM_DUMP_METHOD void Stmt::dump() const {
ASTDumper P(llvm::errs(), nullptr, nullptr);
- P.dumpStmt(this);
+ P.Visit(this);
}
LLVM_DUMP_METHOD void Stmt::dumpColor() const {
ASTDumper P(llvm::errs(), nullptr, nullptr, /*ShowColors*/true);
- P.dumpStmt(this);
+ P.Visit(this);
}
//===----------------------------------------------------------------------===//
@@ -1648,7 +269,7 @@ void Comment::dump(raw_ostream &OS, const CommandTraits *Traits,
if (!FC)
return;
ASTDumper D(OS, Traits, SM);
- D.dumpComment(FC, FC);
+ D.Visit(FC, FC);
}
LLVM_DUMP_METHOD void Comment::dumpColor() const {
@@ -1656,5 +277,5 @@ LLVM_DUMP_METHOD void Comment::dumpColor() const {
if (!FC)
return;
ASTDumper D(llvm::errs(), nullptr, nullptr, /*ShowColors*/true);
- D.dumpComment(FC, FC);
+ D.Visit(FC, FC);
}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 44832557e97be..9d5dd84161dec 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -1,9 +1,8 @@
//===- ASTImporter.cpp - Importing ASTs from other Contexts ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -13,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTImporter.h"
-#include "clang/AST/ASTImporterLookupTable.h"
+#include "clang/AST/ASTImporterSharedState.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTStructuralEquivalence.h"
@@ -58,6 +57,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
@@ -135,25 +135,6 @@ namespace clang {
To->setIsUsed();
}
- // FIXME: Temporary until every import returns Expected.
- template <>
- LLVM_NODISCARD Error
- ASTImporter::importInto(SourceLocation &To, const SourceLocation &From) {
- To = Import(From);
- if (From.isValid() && To.isInvalid())
- return llvm::make_error<ImportError>();
- return Error::success();
- }
- // FIXME: Temporary until every import returns Expected.
- template <>
- LLVM_NODISCARD Error
- ASTImporter::importInto(QualType &To, const QualType &From) {
- To = Import(From);
- if (!From.isNull() && To.isNull())
- return llvm::make_error<ImportError>();
- return Error::success();
- }
-
class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, ExpectedType>,
public DeclVisitor<ASTNodeImporter, ExpectedDecl>,
public StmtVisitor<ASTNodeImporter, ExpectedStmt> {
@@ -168,32 +149,20 @@ namespace clang {
// Use this to import pointers of specific type.
template <typename ImportT>
LLVM_NODISCARD Error importInto(ImportT *&To, ImportT *From) {
- auto ToI = Importer.Import(From);
- if (!ToI && From)
- return make_error<ImportError>();
- To = cast_or_null<ImportT>(ToI);
- return Error::success();
- // FIXME: This should be the final code.
- //auto ToOrErr = Importer.Import(From);
- //if (ToOrErr) {
- // To = cast_or_null<ImportT>(*ToOrErr);
- //}
- //return ToOrErr.takeError();
+ auto ToOrErr = Importer.Import(From);
+ if (ToOrErr)
+ To = cast_or_null<ImportT>(*ToOrErr);
+ return ToOrErr.takeError();
}
// Call the import function of ASTImporter for a baseclass of type `T` and
// cast the return value to `T`.
template <typename T>
Expected<T *> import(T *From) {
- auto *To = Importer.Import(From);
- if (!To && From)
- return make_error<ImportError>();
- return cast_or_null<T>(To);
- // FIXME: This should be the final code.
- //auto ToOrErr = Importer.Import(From);
- //if (!ToOrErr)
- // return ToOrErr.takeError();
- //return cast_or_null<T>(*ToOrErr);
+ auto ToOrErr = Importer.Import(From);
+ if (!ToOrErr)
+ return ToOrErr.takeError();
+ return cast_or_null<T>(*ToOrErr);
}
template <typename T>
@@ -204,13 +173,15 @@ namespace clang {
// Call the import function of ASTImporter for type `T`.
template <typename T>
Expected<T> import(const T &From) {
- T To = Importer.Import(From);
- T DefaultT;
- if (To == DefaultT && !(From == DefaultT))
- return make_error<ImportError>();
- return To;
- // FIXME: This should be the final code.
- //return Importer.Import(From);
+ return Importer.Import(From);
+ }
+
+ // Import an Optional<T> by importing the contained T, if any.
+ template<typename T>
+ Expected<Optional<T>> import(Optional<T> From) {
+ if (!From)
+ return Optional<T>();
+ return import(*From);
}
template <class T>
@@ -283,18 +254,16 @@ namespace clang {
LLVM_NODISCARD bool
GetImportedOrCreateSpecialDecl(ToDeclT *&ToD, CreateFunT CreateFun,
FromDeclT *FromD, Args &&... args) {
- // FIXME: This code is needed later.
- //if (Importer.getImportDeclErrorIfAny(FromD)) {
- // ToD = nullptr;
- // return true; // Already imported but with error.
- //}
+ if (Importer.getImportDeclErrorIfAny(FromD)) {
+ ToD = nullptr;
+ return true; // Already imported but with error.
+ }
ToD = cast_or_null<ToDeclT>(Importer.GetAlreadyImportedOrNull(FromD));
if (ToD)
return true; // Already imported.
ToD = CreateFun(std::forward<Args>(args)...);
// Keep track of imported Decls.
- Importer.MapImported(FromD, ToD);
- Importer.AddToLookupTable(ToD);
+ Importer.RegisterImportedDecl(FromD, ToD);
InitializeImportedDecl(FromD, ToD);
return false; // A new Decl is created.
}
@@ -302,14 +271,31 @@ namespace clang {
void InitializeImportedDecl(Decl *FromD, Decl *ToD) {
ToD->IdentifierNamespace = FromD->IdentifierNamespace;
if (FromD->hasAttrs())
- for (const Attr *FromAttr : FromD->getAttrs())
- ToD->addAttr(Importer.Import(FromAttr));
+ for (const Attr *FromAttr : FromD->getAttrs()) {
+ // FIXME: Return of the error here is not possible until store of
+ // import errors is implemented.
+ auto ToAttrOrErr = import(FromAttr);
+ if (ToAttrOrErr)
+ ToD->addAttr(*ToAttrOrErr);
+ else
+ llvm::consumeError(ToAttrOrErr.takeError());
+ }
if (FromD->isUsed())
ToD->setIsUsed();
if (FromD->isImplicit())
ToD->setImplicit();
}
+ // Check if we have found an existing definition. Returns with that
+ // definition if yes, otherwise returns null.
+ Decl *FindAndMapDefinition(FunctionDecl *D, FunctionDecl *FoundFunction) {
+ const FunctionDecl *Definition = nullptr;
+ if (D->doesThisDeclarationHaveABody() &&
+ FoundFunction->hasBody(Definition))
+ return Importer.MapImported(D, const_cast<FunctionDecl *>(Definition));
+ return nullptr;
+ }
+
public:
explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {}
@@ -412,8 +398,6 @@ namespace clang {
Error ImportDefinition(
ObjCProtocolDecl *From, ObjCProtocolDecl *To,
ImportDefinitionKind Kind = IDK_Default);
- Expected<TemplateParameterList *> ImportTemplateParameterList(
- TemplateParameterList *Params);
Error ImportTemplateArguments(
const TemplateArgument *FromArgs, unsigned NumFromArgs,
SmallVectorImpl<TemplateArgument> &ToArgs);
@@ -435,9 +419,16 @@ namespace clang {
Expected<FunctionTemplateAndArgsTy>
ImportFunctionTemplateWithTemplateArgsFromSpecialization(
FunctionDecl *FromFD);
+ Error ImportTemplateParameterLists(const DeclaratorDecl *FromD,
+ DeclaratorDecl *ToD);
Error ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD);
+ Error ImportFunctionDeclBody(FunctionDecl *FromFD, FunctionDecl *ToFD);
+
+ template <typename T>
+ bool hasSameVisibilityContext(T *Found, T *From);
+
bool IsStructuralMatch(Decl *From, Decl *To, bool Complain);
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord,
bool Complain = true);
@@ -548,6 +539,7 @@ namespace clang {
// Importing expressions
ExpectedStmt VisitExpr(Expr *E);
ExpectedStmt VisitVAArgExpr(VAArgExpr *E);
+ ExpectedStmt VisitChooseExpr(ChooseExpr *E);
ExpectedStmt VisitGNUNullExpr(GNUNullExpr *E);
ExpectedStmt VisitPredefinedExpr(PredefinedExpr *E);
ExpectedStmt VisitDeclRefExpr(DeclRefExpr *E);
@@ -649,15 +641,6 @@ namespace clang {
FunctionDecl *FromFD);
};
-// FIXME: Temporary until every import returns Expected.
-template <>
-Expected<TemplateName> ASTNodeImporter::import(const TemplateName &From) {
- TemplateName To = Importer.Import(From);
- if (To.isNull() && !From.isNull())
- return make_error<ImportError>();
- return To;
-}
-
template <typename InContainerTy>
Error ASTNodeImporter::ImportTemplateArgumentListInfo(
SourceLocation FromLAngleLoc, SourceLocation FromRAngleLoc,
@@ -1649,16 +1632,32 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
auto ToDCOrErr = Importer.ImportContext(FromDC);
return ToDCOrErr.takeError();
}
+
+ // We use strict error handling in case of records and enums, but not
+ // with e.g. namespaces.
+ //
+ // FIXME Clients of the ASTImporter should be able to choose an
+ // appropriate error handling strategy for their needs. For instance,
+ // they may not want to mark an entire namespace as erroneous merely
+ // because there is an ODR error with two typedefs. As another example,
+ // the client may allow EnumConstantDecls with same names but with
+ // different values in two distinct translation units.
+ 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)
- // Ignore the error, continue with next Decl.
- // FIXME: Handle this case somehow better.
- consumeError(ImportedOrErr.takeError());
+ if (!ImportedOrErr) {
+ if (AccumulateChildErrors)
+ ChildErrors =
+ joinErrors(std::move(ChildErrors), ImportedOrErr.takeError());
+ else
+ consumeError(ImportedOrErr.takeError());
+ }
}
- return Error::success();
+ return ChildErrors;
}
Error ASTNodeImporter::ImportDeclContext(
@@ -1698,29 +1697,50 @@ Error ASTNodeImporter::ImportImplicitMethods(
static Error setTypedefNameForAnonDecl(TagDecl *From, TagDecl *To,
ASTImporter &Importer) {
if (TypedefNameDecl *FromTypedef = From->getTypedefNameForAnonDecl()) {
- Decl *ToTypedef = Importer.Import(FromTypedef);
- if (!ToTypedef)
- return make_error<ImportError>();
- To->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(ToTypedef));
- // FIXME: This should be the final code.
- //if (Expected<Decl *> ToTypedefOrErr = Importer.Import(FromTypedef))
- // To->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(*ToTypedefOrErr));
- //else
- // return ToTypedefOrErr.takeError();
+ if (ExpectedDecl ToTypedefOrErr = Importer.Import(FromTypedef))
+ To->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(*ToTypedefOrErr));
+ else
+ return ToTypedefOrErr.takeError();
}
return Error::success();
}
Error ASTNodeImporter::ImportDefinition(
RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind) {
+ auto DefinitionCompleter = [To]() {
+ // There are cases in LLDB when we first import a class without its
+ // members. The class will have DefinitionData, but no members. Then,
+ // importDefinition is called from LLDB, which tries to get the members, so
+ // when we get here, the class already has the DefinitionData set, so we
+ // must unset the CompleteDefinition here to be able to complete again the
+ // definition.
+ To->setCompleteDefinition(false);
+ To->completeDefinition();
+ };
+
if (To->getDefinition() || To->isBeingDefined()) {
- if (Kind == IDK_Everything)
- return ImportDeclContext(From, /*ForceImport=*/true);
+ if (Kind == IDK_Everything ||
+ // In case of lambdas, the class already has a definition ptr set, but
+ // the contained decls are not imported yet. Also, isBeingDefined was
+ // set in CXXRecordDecl::CreateLambda. We must import the contained
+ // decls here and finish the definition.
+ (To->isLambda() && shouldForceImportDeclContext(Kind))) {
+ Error Result = ImportDeclContext(From, /*ForceImport=*/true);
+ // Finish the definition of the lambda, set isBeingDefined to false.
+ if (To->isLambda())
+ DefinitionCompleter();
+ return Result;
+ }
return Error::success();
}
To->startDefinition();
+ // Complete the definition even if error is returned.
+ // The RecordDecl may be already part of the AST so it is better to
+ // have it in complete state even if something is wrong with it.
+ auto DefinitionCompleterScopeExit =
+ llvm::make_scope_exit(DefinitionCompleter);
if (Error Err = setTypedefNameForAnonDecl(From, To, Importer))
return Err;
@@ -1798,6 +1818,9 @@ Error ASTNodeImporter::ImportDefinition(
ToData.HasDeclaredCopyAssignmentWithConstParam
= FromData.HasDeclaredCopyAssignmentWithConstParam;
+ // Copy over the data stored in RecordDeclBits
+ ToCXX->setArgPassingRestrictions(FromCXX->getArgPassingRestrictions());
+
SmallVector<CXXBaseSpecifier *, 4> Bases;
for (const auto &Base1 : FromCXX->bases()) {
ExpectedType TyOrErr = import(Base1.getType());
@@ -1842,7 +1865,6 @@ Error ASTNodeImporter::ImportDefinition(
if (Error Err = ImportDeclContext(From, /*ForceImport=*/true))
return Err;
- To->completeDefinition();
return Error::success();
}
@@ -1903,40 +1925,6 @@ Error ASTNodeImporter::ImportDefinition(
return Error::success();
}
-// FIXME: Remove this, use `import` instead.
-Expected<TemplateParameterList *> ASTNodeImporter::ImportTemplateParameterList(
- TemplateParameterList *Params) {
- SmallVector<NamedDecl *, 4> ToParams(Params->size());
- if (Error Err = ImportContainerChecked(*Params, ToParams))
- return std::move(Err);
-
- Expr *ToRequiresClause;
- if (Expr *const R = Params->getRequiresClause()) {
- if (Error Err = importInto(ToRequiresClause, R))
- return std::move(Err);
- } else {
- ToRequiresClause = nullptr;
- }
-
- auto ToTemplateLocOrErr = import(Params->getTemplateLoc());
- if (!ToTemplateLocOrErr)
- return ToTemplateLocOrErr.takeError();
- auto ToLAngleLocOrErr = import(Params->getLAngleLoc());
- if (!ToLAngleLocOrErr)
- return ToLAngleLocOrErr.takeError();
- auto ToRAngleLocOrErr = import(Params->getRAngleLoc());
- if (!ToRAngleLocOrErr)
- return ToRAngleLocOrErr.takeError();
-
- return TemplateParameterList::Create(
- Importer.getToContext(),
- *ToTemplateLocOrErr,
- *ToLAngleLocOrErr,
- ToParams,
- *ToRAngleLocOrErr,
- ToRequiresClause);
-}
-
Error ASTNodeImporter::ImportTemplateArguments(
const TemplateArgument *FromArgs, unsigned NumFromArgs,
SmallVectorImpl<TemplateArgument> &ToArgs) {
@@ -2011,6 +1999,12 @@ bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar,
}
bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
+ // Eliminate a potential failure point where we attempt to re-import
+ // something we're trying to import while completing ToEnum.
+ if (Decl *ToOrigin = Importer.GetOriginalDecl(ToEnum))
+ if (auto *ToOriginEnum = dyn_cast<EnumDecl>(ToOrigin))
+ ToEnum = ToOriginEnum;
+
StructuralEquivalenceContext Ctx(
Importer.getFromContext(), Importer.getToContext(),
Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer));
@@ -2303,7 +2297,8 @@ ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
if (!FromUT->isIncompleteType() && !FoundUT->isIncompleteType())
return Importer.MapImported(D, FoundTypedef);
}
- // FIXME Handle redecl chain.
+ // FIXME Handle redecl chain. When you do that make consistent changes
+ // in ASTImporterLookupTable too.
break;
}
@@ -2492,6 +2487,8 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
}
if (auto *FoundEnum = dyn_cast<EnumDecl>(FoundDecl)) {
+ if (!hasSameVisibilityContext(FoundEnum, D))
+ continue;
if (IsStructuralMatch(D, FoundEnum))
return Importer.MapImported(D, FoundEnum);
}
@@ -2500,7 +2497,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ Name = Importer.HandleNameConflict(SearchName, DC, IDNS,
ConflictingDecls.data(),
ConflictingDecls.size());
if (!Name)
@@ -2548,26 +2545,6 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
Decl::FOK_None;
}
- // If this record has a definition in the translation unit we're coming from,
- // but this particular declaration is not that definition, import the
- // definition and map to that.
- TagDecl *Definition = D->getDefinition();
- if (Definition && Definition != D &&
- // Friend template declaration must be imported on its own.
- !IsFriendTemplate &&
- // In contrast to a normal CXXRecordDecl, the implicit
- // CXXRecordDecl of ClassTemplateSpecializationDecl is its redeclaration.
- // The definition of the implicit CXXRecordDecl in this case is the
- // ClassTemplateSpecializationDecl itself. Thus, we start with an extra
- // condition in order to be able to import the implict Decl.
- !D->isImplicit()) {
- ExpectedDecl ImportedDefOrErr = import(Definition);
- if (!ImportedDefOrErr)
- return ImportedDefOrErr.takeError();
-
- return Importer.MapImported(D, *ImportedDefOrErr);
- }
-
// Import the major distinguishing characteristics of this record.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
@@ -2596,7 +2573,8 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
auto FoundDecls =
Importer.findDeclsInToCtx(DC, SearchName);
if (!FoundDecls.empty()) {
- // We're going to have to compare D against potentially conflicting Decls, so complete it.
+ // We're going to have to compare D against potentially conflicting Decls,
+ // so complete it.
if (D->hasExternalLexicalStorage() && !D->isCompleteDefinition())
D->getASTContext().getExternalSource()->CompleteType(D);
}
@@ -2625,6 +2603,9 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
if (!IsStructuralMatch(D, FoundRecord, false))
continue;
+ if (!hasSameVisibilityContext(FoundRecord, D))
+ continue;
+
if (IsStructuralMatch(D, FoundRecord)) {
RecordDecl *FoundDef = FoundRecord->getDefinition();
if (D->isThisDeclarationADefinition() && FoundDef) {
@@ -2651,7 +2632,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
} // for
if (!ConflictingDecls.empty() && SearchName) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ Name = Importer.HandleNameConflict(SearchName, DC, IDNS,
ConflictingDecls.data(),
ConflictingDecls.size());
if (!Name)
@@ -2848,6 +2829,22 @@ ExpectedDecl ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
return ToEnumerator;
}
+Error ASTNodeImporter::ImportTemplateParameterLists(const DeclaratorDecl *FromD,
+ DeclaratorDecl *ToD) {
+ unsigned int Num = FromD->getNumTemplateParameterLists();
+ if (Num == 0)
+ return Error::success();
+ SmallVector<TemplateParameterList *, 2> ToTPLists(Num);
+ for (unsigned int I = 0; I < Num; ++I)
+ if (Expected<TemplateParameterList *> ToTPListOrErr =
+ import(FromD->getTemplateParameterList(I)))
+ ToTPLists[I] = *ToTPListOrErr;
+ else
+ return ToTPListOrErr.takeError();
+ ToD->setTemplateParameterListsInfo(Importer.ToContext, ToTPLists);
+ return Error::success();
+}
+
Error ASTNodeImporter::ImportTemplateInformation(
FunctionDecl *FromFD, FunctionDecl *ToFD) {
switch (FromFD->getTemplatedKind()) {
@@ -2894,6 +2891,9 @@ Error ASTNodeImporter::ImportTemplateInformation(
if (!POIOrErr)
return POIOrErr.takeError();
+ if (Error Err = ImportTemplateParameterLists(FromFD, ToFD))
+ return Err;
+
TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind();
ToFD->setFunctionTemplateSpecialization(
std::get<0>(*FunctionAndArgsOrErr), ToTAList, /* InsertPos= */ nullptr,
@@ -2945,6 +2945,30 @@ ASTNodeImporter::FindFunctionTemplateSpecialization(FunctionDecl *FromFD) {
return FoundSpec;
}
+Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD,
+ FunctionDecl *ToFD) {
+ if (Stmt *FromBody = FromFD->getBody()) {
+ if (ExpectedStmt ToBodyOrErr = import(FromBody))
+ ToFD->setBody(*ToBodyOrErr);
+ else
+ return ToBodyOrErr.takeError();
+ }
+ 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();
+}
+
ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
SmallVector<Decl *, 2> Redecls = getCanonicalForwardRedeclChain(D);
@@ -2968,7 +2992,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (ToD)
return ToD;
- const FunctionDecl *FoundByLookup = nullptr;
+ FunctionDecl *FoundByLookup = nullptr;
FunctionTemplateDecl *FromFT = D->getDescribedFunctionTemplate();
// If this is a function template specialization, then try to find the same
@@ -2982,8 +3006,8 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (!FoundFunctionOrErr)
return FoundFunctionOrErr.takeError();
if (FunctionDecl *FoundFunction = *FoundFunctionOrErr) {
- if (D->doesThisDeclarationHaveABody() && FoundFunction->hasBody())
- return Importer.MapImported(D, FoundFunction);
+ if (Decl *Def = FindAndMapDefinition(D, FoundFunction))
+ return Def;
FoundByLookup = FoundFunction;
}
}
@@ -2998,33 +3022,27 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
continue;
if (auto *FoundFunction = dyn_cast<FunctionDecl>(FoundDecl)) {
- if (FoundFunction->hasExternalFormalLinkage() &&
- D->hasExternalFormalLinkage()) {
- if (IsStructuralMatch(D, FoundFunction)) {
- const FunctionDecl *Definition = nullptr;
- if (D->doesThisDeclarationHaveABody() &&
- FoundFunction->hasBody(Definition)) {
- return Importer.MapImported(
- D, const_cast<FunctionDecl *>(Definition));
- }
- FoundByLookup = FoundFunction;
- break;
- }
+ if (!hasSameVisibilityContext(FoundFunction, D))
+ continue;
- // FIXME: Check for overloading more carefully, e.g., by boosting
- // Sema::IsOverload out to the AST library.
+ if (IsStructuralMatch(D, FoundFunction)) {
+ if (Decl *Def = FindAndMapDefinition(D, FoundFunction))
+ return Def;
+ FoundByLookup = FoundFunction;
+ break;
+ }
+ // FIXME: Check for overloading more carefully, e.g., by boosting
+ // Sema::IsOverload out to the AST library.
- // Function overloading is okay in C++.
- if (Importer.getToContext().getLangOpts().CPlusPlus)
- continue;
+ // Function overloading is okay in C++.
+ if (Importer.getToContext().getLangOpts().CPlusPlus)
+ continue;
- // Complain about inconsistent function types.
- Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent)
+ // Complain about inconsistent function types.
+ Importer.ToDiag(Loc, diag::warn_odr_function_type_inconsistent)
<< Name << D->getType() << FoundFunction->getType();
- Importer.ToDiag(FoundFunction->getLocation(),
- diag::note_odr_value_here)
+ Importer.ToDiag(FoundFunction->getLocation(), diag::note_odr_value_here)
<< FoundFunction->getType();
- }
}
ConflictingDecls.push_back(FoundDecl);
@@ -3039,6 +3057,25 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
}
+ // We do not allow more than one in-class declaration of a function. This is
+ // because AST clients like VTableBuilder asserts on this. VTableBuilder
+ // assumes there is only one in-class declaration. Building a redecl
+ // chain would result in more than one in-class declaration for
+ // overrides (even if they are part of the same redecl chain inside the
+ // derived class.)
+ if (FoundByLookup) {
+ if (isa<CXXMethodDecl>(FoundByLookup)) {
+ if (D->getLexicalDeclContext() == D->getDeclContext()) {
+ if (!D->doesThisDeclarationHaveABody())
+ return Importer.MapImported(D, FoundByLookup);
+ else {
+ // Let's continue and build up the redecl chain in this case.
+ // FIXME Merge the functions into one decl.
+ }
+ }
+ }
+ }
+
DeclarationNameInfo NameInfo(Name, Loc);
// Import additional name location/type info.
if (Error Err = ImportDeclarationNameLoc(D->getNameInfo(), NameInfo))
@@ -3086,36 +3123,71 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Create the imported function.
FunctionDecl *ToFunction = nullptr;
if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
+ Expr *ExplicitExpr = nullptr;
+ if (FromConstructor->getExplicitSpecifier().getExpr()) {
+ auto Imp = importSeq(FromConstructor->getExplicitSpecifier().getExpr());
+ if (!Imp)
+ return Imp.takeError();
+ std::tie(ExplicitExpr) = *Imp;
+ }
if (GetImportedOrCreateDecl<CXXConstructorDecl>(
- ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
- ToInnerLocStart, NameInfo, T, TInfo,
- FromConstructor->isExplicit(),
- D->isInlineSpecified(), D->isImplicit(), D->isConstexpr()))
+ ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
+ ToInnerLocStart, NameInfo, T, TInfo,
+ ExplicitSpecifier(
+ ExplicitExpr,
+ FromConstructor->getExplicitSpecifier().getKind()),
+ D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind()))
return ToFunction;
- } else if (isa<CXXDestructorDecl>(D)) {
+ } else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {
+
+ auto Imp =
+ importSeq(const_cast<FunctionDecl *>(FromDtor->getOperatorDelete()),
+ FromDtor->getOperatorDeleteThisArg());
+
+ if (!Imp)
+ return Imp.takeError();
+
+ FunctionDecl *ToOperatorDelete;
+ Expr *ToThisArg;
+ std::tie(ToOperatorDelete, ToThisArg) = *Imp;
+
if (GetImportedOrCreateDecl<CXXDestructorDecl>(
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
D->isImplicit()))
return ToFunction;
+
+ CXXDestructorDecl *ToDtor = cast<CXXDestructorDecl>(ToFunction);
+
+ ToDtor->setOperatorDelete(ToOperatorDelete, ToThisArg);
} else if (CXXConversionDecl *FromConversion =
dyn_cast<CXXConversionDecl>(D)) {
+ Expr *ExplicitExpr = nullptr;
+ if (FromConversion->getExplicitSpecifier().getExpr()) {
+ auto Imp = importSeq(FromConversion->getExplicitSpecifier().getExpr());
+ if (!Imp)
+ return Imp.takeError();
+ std::tie(ExplicitExpr) = *Imp;
+ }
if (GetImportedOrCreateDecl<CXXConversionDecl>(
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
- FromConversion->isExplicit(), D->isConstexpr(), SourceLocation()))
+ ExplicitSpecifier(ExplicitExpr,
+ FromConversion->getExplicitSpecifier().getKind()),
+ D->getConstexprKind(), SourceLocation()))
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->isConstexpr(), SourceLocation()))
+ Method->isInlineSpecified(), D->getConstexprKind(),
+ SourceLocation()))
return ToFunction;
} else {
- if (GetImportedOrCreateDecl(ToFunction, D, Importer.getToContext(), DC,
- ToInnerLocStart, NameInfo, T, TInfo,
- D->getStorageClass(), D->isInlineSpecified(),
- D->hasWrittenPrototype(), D->isConstexpr()))
+ if (GetImportedOrCreateDecl(
+ ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart,
+ NameInfo, T, TInfo, D->getStorageClass(), D->isInlineSpecified(),
+ D->hasWrittenPrototype(), D->getConstexprKind()))
return ToFunction;
}
@@ -3124,6 +3196,11 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
auto *Recent = const_cast<FunctionDecl *>(
FoundByLookup->getMostRecentDecl());
ToFunction->setPreviousDecl(Recent);
+ // FIXME Probably we should merge exception specifications. E.g. In the
+ // "To" context the existing function may have exception specification with
+ // noexcept-unevaluated, while the newly imported function may have an
+ // evaluated noexcept. A call to adjustExceptionSpec() on the imported
+ // decl and its redeclarations may be required.
}
// Import Ctor initializers.
@@ -3184,12 +3261,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
if (D->doesThisDeclarationHaveABody()) {
- if (Stmt *FromBody = D->getBody()) {
- if (ExpectedStmt ToBodyOrErr = import(FromBody))
- ToFunction->setBody(*ToBodyOrErr);
- else
- return ToBodyOrErr.takeError();
- }
+ Error Err = ImportFunctionDeclBody(D, ToFunction);
+
+ if (Err)
+ return std::move(Err);
}
// FIXME: Other bits to merge?
@@ -3292,7 +3367,7 @@ ExpectedDecl ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
}
// FIXME: Why is this case not handled with calling HandleNameConflict?
- Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent)
+ Importer.ToDiag(Loc, diag::warn_odr_field_type_inconsistent)
<< Name << D->getType() << FoundField->getType();
Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here)
<< FoundField->getType();
@@ -3363,7 +3438,7 @@ ExpectedDecl ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
continue;
// FIXME: Why is this case not handled with calling HandleNameConflict?
- Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent)
+ Importer.ToDiag(Loc, diag::warn_odr_field_type_inconsistent)
<< Name << D->getType() << FoundField->getType();
Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here)
<< FoundField->getType();
@@ -3394,9 +3469,6 @@ ExpectedDecl ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
// FIXME here we leak `NamedChain` which is allocated before
return ToIndirectField;
- for (const auto *Attr : D->attrs())
- ToIndirectField->addAttr(Importer.Import(Attr));
-
ToIndirectField->setAccess(D->getAccess());
ToIndirectField->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToIndirectField);
@@ -3451,7 +3523,7 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
SmallVector<TemplateParameterList *, 1> ToTPLists(D->NumTPLists);
auto **FromTPLists = D->getTrailingObjects<TemplateParameterList *>();
for (unsigned I = 0; I < D->NumTPLists; I++) {
- if (auto ListOrErr = ImportTemplateParameterList(FromTPLists[I]))
+ if (auto ListOrErr = import(FromTPLists[I]))
ToTPLists[I] = *ListOrErr;
else
return ListOrErr.takeError();
@@ -3497,7 +3569,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
return FoundIvar;
}
- Importer.ToDiag(Loc, diag::err_odr_ivar_type_inconsistent)
+ Importer.ToDiag(Loc, diag::warn_odr_ivar_type_inconsistent)
<< Name << D->getType() << FoundIvar->getType();
Importer.ToDiag(FoundIvar->getLocation(), diag::note_odr_value_here)
<< FoundIvar->getType();
@@ -3564,58 +3636,56 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) {
continue;
if (auto *FoundVar = dyn_cast<VarDecl>(FoundDecl)) {
- // We have found a variable that we may need to merge with. Check it.
- if (FoundVar->hasExternalFormalLinkage() &&
- D->hasExternalFormalLinkage()) {
- if (Importer.IsStructurallyEquivalent(D->getType(),
- FoundVar->getType())) {
-
- // The VarDecl in the "From" context has a definition, but in the
- // "To" context we already have a definition.
- VarDecl *FoundDef = FoundVar->getDefinition();
- if (D->isThisDeclarationADefinition() && FoundDef)
- // FIXME Check for ODR error if the two definitions have
- // different initializers?
- return Importer.MapImported(D, FoundDef);
-
- // The VarDecl in the "From" context has an initializer, but in the
- // "To" context we already have an initializer.
- const VarDecl *FoundDInit = nullptr;
- if (D->getInit() && FoundVar->getAnyInitializer(FoundDInit))
- // FIXME Diagnose ODR error if the two initializers are different?
- return Importer.MapImported(D, const_cast<VarDecl*>(FoundDInit));
+ if (!hasSameVisibilityContext(FoundVar, D))
+ continue;
+ if (Importer.IsStructurallyEquivalent(D->getType(),
+ FoundVar->getType())) {
+
+ // The VarDecl in the "From" context has a definition, but in the
+ // "To" context we already have a definition.
+ VarDecl *FoundDef = FoundVar->getDefinition();
+ if (D->isThisDeclarationADefinition() && FoundDef)
+ // FIXME Check for ODR error if the two definitions have
+ // different initializers?
+ return Importer.MapImported(D, FoundDef);
+
+ // The VarDecl in the "From" context has an initializer, but in the
+ // "To" context we already have an initializer.
+ const VarDecl *FoundDInit = nullptr;
+ if (D->getInit() && FoundVar->getAnyInitializer(FoundDInit))
+ // FIXME Diagnose ODR error if the two initializers are different?
+ return Importer.MapImported(D, const_cast<VarDecl*>(FoundDInit));
+
+ FoundByLookup = FoundVar;
+ break;
+ }
+
+ const ArrayType *FoundArray
+ = Importer.getToContext().getAsArrayType(FoundVar->getType());
+ const ArrayType *TArray
+ = Importer.getToContext().getAsArrayType(D->getType());
+ if (FoundArray && TArray) {
+ if (isa<IncompleteArrayType>(FoundArray) &&
+ isa<ConstantArrayType>(TArray)) {
+ // Import the type.
+ if (auto TyOrErr = import(D->getType()))
+ FoundVar->setType(*TyOrErr);
+ else
+ return TyOrErr.takeError();
FoundByLookup = FoundVar;
break;
+ } else if (isa<IncompleteArrayType>(TArray) &&
+ isa<ConstantArrayType>(FoundArray)) {
+ FoundByLookup = FoundVar;
+ break;
}
-
- const ArrayType *FoundArray
- = Importer.getToContext().getAsArrayType(FoundVar->getType());
- const ArrayType *TArray
- = Importer.getToContext().getAsArrayType(D->getType());
- if (FoundArray && TArray) {
- if (isa<IncompleteArrayType>(FoundArray) &&
- isa<ConstantArrayType>(TArray)) {
- // Import the type.
- if (auto TyOrErr = import(D->getType()))
- FoundVar->setType(*TyOrErr);
- else
- return TyOrErr.takeError();
-
- FoundByLookup = FoundVar;
- break;
- } else if (isa<IncompleteArrayType>(TArray) &&
- isa<ConstantArrayType>(FoundArray)) {
- FoundByLookup = FoundVar;
- break;
- }
- }
-
- Importer.ToDiag(Loc, diag::err_odr_variable_type_inconsistent)
- << Name << D->getType() << FoundVar->getType();
- Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here)
- << FoundVar->getType();
}
+
+ Importer.ToDiag(Loc, diag::warn_odr_variable_type_inconsistent)
+ << Name << D->getType() << FoundVar->getType();
+ Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here)
+ << FoundVar->getType();
}
ConflictingDecls.push_back(FoundDecl);
@@ -3777,7 +3847,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
// Check return types.
if (!Importer.IsStructurallyEquivalent(D->getReturnType(),
FoundMethod->getReturnType())) {
- Importer.ToDiag(Loc, diag::err_odr_objc_method_result_type_inconsistent)
+ Importer.ToDiag(Loc, diag::warn_odr_objc_method_result_type_inconsistent)
<< D->isInstanceMethod() << Name << D->getReturnType()
<< FoundMethod->getReturnType();
Importer.ToDiag(FoundMethod->getLocation(),
@@ -3789,7 +3859,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
// Check the number of parameters.
if (D->param_size() != FoundMethod->param_size()) {
- Importer.ToDiag(Loc, diag::err_odr_objc_method_num_params_inconsistent)
+ Importer.ToDiag(Loc, diag::warn_odr_objc_method_num_params_inconsistent)
<< D->isInstanceMethod() << Name
<< D->param_size() << FoundMethod->param_size();
Importer.ToDiag(FoundMethod->getLocation(),
@@ -3806,7 +3876,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
if (!Importer.IsStructurallyEquivalent((*P)->getType(),
(*FoundP)->getType())) {
Importer.FromDiag((*P)->getLocation(),
- diag::err_odr_objc_method_param_type_inconsistent)
+ diag::warn_odr_objc_method_param_type_inconsistent)
<< D->isInstanceMethod() << Name
<< (*P)->getType() << (*FoundP)->getType();
Importer.ToDiag((*FoundP)->getLocation(), diag::note_odr_value_here)
@@ -3819,7 +3889,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
// Check variadic/non-variadic.
// Check the number of parameters.
if (D->isVariadic() != FoundMethod->isVariadic()) {
- Importer.ToDiag(Loc, diag::err_odr_objc_method_variadic_inconsistent)
+ Importer.ToDiag(Loc, diag::warn_odr_objc_method_variadic_inconsistent)
<< D->isInstanceMethod() << Name;
Importer.ToDiag(FoundMethod->getLocation(),
diag::note_odr_objc_method_here)
@@ -4364,7 +4434,7 @@ Error ASTNodeImporter::ImportDefinition(
if ((bool)FromSuper != (bool)ToSuper ||
(FromSuper && !declaresSameEntity(FromSuper, ToSuper))) {
Importer.ToDiag(To->getLocation(),
- diag::err_odr_objc_superclass_inconsistent)
+ diag::warn_odr_objc_superclass_inconsistent)
<< To->getDeclName();
if (ToSuper)
Importer.ToDiag(To->getSuperClassLoc(), diag::note_odr_objc_superclass)
@@ -4633,7 +4703,7 @@ ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
!declaresSameEntity(Super->getCanonicalDecl(),
Impl->getSuperClass()))) {
Importer.ToDiag(Impl->getLocation(),
- diag::err_odr_objc_superclass_inconsistent)
+ diag::warn_odr_objc_superclass_inconsistent)
<< Iface->getDeclName();
// FIXME: It would be nice to have the location of the superclass
// below.
@@ -4681,7 +4751,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
// Check property types.
if (!Importer.IsStructurallyEquivalent(D->getType(),
FoundProp->getType())) {
- Importer.ToDiag(Loc, diag::err_odr_objc_property_type_inconsistent)
+ Importer.ToDiag(Loc, diag::warn_odr_objc_property_type_inconsistent)
<< Name << D->getType() << FoundProp->getType();
Importer.ToDiag(FoundProp->getLocation(), diag::note_odr_value_here)
<< FoundProp->getType();
@@ -4788,7 +4858,7 @@ ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
// vs. @dynamic).
if (D->getPropertyImplementation() != ToImpl->getPropertyImplementation()) {
Importer.ToDiag(ToImpl->getLocation(),
- diag::err_odr_objc_property_impl_kind_inconsistent)
+ diag::warn_odr_objc_property_impl_kind_inconsistent)
<< Property->getDeclName()
<< (ToImpl->getPropertyImplementation()
== ObjCPropertyImplDecl::Dynamic);
@@ -4804,7 +4874,7 @@ ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize &&
Ivar != ToImpl->getPropertyIvarDecl()) {
Importer.ToDiag(ToImpl->getPropertyIvarDeclLoc(),
- diag::err_odr_objc_synthesize_ivar_inconsistent)
+ diag::warn_odr_objc_synthesize_ivar_inconsistent)
<< Property->getDeclName()
<< ToImpl->getPropertyIvarDecl()->getDeclName()
<< Ivar->getDeclName();
@@ -4888,8 +4958,7 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
return LocationOrErr.takeError();
// Import template parameters.
- auto TemplateParamsOrErr = ImportTemplateParameterList(
- D->getTemplateParameters());
+ auto TemplateParamsOrErr = import(D->getTemplateParameters());
if (!TemplateParamsOrErr)
return TemplateParamsOrErr.takeError();
@@ -4905,31 +4974,20 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
return ToD;
}
-// Returns the definition for a (forward) declaration of a ClassTemplateDecl, if
+// Returns the definition for a (forward) declaration of a TemplateDecl, if
// it has any definition in the redecl chain.
-static ClassTemplateDecl *getDefinition(ClassTemplateDecl *D) {
- CXXRecordDecl *ToTemplatedDef = D->getTemplatedDecl()->getDefinition();
+template <typename T> static auto getTemplateDefinition(T *D) -> T * {
+ assert(D->getTemplatedDecl() && "Should be called on templates only");
+ auto *ToTemplatedDef = D->getTemplatedDecl()->getDefinition();
if (!ToTemplatedDef)
return nullptr;
- ClassTemplateDecl *TemplateWithDef =
- ToTemplatedDef->getDescribedClassTemplate();
- return TemplateWithDef;
+ auto *TemplateWithDef = ToTemplatedDef->getDescribedTemplate();
+ return cast_or_null<T>(TemplateWithDef);
}
ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
bool IsFriend = D->getFriendObjectKind() != Decl::FOK_None;
- // If this template has a definition in the translation unit we're coming
- // from, but this particular declaration is not that definition, import the
- // definition and map to that.
- ClassTemplateDecl *Definition = getDefinition(D);
- if (Definition && Definition != D && !IsFriend) {
- if (ExpectedDecl ImportedDefOrErr = import(Definition))
- return Importer.MapImported(D, *ImportedDefOrErr);
- else
- return ImportedDefOrErr.takeError();
- }
-
// Import the major distinguishing characteristics of this class template.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
@@ -4956,7 +5014,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (FoundTemplate) {
if (IsStructuralMatch(D, FoundTemplate)) {
- ClassTemplateDecl *TemplateWithDef = getDefinition(FoundTemplate);
+ ClassTemplateDecl *TemplateWithDef =
+ getTemplateDefinition(FoundTemplate);
if (D->isThisDeclarationADefinition() && TemplateWithDef) {
return Importer.MapImported(D, TemplateWithDef);
}
@@ -4986,8 +5045,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
return std::move(Err);
// Create the class template declaration itself.
- auto TemplateParamsOrErr = ImportTemplateParameterList(
- D->getTemplateParameters());
+ auto TemplateParamsOrErr = import(D->getTemplateParameters());
if (!TemplateParamsOrErr)
return TemplateParamsOrErr.takeError();
@@ -5019,6 +5077,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// and this time the lookup finds the previous fwd friend class template.
// In this case we must set up the previous decl for the templated decl.
if (!ToTemplated->getPreviousDecl()) {
+ assert(FoundByLookup->getTemplatedDecl() &&
+ "Found decl must have its templated decl set");
CXXRecordDecl *PrevTemplated =
FoundByLookup->getTemplatedDecl()->getMostRecentDecl();
if (ToTemplated != PrevTemplated)
@@ -5041,17 +5101,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl *D) {
- // If this record has a definition in the translation unit we're coming from,
- // but this particular declaration is not that definition, import the
- // definition and map to that.
- TagDecl *Definition = D->getDefinition();
- if (Definition && Definition != D) {
- if (ExpectedDecl ImportedDefOrErr = import(Definition))
- return Importer.MapImported(D, *ImportedDefOrErr);
- else
- return ImportedDefOrErr.takeError();
- }
-
ClassTemplateDecl *ClassTemplate;
if (Error Err = importInto(ClassTemplate, D->getSpecializedTemplate()))
return std::move(Err);
@@ -5069,154 +5118,146 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
// Try to find an existing specialization with these template arguments.
void *InsertPos = nullptr;
- ClassTemplateSpecializationDecl *D2 = nullptr;
+ ClassTemplateSpecializationDecl *PrevDecl = nullptr;
ClassTemplatePartialSpecializationDecl *PartialSpec =
dyn_cast<ClassTemplatePartialSpecializationDecl>(D);
if (PartialSpec)
- D2 = ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos);
+ PrevDecl =
+ ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos);
else
- D2 = ClassTemplate->findSpecialization(TemplateArgs, InsertPos);
- ClassTemplateSpecializationDecl * const PrevDecl = D2;
- RecordDecl *FoundDef = D2 ? D2->getDefinition() : nullptr;
- if (FoundDef) {
- if (!D->isCompleteDefinition()) {
- // The "From" translation unit only had a forward declaration; call it
- // the same declaration.
- // TODO Handle the redecl chain properly!
- return Importer.MapImported(D, FoundDef);
- }
-
- if (IsStructuralMatch(D, FoundDef)) {
+ PrevDecl = ClassTemplate->findSpecialization(TemplateArgs, InsertPos);
+
+ if (PrevDecl) {
+ if (IsStructuralMatch(D, PrevDecl)) {
+ if (D->isThisDeclarationADefinition() && PrevDecl->getDefinition()) {
+ Importer.MapImported(D, PrevDecl->getDefinition());
+ // Import those default field initializers which have been
+ // instantiated in the "From" context, but not in the "To" context.
+ for (auto *FromField : D->fields()) {
+ auto ToOrErr = import(FromField);
+ if (!ToOrErr)
+ return ToOrErr.takeError();
+ }
- Importer.MapImported(D, FoundDef);
+ // Import those methods which have been instantiated in the
+ // "From" context, but not in the "To" context.
+ for (CXXMethodDecl *FromM : D->methods()) {
+ auto ToOrErr = import(FromM);
+ if (!ToOrErr)
+ return ToOrErr.takeError();
+ }
- // Import those those default field initializers which have been
- // instantiated in the "From" context, but not in the "To" context.
- for (auto *FromField : D->fields()) {
- auto ToOrErr = import(FromField);
- if (!ToOrErr)
- // FIXME: return the error?
- consumeError(ToOrErr.takeError());
+ // TODO Import instantiated default arguments.
+ // TODO Import instantiated exception specifications.
+ //
+ // Generally, ASTCommon.h/DeclUpdateKind enum gives a very good hint
+ // what else could be fused during an AST merge.
+ return PrevDecl;
}
+ } else { // ODR violation.
+ // FIXME HandleNameConflict
+ return make_error<ImportError>(ImportError::NameConflict);
+ }
+ }
- // Import those methods which have been instantiated in the
- // "From" context, but not in the "To" context.
- for (CXXMethodDecl *FromM : D->methods()) {
- auto ToOrErr = import(FromM);
- if (!ToOrErr)
- // FIXME: return the error?
- consumeError(ToOrErr.takeError());
- }
+ // Import the location of this declaration.
+ ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc());
+ if (!BeginLocOrErr)
+ return BeginLocOrErr.takeError();
+ ExpectedSLoc IdLocOrErr = import(D->getLocation());
+ if (!IdLocOrErr)
+ return IdLocOrErr.takeError();
- // TODO Import instantiated default arguments.
- // TODO Import instantiated exception specifications.
- //
- // Generally, ASTCommon.h/DeclUpdateKind enum gives a very good hint what
- // else could be fused during an AST merge.
+ // Create the specialization.
+ ClassTemplateSpecializationDecl *D2 = nullptr;
+ if (PartialSpec) {
+ // Import TemplateArgumentListInfo.
+ TemplateArgumentListInfo ToTAInfo;
+ const auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten();
+ if (Error Err = ImportTemplateArgumentListInfo(ASTTemplateArgs, ToTAInfo))
+ return std::move(Err);
- return FoundDef;
- }
- } else { // We either couldn't find any previous specialization in the "To"
- // context, or we found one but without definition. Let's create a
- // new specialization and register that at the class template.
+ QualType CanonInjType;
+ if (Error Err = importInto(
+ CanonInjType, PartialSpec->getInjectedSpecializationType()))
+ 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,
+ llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()),
+ ToTAInfo, CanonInjType,
+ cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
+ return D2;
- // Import the location of this declaration.
- ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc());
- if (!BeginLocOrErr)
- return BeginLocOrErr.takeError();
- ExpectedSLoc IdLocOrErr = import(D->getLocation());
- if (!IdLocOrErr)
- return IdLocOrErr.takeError();
-
- if (PartialSpec) {
- // Import TemplateArgumentListInfo.
- TemplateArgumentListInfo ToTAInfo;
- const auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten();
- if (Error Err = ImportTemplateArgumentListInfo(ASTTemplateArgs, ToTAInfo))
- return std::move(Err);
+ // Update InsertPos, because preceding import calls may have invalidated
+ // it by adding new specializations.
+ if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos))
+ // Add this partial specialization to the class template.
+ ClassTemplate->AddPartialSpecialization(
+ cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos);
- QualType CanonInjType;
- if (Error Err = importInto(
- CanonInjType, PartialSpec->getInjectedSpecializationType()))
- return std::move(Err);
- CanonInjType = CanonInjType.getCanonicalType();
+ } else { // Not a partial specialization.
+ if (GetImportedOrCreateDecl(
+ D2, D, Importer.getToContext(), D->getTagKind(), DC,
+ *BeginLocOrErr, *IdLocOrErr, ClassTemplate, TemplateArgs,
+ PrevDecl))
+ return D2;
- auto ToTPListOrErr = ImportTemplateParameterList(
- PartialSpec->getTemplateParameters());
- if (!ToTPListOrErr)
- return ToTPListOrErr.takeError();
+ // Update InsertPos, because preceding import calls may have invalidated
+ // it by adding new specializations.
+ if (!ClassTemplate->findSpecialization(TemplateArgs, InsertPos))
+ // Add this specialization to the class template.
+ ClassTemplate->AddSpecialization(D2, InsertPos);
+ }
- if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
- D2, D, Importer.getToContext(), D->getTagKind(), DC,
- *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, ClassTemplate,
- llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()),
- ToTAInfo, CanonInjType,
- cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
- return D2;
+ D2->setSpecializationKind(D->getSpecializationKind());
- // Update InsertPos, because preceding import calls may have invalidated
- // it by adding new specializations.
- if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos))
- // Add this partial specialization to the class template.
- ClassTemplate->AddPartialSpecialization(
- cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos);
+ // Set the context of this specialization/instantiation.
+ D2->setLexicalDeclContext(LexicalDC);
- } else { // Not a partial specialization.
- if (GetImportedOrCreateDecl(
- D2, D, Importer.getToContext(), D->getTagKind(), DC,
- *BeginLocOrErr, *IdLocOrErr, ClassTemplate, TemplateArgs,
- PrevDecl))
- return D2;
+ // Add to the DC only if it was an explicit specialization/instantiation.
+ if (D2->isExplicitInstantiationOrSpecialization()) {
+ LexicalDC->addDeclInternal(D2);
+ }
- // Update InsertPos, because preceding import calls may have invalidated
- // it by adding new specializations.
- if (!ClassTemplate->findSpecialization(TemplateArgs, InsertPos))
- // Add this specialization to the class template.
- ClassTemplate->AddSpecialization(D2, InsertPos);
- }
+ // Import the qualifier, if any.
+ if (auto LocOrErr = import(D->getQualifierLoc()))
+ D2->setQualifierInfo(*LocOrErr);
+ else
+ return LocOrErr.takeError();
- D2->setSpecializationKind(D->getSpecializationKind());
+ if (auto *TSI = D->getTypeAsWritten()) {
+ if (auto TInfoOrErr = import(TSI))
+ D2->setTypeAsWritten(*TInfoOrErr);
+ else
+ return TInfoOrErr.takeError();
- // Import the qualifier, if any.
- if (auto LocOrErr = import(D->getQualifierLoc()))
- D2->setQualifierInfo(*LocOrErr);
+ if (auto LocOrErr = import(D->getTemplateKeywordLoc()))
+ D2->setTemplateKeywordLoc(*LocOrErr);
else
return LocOrErr.takeError();
- if (auto *TSI = D->getTypeAsWritten()) {
- if (auto TInfoOrErr = import(TSI))
- D2->setTypeAsWritten(*TInfoOrErr);
- else
- return TInfoOrErr.takeError();
-
- if (auto LocOrErr = import(D->getTemplateKeywordLoc()))
- D2->setTemplateKeywordLoc(*LocOrErr);
- else
- return LocOrErr.takeError();
-
- if (auto LocOrErr = import(D->getExternLoc()))
- D2->setExternLoc(*LocOrErr);
- else
- return LocOrErr.takeError();
- }
-
- if (D->getPointOfInstantiation().isValid()) {
- if (auto POIOrErr = import(D->getPointOfInstantiation()))
- D2->setPointOfInstantiation(*POIOrErr);
- else
- return POIOrErr.takeError();
- }
+ if (auto LocOrErr = import(D->getExternLoc()))
+ D2->setExternLoc(*LocOrErr);
+ else
+ return LocOrErr.takeError();
+ }
- D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind());
+ if (D->getPointOfInstantiation().isValid()) {
+ if (auto POIOrErr = import(D->getPointOfInstantiation()))
+ D2->setPointOfInstantiation(*POIOrErr);
+ else
+ return POIOrErr.takeError();
+ }
- // Set the context of this specialization/instantiation.
- D2->setLexicalDeclContext(LexicalDC);
+ D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind());
- // Add to the DC only if it was an explicit specialization/instantiation.
- if (D2->isExplicitInstantiationOrSpecialization()) {
- LexicalDC->addDeclInternal(D2);
- }
- }
if (D->isCompleteDefinition())
if (Error Err = ImportDefinition(D, D2))
return std::move(Err);
@@ -5296,8 +5337,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
return std::move(Err);
// Create the variable template declaration itself.
- auto TemplateParamsOrErr = ImportTemplateParameterList(
- D->getTemplateParameters());
+ auto TemplateParamsOrErr = import(D->getTemplateParameters());
if (!TemplateParamsOrErr)
return TemplateParamsOrErr.takeError();
@@ -5333,7 +5373,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
return ImportedDefOrErr.takeError();
}
- VarTemplateDecl *VarTemplate;
+ VarTemplateDecl *VarTemplate = nullptr;
if (Error Err = importInto(VarTemplate, D->getSpecializedTemplate()))
return std::move(Err);
@@ -5402,8 +5442,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
*FromTAArgsAsWritten, ArgInfos))
return std::move(Err);
- auto ToTPListOrErr = ImportTemplateParameterList(
- FromPartial->getTemplateParameters());
+ auto ToTPListOrErr = import(FromPartial->getTemplateParameters());
if (!ToTPListOrErr)
return ToTPListOrErr.takeError();
@@ -5481,32 +5520,37 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (ToD)
return ToD;
+ const FunctionTemplateDecl *FoundByLookup = nullptr;
+
// Try to find a function in our own ("to") context with the same name, same
// type, and in the same context as the function we're importing.
+ // FIXME Split this into a separate function.
if (!LexicalDC->isFunctionOrMethod()) {
- unsigned IDNS = Decl::IDNS_Ordinary;
+ unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend;
auto FoundDecls = Importer.findDeclsInToCtx(DC, Name);
for (auto *FoundDecl : FoundDecls) {
if (!FoundDecl->isInIdentifierNamespace(IDNS))
continue;
- if (auto *FoundFunction =
- dyn_cast<FunctionTemplateDecl>(FoundDecl)) {
- if (FoundFunction->hasExternalFormalLinkage() &&
+ if (auto *FoundTemplate = dyn_cast<FunctionTemplateDecl>(FoundDecl)) {
+ if (FoundTemplate->hasExternalFormalLinkage() &&
D->hasExternalFormalLinkage()) {
- if (IsStructuralMatch(D, FoundFunction)) {
- Importer.MapImported(D, FoundFunction);
- // FIXME: Actually try to merge the body and other attributes.
- return FoundFunction;
+ if (IsStructuralMatch(D, FoundTemplate)) {
+ FunctionTemplateDecl *TemplateWithDef =
+ getTemplateDefinition(FoundTemplate);
+ if (D->isThisDeclarationADefinition() && TemplateWithDef) {
+ return Importer.MapImported(D, TemplateWithDef);
+ }
+ FoundByLookup = FoundTemplate;
+ break;
}
+ // TODO: handle conflicting names
}
}
- // TODO: handle conflicting names
}
}
- auto ParamsOrErr = ImportTemplateParameterList(
- D->getTemplateParameters());
+ auto ParamsOrErr = import(D->getTemplateParameters());
if (!ParamsOrErr)
return ParamsOrErr.takeError();
@@ -5520,10 +5564,25 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
return ToFunc;
TemplatedFD->setDescribedFunctionTemplate(ToFunc);
+
ToFunc->setAccess(D->getAccess());
ToFunc->setLexicalDeclContext(LexicalDC);
-
LexicalDC->addDeclInternal(ToFunc);
+
+ if (FoundByLookup) {
+ auto *Recent =
+ const_cast<FunctionTemplateDecl *>(FoundByLookup->getMostRecentDecl());
+ if (!TemplatedFD->getPreviousDecl()) {
+ assert(FoundByLookup->getTemplatedDecl() &&
+ "Found decl must have its templated decl set");
+ auto *PrevTemplated =
+ FoundByLookup->getTemplatedDecl()->getMostRecentDecl();
+ if (TemplatedFD != PrevTemplated)
+ TemplatedFD->setPreviousDecl(PrevTemplated);
+ }
+ ToFunc->setPreviousDecl(Recent);
+ }
+
return ToFunc;
}
@@ -5539,6 +5598,8 @@ ExpectedStmt ASTNodeImporter::VisitStmt(Stmt *S) {
ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
+ if (Importer.returnWithErrorInTest())
+ return make_error<ImportError>(ImportError::UnsupportedConstruct);
SmallVector<IdentifierInfo *, 4> Names;
for (unsigned I = 0, E = S->getNumOutputs(); I != E; I++) {
IdentifierInfo *ToII = Importer.Import(S->getOutputIdentifier(I));
@@ -5578,12 +5639,17 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
return InputOrErr.takeError();
}
- SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs());
+ SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs() +
+ S->getNumLabels());
if (Error Err = ImportContainerChecked(S->outputs(), Exprs))
return std::move(Err);
+ if (Error Err =
+ ImportArrayChecked(S->inputs(), Exprs.begin() + S->getNumOutputs()))
+ return std::move(Err);
+
if (Error Err = ImportArrayChecked(
- S->inputs(), Exprs.begin() + S->getNumOutputs()))
+ S->labels(), Exprs.begin() + S->getNumOutputs() + S->getNumInputs()))
return std::move(Err);
ExpectedSLoc AsmLocOrErr = import(S->getAsmLoc());
@@ -5609,6 +5675,7 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
*AsmStrOrErr,
S->getNumClobbers(),
Clobbers.data(),
+ S->getNumLabels(),
*RParenLocOrErr);
}
@@ -6079,6 +6146,33 @@ ExpectedStmt ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) {
E->isMicrosoftABI());
}
+ExpectedStmt ASTNodeImporter::VisitChooseExpr(ChooseExpr *E) {
+ auto Imp = importSeq(E->getCond(), E->getLHS(), E->getRHS(),
+ E->getBuiltinLoc(), E->getRParenLoc(), E->getType());
+ if (!Imp)
+ return Imp.takeError();
+
+ Expr *ToCond;
+ Expr *ToLHS;
+ Expr *ToRHS;
+ SourceLocation ToBuiltinLoc, ToRParenLoc;
+ QualType ToType;
+ std::tie(ToCond, ToLHS, ToRHS, ToBuiltinLoc, ToRParenLoc, ToType) = *Imp;
+
+ ExprValueKind VK = E->getValueKind();
+ ExprObjectKind OK = E->getObjectKind();
+
+ bool TypeDependent = ToCond->isTypeDependent();
+ bool ValueDependent = ToCond->isValueDependent();
+
+ // The value of CondIsTrue only matters if the value is not
+ // condition-dependent.
+ bool CondIsTrue = !E->isConditionDependent() && E->isConditionTrue();
+
+ return new (Importer.getToContext())
+ ChooseExpr(ToBuiltinLoc, ToCond, ToLHS, ToRHS, ToType, VK, OK,
+ ToRParenLoc, CondIsTrue, TypeDependent, ValueDependent);
+}
ExpectedStmt ASTNodeImporter::VisitGNUNullExpr(GNUNullExpr *E) {
ExpectedType TypeOrErr = import(E->getType());
@@ -6141,7 +6235,7 @@ ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
auto *ToE = DeclRefExpr::Create(
Importer.getToContext(), ToQualifierLoc, ToTemplateKeywordLoc, ToDecl,
E->refersToEnclosingVariableOrCapture(), ToLocation, ToType,
- E->getValueKind(), ToFoundD, ToResInfo);
+ E->getValueKind(), ToFoundD, ToResInfo, E->isNonOdrUse());
if (E->hadMultipleCandidates())
ToE->setHadMultipleCandidates(true);
return ToE;
@@ -6327,6 +6421,13 @@ ExpectedStmt ASTNodeImporter::VisitConstantExpr(ConstantExpr *E) {
Expr *ToSubExpr;
std::tie(ToSubExpr) = *Imp;
+ // TODO : Handle APValue::ValueKind that require importing.
+ APValue::ValueKind Kind = E->getResultAPValueKind();
+ if (Kind == APValue::Int || Kind == APValue::Float ||
+ Kind == APValue::FixedPoint || Kind == APValue::ComplexFloat ||
+ Kind == APValue::ComplexInt)
+ return ConstantExpr::Create(Importer.getToContext(), ToSubExpr,
+ E->getAPValueResult());
return ConstantExpr::Create(Importer.getToContext(), ToSubExpr);
}
@@ -6763,8 +6864,12 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
if (!ToParamOrErr)
return ToParamOrErr.takeError();
+ auto UsedContextOrErr = Importer.ImportContext(E->getUsedContext());
+ if (!UsedContextOrErr)
+ return UsedContextOrErr.takeError();
+
return CXXDefaultArgExpr::Create(
- Importer.getToContext(), *ToUsedLocOrErr, *ToParamOrErr);
+ Importer.getToContext(), *ToUsedLocOrErr, *ToParamOrErr, *UsedContextOrErr);
}
ExpectedStmt
@@ -6898,7 +7003,8 @@ ExpectedStmt ASTNodeImporter::VisitCXXNewExpr(CXXNewExpr *E) {
FunctionDecl *ToOperatorNew, *ToOperatorDelete;
SourceRange ToTypeIdParens, ToSourceRange, ToDirectInitRange;
- Expr *ToArraySize, *ToInitializer;
+ Optional<Expr *> ToArraySize;
+ Expr *ToInitializer;
QualType ToType;
TypeSourceInfo *ToAllocatedTypeSourceInfo;
std::tie(
@@ -7051,15 +7157,20 @@ ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) {
DeclarationNameInfo ToMemberNameInfo(ToName, ToLoc);
+ TemplateArgumentListInfo ToTAInfo, *ResInfo = nullptr;
if (E->hasExplicitTemplateArgs()) {
- // FIXME: handle template arguments
- return make_error<ImportError>(ImportError::UnsupportedConstruct);
+ if (Error Err =
+ ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(),
+ E->template_arguments(), ToTAInfo))
+ return std::move(Err);
+ ResInfo = &ToTAInfo;
}
- return MemberExpr::Create(
- Importer.getToContext(), ToBase, E->isArrow(), ToOperatorLoc,
- ToQualifierLoc, ToTemplateKeywordLoc, ToMemberDecl, ToFoundDecl,
- ToMemberNameInfo, nullptr, ToType, E->getValueKind(), E->getObjectKind());
+ return MemberExpr::Create(Importer.getToContext(), ToBase, E->isArrow(),
+ ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc,
+ ToMemberDecl, ToFoundDecl, ToMemberNameInfo,
+ ResInfo, ToType, E->getValueKind(),
+ E->getObjectKind(), E->isNonOdrUse());
}
ExpectedStmt
@@ -7334,23 +7445,10 @@ ExpectedStmt ASTNodeImporter::VisitLambdaExpr(LambdaExpr *E) {
return ToClassOrErr.takeError();
CXXRecordDecl *ToClass = *ToClassOrErr;
- // NOTE: lambda classes are created with BeingDefined flag set up.
- // It means that ImportDefinition doesn't work for them and we should fill it
- // manually.
- if (ToClass->isBeingDefined()) {
- for (auto FromField : FromClass->fields()) {
- auto ToFieldOrErr = import(FromField);
- if (!ToFieldOrErr)
- return ToFieldOrErr.takeError();
- }
- }
-
auto ToCallOpOrErr = import(E->getCallOperator());
if (!ToCallOpOrErr)
return ToCallOpOrErr.takeError();
- ToClass->completeDefinition();
-
SmallVector<LambdaCapture, 8> ToCaptures;
ToCaptures.reserve(E->capture_size());
for (const auto &FromCapture : E->captures()) {
@@ -7486,8 +7584,12 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
if (!ToFieldOrErr)
return ToFieldOrErr.takeError();
+ auto UsedContextOrErr = Importer.ImportContext(E->getUsedContext());
+ if (!UsedContextOrErr)
+ return UsedContextOrErr.takeError();
+
return CXXDefaultInitExpr::Create(
- Importer.getToContext(), *ToBeginLocOrErr, *ToFieldOrErr);
+ Importer.getToContext(), *ToBeginLocOrErr, *ToFieldOrErr, *UsedContextOrErr);
}
ExpectedStmt ASTNodeImporter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
@@ -7613,24 +7715,22 @@ void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod,
ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
ASTContext &FromContext, FileManager &FromFileManager,
bool MinimalImport,
- ASTImporterLookupTable *LookupTable)
- : LookupTable(LookupTable), ToContext(ToContext), FromContext(FromContext),
+ std::shared_ptr<ASTImporterSharedState> SharedState)
+ : SharedState(SharedState), ToContext(ToContext), FromContext(FromContext),
ToFileManager(ToFileManager), FromFileManager(FromFileManager),
Minimal(MinimalImport) {
+ // Create a default state without the lookup table: LLDB case.
+ if (!SharedState) {
+ this->SharedState = std::make_shared<ASTImporterSharedState>();
+ }
+
ImportedDecls[FromContext.getTranslationUnitDecl()] =
ToContext.getTranslationUnitDecl();
}
ASTImporter::~ASTImporter() = default;
-Expected<QualType> ASTImporter::Import_New(QualType FromT) {
- QualType ToT = Import(FromT);
- if (ToT.isNull() && !FromT.isNull())
- return make_error<ImportError>();
- return ToT;
-}
-
Optional<unsigned> ASTImporter::getFieldIndex(Decl *F) {
assert(F && (isa<FieldDecl>(*F) || isa<IndirectFieldDecl>(*F)) &&
"Try to get field index for non-field.");
@@ -7663,28 +7763,46 @@ ASTImporter::findDeclsInToCtx(DeclContext *DC, DeclarationName Name) {
// then the enum constant 'A' and the variable 'A' violates ODR.
// We can diagnose this only if we search in the redecl context.
DeclContext *ReDC = DC->getRedeclContext();
- if (LookupTable) {
+ if (SharedState->getLookupTable()) {
ASTImporterLookupTable::LookupResult LookupResult =
- LookupTable->lookup(ReDC, Name);
+ SharedState->getLookupTable()->lookup(ReDC, Name);
return FoundDeclsTy(LookupResult.begin(), LookupResult.end());
} else {
- // FIXME Can we remove this kind of lookup?
- // Or lldb really needs this C/C++ lookup?
- FoundDeclsTy Result;
- ReDC->localUncachedLookup(Name, Result);
+ DeclContext::lookup_result NoloadLookupResult = ReDC->noload_lookup(Name);
+ FoundDeclsTy Result(NoloadLookupResult.begin(), NoloadLookupResult.end());
+ // We must search by the slow case of localUncachedLookup because that is
+ // working even if there is no LookupPtr for the DC. We could use
+ // DC::buildLookup() to create the LookupPtr, but that would load external
+ // decls again, we must avoid that case.
+ // Also, even if we had the LookupPtr, we must find Decls which are not
+ // in the LookupPtr, so we need the slow case.
+ // These cases are handled in ASTImporterLookupTable, but we cannot use
+ // that with LLDB since that traverses through the AST which initiates the
+ // load of external decls again via DC::decls(). And again, we must avoid
+ // loading external decls during the import.
+ if (Result.empty())
+ ReDC->localUncachedLookup(Name, Result);
return Result;
}
}
void ASTImporter::AddToLookupTable(Decl *ToD) {
- if (LookupTable)
- if (auto *ToND = dyn_cast<NamedDecl>(ToD))
- LookupTable->add(ToND);
+ SharedState->addDeclToLookup(ToD);
+}
+
+Expected<Decl *> ASTImporter::ImportImpl(Decl *FromD) {
+ // Import the decl using ASTNodeImporter.
+ ASTNodeImporter Importer(*this);
+ return Importer.Visit(FromD);
+}
+
+void ASTImporter::RegisterImportedDecl(Decl *FromD, Decl *ToD) {
+ MapImported(FromD, ToD);
}
-QualType ASTImporter::Import(QualType FromT) {
+Expected<QualType> ASTImporter::Import(QualType FromT) {
if (FromT.isNull())
- return {};
+ return QualType{};
const Type *FromTy = FromT.getTypePtr();
@@ -7697,10 +7815,8 @@ QualType ASTImporter::Import(QualType FromT) {
// Import the type
ASTNodeImporter Importer(*this);
ExpectedType ToTOrErr = Importer.Visit(FromTy);
- if (!ToTOrErr) {
- llvm::consumeError(ToTOrErr.takeError());
- return {};
- }
+ if (!ToTOrErr)
+ return ToTOrErr.takeError();
// Record the imported type.
ImportedTypes[FromTy] = (*ToTOrErr).getTypePtr();
@@ -7708,33 +7824,29 @@ QualType ASTImporter::Import(QualType FromT) {
return ToContext.getQualifiedType(*ToTOrErr, FromT.getLocalQualifiers());
}
-Expected<TypeSourceInfo *> ASTImporter::Import_New(TypeSourceInfo *FromTSI) {
- TypeSourceInfo *ToTSI = Import(FromTSI);
- if (!ToTSI && FromTSI)
- return llvm::make_error<ImportError>();
- return ToTSI;
-}
-TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) {
+Expected<TypeSourceInfo *> ASTImporter::Import(TypeSourceInfo *FromTSI) {
if (!FromTSI)
return FromTSI;
// FIXME: For now we just create a "trivial" type source info based
// on the type and a single location. Implement a real version of this.
- QualType T = Import(FromTSI->getType());
- if (T.isNull())
- return nullptr;
+ ExpectedType TOrErr = Import(FromTSI->getType());
+ if (!TOrErr)
+ return TOrErr.takeError();
+ ExpectedSLoc BeginLocOrErr = Import(FromTSI->getTypeLoc().getBeginLoc());
+ if (!BeginLocOrErr)
+ return BeginLocOrErr.takeError();
- return ToContext.getTrivialTypeSourceInfo(
- T, Import(FromTSI->getTypeLoc().getBeginLoc()));
+ return ToContext.getTrivialTypeSourceInfo(*TOrErr, *BeginLocOrErr);
}
-Expected<Attr *> ASTImporter::Import_New(const Attr *FromAttr) {
- return Import(FromAttr);
-}
-Attr *ASTImporter::Import(const Attr *FromAttr) {
+Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) {
Attr *ToAttr = FromAttr->clone(ToContext);
- // NOTE: Import of SourceRange may fail.
- ToAttr->setRange(Import(FromAttr->getRange()));
+ if (auto ToRangeOrErr = Import(FromAttr->getRange()))
+ ToAttr->setRange(*ToRangeOrErr);
+ else
+ return ToRangeOrErr.takeError();
+
return ToAttr;
}
@@ -7746,53 +7858,147 @@ Decl *ASTImporter::GetAlreadyImportedOrNull(const Decl *FromD) const {
return nullptr;
}
-Expected<Decl *> ASTImporter::Import_New(Decl *FromD) {
- Decl *ToD = Import(FromD);
- if (!ToD && FromD)
- return llvm::make_error<ImportError>();
- return ToD;
+TranslationUnitDecl *ASTImporter::GetFromTU(Decl *ToD) {
+ auto FromDPos = ImportedFromDecls.find(ToD);
+ if (FromDPos == ImportedFromDecls.end())
+ return nullptr;
+ return FromDPos->second->getTranslationUnitDecl();
}
-Decl *ASTImporter::Import(Decl *FromD) {
+
+Expected<Decl *> ASTImporter::Import(Decl *FromD) {
if (!FromD)
return nullptr;
- ASTNodeImporter Importer(*this);
+ // Push FromD to the stack, and remove that when we return.
+ ImportPath.push(FromD);
+ auto ImportPathBuilder =
+ llvm::make_scope_exit([this]() { ImportPath.pop(); });
+
+ // Check whether there was a previous failed import.
+ // If yes return the existing error.
+ if (auto Error = getImportDeclErrorIfAny(FromD))
+ return make_error<ImportError>(*Error);
// Check whether we've already imported this declaration.
Decl *ToD = GetAlreadyImportedOrNull(FromD);
if (ToD) {
+ // Already imported (possibly from another TU) and with an error.
+ if (auto Error = SharedState->getImportDeclErrorIfAny(ToD)) {
+ setImportDeclError(FromD, *Error);
+ return make_error<ImportError>(*Error);
+ }
+
// If FromD has some updated flags after last import, apply it
updateFlags(FromD, ToD);
+ // If we encounter a cycle during an import then we save the relevant part
+ // of the import path associated to the Decl.
+ if (ImportPath.hasCycleAtBack())
+ SavedImportPaths[FromD].push_back(ImportPath.copyCycleAtBack());
return ToD;
}
- // Import the type.
- ExpectedDecl ToDOrErr = Importer.Visit(FromD);
+ // Import the declaration.
+ ExpectedDecl ToDOrErr = ImportImpl(FromD);
if (!ToDOrErr) {
- llvm::consumeError(ToDOrErr.takeError());
- return nullptr;
+ // Failed to import.
+
+ auto Pos = ImportedDecls.find(FromD);
+ if (Pos != ImportedDecls.end()) {
+ // Import failed after the object was created.
+ // Remove all references to it.
+ auto *ToD = Pos->second;
+ ImportedDecls.erase(Pos);
+
+ // ImportedDecls and ImportedFromDecls are not symmetric. It may happen
+ // (e.g. with namespaces) that several decls from the 'from' context are
+ // mapped to the same decl in the 'to' context. If we removed entries
+ // from the LookupTable here then we may end up removing them multiple
+ // times.
+
+ // The Lookuptable contains decls only which are in the 'to' context.
+ // Remove from the Lookuptable only if it is *imported* into the 'to'
+ // context (and do not remove it if it was added during the initial
+ // traverse of the 'to' context).
+ auto PosF = ImportedFromDecls.find(ToD);
+ if (PosF != ImportedFromDecls.end()) {
+ SharedState->removeDeclFromLookup(ToD);
+ ImportedFromDecls.erase(PosF);
+ }
+
+ // FIXME: AST may contain remaining references to the failed object.
+ // However, the ImportDeclErrors in the shared state contains all the
+ // failed objects together with their error.
+ }
+
+ // Error encountered for the first time.
+ // After takeError the error is not usable any more in ToDOrErr.
+ // Get a copy of the error object (any more simple solution for this?).
+ ImportError ErrOut;
+ handleAllErrors(ToDOrErr.takeError(),
+ [&ErrOut](const ImportError &E) { ErrOut = E; });
+ setImportDeclError(FromD, ErrOut);
+ // Set the error for the mapped to Decl, which is in the "to" context.
+ if (Pos != ImportedDecls.end())
+ SharedState->setImportDeclError(Pos->second, ErrOut);
+
+ // Set the error for all nodes which have been created before we
+ // recognized the error.
+ for (const auto &Path : SavedImportPaths[FromD])
+ for (Decl *FromDi : Path) {
+ setImportDeclError(FromDi, ErrOut);
+ //FIXME Should we remove these Decls from ImportedDecls?
+ // Set the error for the mapped to Decl, which is in the "to" context.
+ auto Ii = ImportedDecls.find(FromDi);
+ if (Ii != ImportedDecls.end())
+ SharedState->setImportDeclError(Ii->second, ErrOut);
+ // FIXME Should we remove these Decls from the LookupTable,
+ // and from ImportedFromDecls?
+ }
+ SavedImportPaths[FromD].clear();
+
+ // Do not return ToDOrErr, error was taken out of it.
+ return make_error<ImportError>(ErrOut);
}
+
ToD = *ToDOrErr;
- // Once the decl is connected to the existing declarations, i.e. when the
- // redecl chain is properly set then we populate the lookup again.
- // This way the primary context will be able to find all decls.
- AddToLookupTable(ToD);
+ // FIXME: Handle the "already imported with error" case. We can get here
+ // nullptr only if GetImportedOrCreateDecl returned nullptr (after a
+ // previously failed create was requested).
+ // Later GetImportedOrCreateDecl can be updated to return the error.
+ if (!ToD) {
+ auto Err = getImportDeclErrorIfAny(FromD);
+ assert(Err);
+ return make_error<ImportError>(*Err);
+ }
+
+ // We could import from the current TU without error. But previously we
+ // already had imported a Decl as `ToD` from another TU (with another
+ // ASTImporter object) and with an error.
+ if (auto Error = SharedState->getImportDeclErrorIfAny(ToD)) {
+ setImportDeclError(FromD, *Error);
+ return make_error<ImportError>(*Error);
+ }
+
+ // Make sure that ImportImpl registered the imported decl.
+ assert(ImportedDecls.count(FromD) != 0 && "Missing call to MapImported?");
// Notify subclasses.
Imported(FromD, ToD);
updateFlags(FromD, ToD);
- return ToD;
+ SavedImportPaths[FromD].clear();
+ return ToDOrErr;
}
Expected<DeclContext *> ASTImporter::ImportContext(DeclContext *FromDC) {
if (!FromDC)
return FromDC;
- auto *ToDC = cast_or_null<DeclContext>(Import(cast<Decl>(FromDC)));
- if (!ToDC)
- return nullptr;
+ ExpectedDecl ToDCOrErr = Import(cast<Decl>(FromDC));
+ if (!ToDCOrErr)
+ return ToDCOrErr.takeError();
+ auto *ToDC = cast<DeclContext>(*ToDCOrErr);
// When we're using a record/enum/Objective-C class/protocol as a context, we
// need it to have a definition.
@@ -7845,30 +8051,18 @@ Expected<DeclContext *> ASTImporter::ImportContext(DeclContext *FromDC) {
return ToDC;
}
-Expected<Expr *> ASTImporter::Import_New(Expr *FromE) {
- Expr *ToE = Import(FromE);
- if (!ToE && FromE)
- return llvm::make_error<ImportError>();
- return ToE;
-}
-Expr *ASTImporter::Import(Expr *FromE) {
- if (!FromE)
- return nullptr;
-
- return cast_or_null<Expr>(Import(cast<Stmt>(FromE)));
+Expected<Expr *> ASTImporter::Import(Expr *FromE) {
+ if (ExpectedStmt ToSOrErr = Import(cast_or_null<Stmt>(FromE)))
+ return cast_or_null<Expr>(*ToSOrErr);
+ else
+ return ToSOrErr.takeError();
}
-Expected<Stmt *> ASTImporter::Import_New(Stmt *FromS) {
- Stmt *ToS = Import(FromS);
- if (!ToS && FromS)
- return llvm::make_error<ImportError>();
- return ToS;
-}
-Stmt *ASTImporter::Import(Stmt *FromS) {
+Expected<Stmt *> ASTImporter::Import(Stmt *FromS) {
if (!FromS)
return nullptr;
- // Check whether we've already imported this declaration.
+ // Check whether we've already imported this statement.
llvm::DenseMap<Stmt *, Stmt *>::iterator Pos = ImportedStmts.find(FromS);
if (Pos != ImportedStmts.end())
return Pos->second;
@@ -7876,10 +8070,8 @@ Stmt *ASTImporter::Import(Stmt *FromS) {
// Import the statement.
ASTNodeImporter Importer(*this);
ExpectedStmt ToSOrErr = Importer.Visit(FromS);
- if (!ToSOrErr) {
- llvm::consumeError(ToSOrErr.takeError());
- return nullptr;
- }
+ if (!ToSOrErr)
+ return ToSOrErr;
if (auto *ToE = dyn_cast<Expr>(*ToSOrErr)) {
auto *FromE = cast<Expr>(FromS);
@@ -7894,77 +8086,68 @@ Stmt *ASTImporter::Import(Stmt *FromS) {
FromE->containsUnexpandedParameterPack());
}
- // Record the imported declaration.
+ // Record the imported statement object.
ImportedStmts[FromS] = *ToSOrErr;
- return *ToSOrErr;
+ return ToSOrErr;
}
Expected<NestedNameSpecifier *>
-ASTImporter::Import_New(NestedNameSpecifier *FromNNS) {
- NestedNameSpecifier *ToNNS = Import(FromNNS);
- if (!ToNNS && FromNNS)
- return llvm::make_error<ImportError>();
- return ToNNS;
-}
-NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
+ASTImporter::Import(NestedNameSpecifier *FromNNS) {
if (!FromNNS)
return nullptr;
- NestedNameSpecifier *prefix = Import(FromNNS->getPrefix());
+ NestedNameSpecifier *Prefix = nullptr;
+ if (Error Err = importInto(Prefix, FromNNS->getPrefix()))
+ return std::move(Err);
switch (FromNNS->getKind()) {
case NestedNameSpecifier::Identifier:
- if (IdentifierInfo *II = Import(FromNNS->getAsIdentifier())) {
- return NestedNameSpecifier::Create(ToContext, prefix, II);
- }
- return nullptr;
+ assert(FromNNS->getAsIdentifier() && "NNS should contain identifier.");
+ return NestedNameSpecifier::Create(ToContext, Prefix,
+ Import(FromNNS->getAsIdentifier()));
case NestedNameSpecifier::Namespace:
- if (auto *NS =
- cast_or_null<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) {
- return NestedNameSpecifier::Create(ToContext, prefix, NS);
- }
- return nullptr;
+ if (ExpectedDecl NSOrErr = Import(FromNNS->getAsNamespace())) {
+ return NestedNameSpecifier::Create(ToContext, Prefix,
+ cast<NamespaceDecl>(*NSOrErr));
+ } else
+ return NSOrErr.takeError();
case NestedNameSpecifier::NamespaceAlias:
- if (auto *NSAD =
- cast_or_null<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) {
- return NestedNameSpecifier::Create(ToContext, prefix, NSAD);
- }
- return nullptr;
+ if (ExpectedDecl NSADOrErr = Import(FromNNS->getAsNamespaceAlias()))
+ return NestedNameSpecifier::Create(ToContext, Prefix,
+ cast<NamespaceAliasDecl>(*NSADOrErr));
+ else
+ return NSADOrErr.takeError();
case NestedNameSpecifier::Global:
return NestedNameSpecifier::GlobalSpecifier(ToContext);
case NestedNameSpecifier::Super:
- if (auto *RD =
- cast_or_null<CXXRecordDecl>(Import(FromNNS->getAsRecordDecl()))) {
- return NestedNameSpecifier::SuperSpecifier(ToContext, RD);
- }
- return nullptr;
+ if (ExpectedDecl RDOrErr = Import(FromNNS->getAsRecordDecl()))
+ return NestedNameSpecifier::SuperSpecifier(ToContext,
+ cast<CXXRecordDecl>(*RDOrErr));
+ else
+ return RDOrErr.takeError();
case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate: {
- QualType T = Import(QualType(FromNNS->getAsType(), 0u));
- if (!T.isNull()) {
- bool bTemplate = FromNNS->getKind() ==
- NestedNameSpecifier::TypeSpecWithTemplate;
- return NestedNameSpecifier::Create(ToContext, prefix,
- bTemplate, T.getTypePtr());
- }
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ if (Expected<QualType> TyOrErr =
+ Import(QualType(FromNNS->getAsType(), 0u))) {
+ bool TSTemplate =
+ FromNNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate;
+ return NestedNameSpecifier::Create(ToContext, Prefix, TSTemplate,
+ TyOrErr->getTypePtr());
+ } else {
+ return TyOrErr.takeError();
}
- return nullptr;
}
llvm_unreachable("Invalid nested name specifier kind");
}
Expected<NestedNameSpecifierLoc>
-ASTImporter::Import_New(NestedNameSpecifierLoc FromNNS) {
- NestedNameSpecifierLoc ToNNS = Import(FromNNS);
- return ToNNS;
-}
-NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
+ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
// Copied from NestedNameSpecifier mostly.
SmallVector<NestedNameSpecifierLoc , 8> NestedNames;
NestedNameSpecifierLoc NNS = FromNNS;
@@ -7980,54 +8163,62 @@ NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
while (!NestedNames.empty()) {
NNS = NestedNames.pop_back_val();
- NestedNameSpecifier *Spec = Import(NNS.getNestedNameSpecifier());
- if (!Spec)
- return NestedNameSpecifierLoc();
+ NestedNameSpecifier *Spec = nullptr;
+ if (Error Err = importInto(Spec, NNS.getNestedNameSpecifier()))
+ return std::move(Err);
NestedNameSpecifier::SpecifierKind Kind = Spec->getKind();
+
+ SourceLocation ToLocalBeginLoc, ToLocalEndLoc;
+ if (Kind != NestedNameSpecifier::Super) {
+ if (Error Err = importInto(ToLocalBeginLoc, NNS.getLocalBeginLoc()))
+ return std::move(Err);
+
+ if (Kind != NestedNameSpecifier::Global)
+ if (Error Err = importInto(ToLocalEndLoc, NNS.getLocalEndLoc()))
+ return std::move(Err);
+ }
+
switch (Kind) {
case NestedNameSpecifier::Identifier:
- Builder.Extend(getToContext(),
- Spec->getAsIdentifier(),
- Import(NNS.getLocalBeginLoc()),
- Import(NNS.getLocalEndLoc()));
+ Builder.Extend(getToContext(), Spec->getAsIdentifier(), ToLocalBeginLoc,
+ ToLocalEndLoc);
break;
case NestedNameSpecifier::Namespace:
- Builder.Extend(getToContext(),
- Spec->getAsNamespace(),
- Import(NNS.getLocalBeginLoc()),
- Import(NNS.getLocalEndLoc()));
+ Builder.Extend(getToContext(), Spec->getAsNamespace(), ToLocalBeginLoc,
+ ToLocalEndLoc);
break;
case NestedNameSpecifier::NamespaceAlias:
- Builder.Extend(getToContext(),
- Spec->getAsNamespaceAlias(),
- Import(NNS.getLocalBeginLoc()),
- Import(NNS.getLocalEndLoc()));
+ Builder.Extend(getToContext(), Spec->getAsNamespaceAlias(),
+ ToLocalBeginLoc, ToLocalEndLoc);
break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
+ SourceLocation ToTLoc;
+ if (Error Err = importInto(ToTLoc, NNS.getTypeLoc().getBeginLoc()))
+ return std::move(Err);
TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo(
- QualType(Spec->getAsType(), 0));
- Builder.Extend(getToContext(),
- Import(NNS.getLocalBeginLoc()),
- TSI->getTypeLoc(),
- Import(NNS.getLocalEndLoc()));
+ QualType(Spec->getAsType(), 0), ToTLoc);
+ Builder.Extend(getToContext(), ToLocalBeginLoc, TSI->getTypeLoc(),
+ ToLocalEndLoc);
break;
}
case NestedNameSpecifier::Global:
- Builder.MakeGlobal(getToContext(), Import(NNS.getLocalBeginLoc()));
+ Builder.MakeGlobal(getToContext(), ToLocalBeginLoc);
break;
case NestedNameSpecifier::Super: {
- SourceRange ToRange = Import(NNS.getSourceRange());
- Builder.MakeSuper(getToContext(),
- Spec->getAsRecordDecl(),
- ToRange.getBegin(),
- ToRange.getEnd());
+ auto ToSourceRangeOrErr = Import(NNS.getSourceRange());
+ if (!ToSourceRangeOrErr)
+ return ToSourceRangeOrErr.takeError();
+
+ Builder.MakeSuper(getToContext(), Spec->getAsRecordDecl(),
+ ToSourceRangeOrErr->getBegin(),
+ ToSourceRangeOrErr->getEnd());
}
}
}
@@ -8035,137 +8226,126 @@ NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
return Builder.getWithLocInContext(getToContext());
}
-Expected<TemplateName> ASTImporter::Import_New(TemplateName From) {
- TemplateName To = Import(From);
- if (To.isNull() && !From.isNull())
- return llvm::make_error<ImportError>();
- return To;
-}
-TemplateName ASTImporter::Import(TemplateName From) {
+Expected<TemplateName> ASTImporter::Import(TemplateName From) {
switch (From.getKind()) {
case TemplateName::Template:
- if (auto *ToTemplate =
- cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl())))
- return TemplateName(ToTemplate);
-
- return {};
+ if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl()))
+ return TemplateName(cast<TemplateDecl>(*ToTemplateOrErr));
+ else
+ return ToTemplateOrErr.takeError();
case TemplateName::OverloadedTemplate: {
OverloadedTemplateStorage *FromStorage = From.getAsOverloadedTemplate();
UnresolvedSet<2> ToTemplates;
for (auto *I : *FromStorage) {
- if (auto *To = cast_or_null<NamedDecl>(Import(I)))
- ToTemplates.addDecl(To);
+ if (auto ToOrErr = Import(I))
+ ToTemplates.addDecl(cast<NamedDecl>(*ToOrErr));
else
- return {};
+ return ToOrErr.takeError();
}
return ToContext.getOverloadedTemplateName(ToTemplates.begin(),
ToTemplates.end());
}
+ case TemplateName::AssumedTemplate: {
+ AssumedTemplateStorage *FromStorage = From.getAsAssumedTemplateName();
+ auto DeclNameOrErr = Import(FromStorage->getDeclName());
+ if (!DeclNameOrErr)
+ return DeclNameOrErr.takeError();
+ return ToContext.getAssumedTemplateName(*DeclNameOrErr);
+ }
+
case TemplateName::QualifiedTemplate: {
QualifiedTemplateName *QTN = From.getAsQualifiedTemplateName();
- NestedNameSpecifier *Qualifier = Import(QTN->getQualifier());
- if (!Qualifier)
- return {};
-
- if (auto *ToTemplate =
- cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl())))
- return ToContext.getQualifiedTemplateName(Qualifier,
- QTN->hasTemplateKeyword(),
- ToTemplate);
-
- return {};
+ auto QualifierOrErr = Import(QTN->getQualifier());
+ if (!QualifierOrErr)
+ return QualifierOrErr.takeError();
+
+ if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl()))
+ return ToContext.getQualifiedTemplateName(
+ *QualifierOrErr, QTN->hasTemplateKeyword(),
+ cast<TemplateDecl>(*ToTemplateOrErr));
+ else
+ return ToTemplateOrErr.takeError();
}
case TemplateName::DependentTemplate: {
DependentTemplateName *DTN = From.getAsDependentTemplateName();
- NestedNameSpecifier *Qualifier = Import(DTN->getQualifier());
- if (!Qualifier)
- return {};
+ auto QualifierOrErr = Import(DTN->getQualifier());
+ if (!QualifierOrErr)
+ return QualifierOrErr.takeError();
if (DTN->isIdentifier()) {
- return ToContext.getDependentTemplateName(Qualifier,
+ return ToContext.getDependentTemplateName(*QualifierOrErr,
Import(DTN->getIdentifier()));
}
- return ToContext.getDependentTemplateName(Qualifier, DTN->getOperator());
+ return ToContext.getDependentTemplateName(*QualifierOrErr,
+ DTN->getOperator());
}
case TemplateName::SubstTemplateTemplateParm: {
- SubstTemplateTemplateParmStorage *subst
- = From.getAsSubstTemplateTemplateParm();
- auto *param =
- cast_or_null<TemplateTemplateParmDecl>(Import(subst->getParameter()));
- if (!param)
- return {};
+ SubstTemplateTemplateParmStorage *Subst =
+ From.getAsSubstTemplateTemplateParm();
+ ExpectedDecl ParamOrErr = Import(Subst->getParameter());
+ if (!ParamOrErr)
+ return ParamOrErr.takeError();
- TemplateName replacement = Import(subst->getReplacement());
- if (replacement.isNull())
- return {};
+ auto ReplacementOrErr = Import(Subst->getReplacement());
+ if (!ReplacementOrErr)
+ return ReplacementOrErr.takeError();
- return ToContext.getSubstTemplateTemplateParm(param, replacement);
+ return ToContext.getSubstTemplateTemplateParm(
+ cast<TemplateTemplateParmDecl>(*ParamOrErr), *ReplacementOrErr);
}
case TemplateName::SubstTemplateTemplateParmPack: {
SubstTemplateTemplateParmPackStorage *SubstPack
= From.getAsSubstTemplateTemplateParmPack();
- auto *Param =
- cast_or_null<TemplateTemplateParmDecl>(
- Import(SubstPack->getParameterPack()));
- if (!Param)
- return {};
+ ExpectedDecl ParamOrErr = Import(SubstPack->getParameterPack());
+ if (!ParamOrErr)
+ return ParamOrErr.takeError();
ASTNodeImporter Importer(*this);
- Expected<TemplateArgument> ArgPack
- = Importer.ImportTemplateArgument(SubstPack->getArgumentPack());
- if (!ArgPack) {
- llvm::consumeError(ArgPack.takeError());
- return {};
- }
+ auto ArgPackOrErr =
+ Importer.ImportTemplateArgument(SubstPack->getArgumentPack());
+ if (!ArgPackOrErr)
+ return ArgPackOrErr.takeError();
- return ToContext.getSubstTemplateTemplateParmPack(Param, *ArgPack);
+ return ToContext.getSubstTemplateTemplateParmPack(
+ cast<TemplateTemplateParmDecl>(*ParamOrErr), *ArgPackOrErr);
}
}
llvm_unreachable("Invalid template name kind");
}
-Expected<SourceLocation> ASTImporter::Import_New(SourceLocation FromLoc) {
- SourceLocation ToLoc = Import(FromLoc);
- if (ToLoc.isInvalid() && !FromLoc.isInvalid())
- return llvm::make_error<ImportError>();
- return ToLoc;
-}
-SourceLocation ASTImporter::Import(SourceLocation FromLoc) {
+Expected<SourceLocation> ASTImporter::Import(SourceLocation FromLoc) {
if (FromLoc.isInvalid())
- return {};
+ return SourceLocation{};
SourceManager &FromSM = FromContext.getSourceManager();
+ bool IsBuiltin = FromSM.isWrittenInBuiltinFile(FromLoc);
std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc);
- FileID ToFileID = Import(Decomposed.first);
- if (ToFileID.isInvalid())
- return {};
+ Expected<FileID> ToFileIDOrErr = Import(Decomposed.first, IsBuiltin);
+ if (!ToFileIDOrErr)
+ return ToFileIDOrErr.takeError();
SourceManager &ToSM = ToContext.getSourceManager();
- return ToSM.getComposedLoc(ToFileID, Decomposed.second);
+ return ToSM.getComposedLoc(*ToFileIDOrErr, Decomposed.second);
}
-Expected<SourceRange> ASTImporter::Import_New(SourceRange FromRange) {
- SourceRange ToRange = Import(FromRange);
- return ToRange;
-}
-SourceRange ASTImporter::Import(SourceRange FromRange) {
- return SourceRange(Import(FromRange.getBegin()), Import(FromRange.getEnd()));
-}
+Expected<SourceRange> ASTImporter::Import(SourceRange FromRange) {
+ SourceLocation ToBegin, ToEnd;
+ if (Error Err = importInto(ToBegin, FromRange.getBegin()))
+ return std::move(Err);
+ if (Error Err = importInto(ToEnd, FromRange.getEnd()))
+ return std::move(Err);
-Expected<FileID> ASTImporter::Import_New(FileID FromID) {
- FileID ToID = Import(FromID);
- if (ToID.isInvalid() && FromID.isValid())
- return llvm::make_error<ImportError>();
- return ToID;
+ return SourceRange(ToBegin, ToEnd);
}
-FileID ASTImporter::Import(FileID FromID) {
+
+Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
llvm::DenseMap<FileID, FileID>::iterator Pos = ImportedFileIDs.find(FromID);
if (Pos != ImportedFileIDs.end())
return Pos->second;
@@ -8178,38 +8358,58 @@ FileID ASTImporter::Import(FileID FromID) {
FileID ToID;
if (FromSLoc.isExpansion()) {
const SrcMgr::ExpansionInfo &FromEx = FromSLoc.getExpansion();
- SourceLocation ToSpLoc = Import(FromEx.getSpellingLoc());
- SourceLocation ToExLocS = Import(FromEx.getExpansionLocStart());
+ ExpectedSLoc ToSpLoc = Import(FromEx.getSpellingLoc());
+ if (!ToSpLoc)
+ return ToSpLoc.takeError();
+ ExpectedSLoc ToExLocS = Import(FromEx.getExpansionLocStart());
+ if (!ToExLocS)
+ return ToExLocS.takeError();
unsigned TokenLen = FromSM.getFileIDSize(FromID);
SourceLocation MLoc;
if (FromEx.isMacroArgExpansion()) {
- MLoc = ToSM.createMacroArgExpansionLoc(ToSpLoc, ToExLocS, TokenLen);
+ MLoc = ToSM.createMacroArgExpansionLoc(*ToSpLoc, *ToExLocS, TokenLen);
} else {
- SourceLocation ToExLocE = Import(FromEx.getExpansionLocEnd());
- MLoc = ToSM.createExpansionLoc(ToSpLoc, ToExLocS, ToExLocE, TokenLen,
- FromEx.isExpansionTokenRange());
+ if (ExpectedSLoc ToExLocE = Import(FromEx.getExpansionLocEnd()))
+ MLoc = ToSM.createExpansionLoc(*ToSpLoc, *ToExLocS, *ToExLocE, TokenLen,
+ FromEx.isExpansionTokenRange());
+ else
+ return ToExLocE.takeError();
}
ToID = ToSM.getFileID(MLoc);
} else {
- // Include location of this file.
- SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc());
-
const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache();
- if (Cache->OrigEntry && Cache->OrigEntry->getDir()) {
- // FIXME: We probably want to use getVirtualFile(), so we don't hit the
- // disk again
- // FIXME: We definitely want to re-use the existing MemoryBuffer, rather
- // than mmap the files several times.
- const FileEntry *Entry =
- ToFileManager.getFile(Cache->OrigEntry->getName());
- if (!Entry)
- return {};
- ToID = ToSM.createFileID(Entry, ToIncludeLoc,
- FromSLoc.getFile().getFileCharacteristic());
- } else {
+
+ if (!IsBuiltin) {
+ // Include location of this file.
+ ExpectedSLoc ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc());
+ if (!ToIncludeLoc)
+ return ToIncludeLoc.takeError();
+
+ if (Cache->OrigEntry && Cache->OrigEntry->getDir()) {
+ // FIXME: We probably want to use getVirtualFile(), so we don't hit the
+ // disk again
+ // FIXME: We definitely want to re-use the existing MemoryBuffer, rather
+ // than mmap the files several times.
+ const FileEntry *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,
+ FromSLoc.getFile().getFileCharacteristic());
+ }
+ }
+
+ if (ToID.isInvalid() || IsBuiltin) {
// FIXME: We want to re-use the existing MemoryBuffer!
- const llvm::MemoryBuffer *FromBuf =
- Cache->getBuffer(FromContext.getDiagnostics(), FromSM);
+ bool Invalid = true;
+ const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(
+ FromContext.getDiagnostics(), FromSM, SourceLocation{}, &Invalid);
+ if (!FromBuf || Invalid)
+ // FIXME: Use a new error kind?
+ return llvm::make_error<ImportError>(ImportError::Unknown);
+
std::unique_ptr<llvm::MemoryBuffer> ToBuf =
llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(),
FromBuf->getBufferIdentifier());
@@ -8218,186 +8418,187 @@ FileID ASTImporter::Import(FileID FromID) {
}
}
+ assert(ToID.isValid() && "Unexpected invalid fileID was created.");
+
ImportedFileIDs[FromID] = ToID;
return ToID;
}
-Expected<CXXCtorInitializer *>
-ASTImporter::Import_New(CXXCtorInitializer *From) {
- CXXCtorInitializer *To = Import(From);
- if (!To && From)
- return llvm::make_error<ImportError>();
- return To;
-}
-CXXCtorInitializer *ASTImporter::Import(CXXCtorInitializer *From) {
- Expr *ToExpr = Import(From->getInit());
- if (!ToExpr && From->getInit())
- return nullptr;
+Expected<CXXCtorInitializer *> ASTImporter::Import(CXXCtorInitializer *From) {
+ ExpectedExpr ToExprOrErr = Import(From->getInit());
+ if (!ToExprOrErr)
+ return ToExprOrErr.takeError();
+
+ auto LParenLocOrErr = Import(From->getLParenLoc());
+ if (!LParenLocOrErr)
+ return LParenLocOrErr.takeError();
+
+ auto RParenLocOrErr = Import(From->getRParenLoc());
+ if (!RParenLocOrErr)
+ return RParenLocOrErr.takeError();
if (From->isBaseInitializer()) {
- TypeSourceInfo *ToTInfo = Import(From->getTypeSourceInfo());
- if (!ToTInfo && From->getTypeSourceInfo())
- return nullptr;
+ auto ToTInfoOrErr = Import(From->getTypeSourceInfo());
+ if (!ToTInfoOrErr)
+ return ToTInfoOrErr.takeError();
+
+ SourceLocation EllipsisLoc;
+ if (From->isPackExpansion())
+ if (Error Err = importInto(EllipsisLoc, From->getEllipsisLoc()))
+ return std::move(Err);
return new (ToContext) CXXCtorInitializer(
- ToContext, ToTInfo, From->isBaseVirtual(), Import(From->getLParenLoc()),
- ToExpr, Import(From->getRParenLoc()),
- From->isPackExpansion() ? Import(From->getEllipsisLoc())
- : SourceLocation());
+ ToContext, *ToTInfoOrErr, From->isBaseVirtual(), *LParenLocOrErr,
+ *ToExprOrErr, *RParenLocOrErr, EllipsisLoc);
} else if (From->isMemberInitializer()) {
- auto *ToField = cast_or_null<FieldDecl>(Import(From->getMember()));
- if (!ToField && From->getMember())
- return nullptr;
+ ExpectedDecl ToFieldOrErr = Import(From->getMember());
+ if (!ToFieldOrErr)
+ return ToFieldOrErr.takeError();
+
+ auto MemberLocOrErr = Import(From->getMemberLocation());
+ if (!MemberLocOrErr)
+ return MemberLocOrErr.takeError();
return new (ToContext) CXXCtorInitializer(
- ToContext, ToField, Import(From->getMemberLocation()),
- Import(From->getLParenLoc()), ToExpr, Import(From->getRParenLoc()));
+ ToContext, cast_or_null<FieldDecl>(*ToFieldOrErr), *MemberLocOrErr,
+ *LParenLocOrErr, *ToExprOrErr, *RParenLocOrErr);
} else if (From->isIndirectMemberInitializer()) {
- auto *ToIField = cast_or_null<IndirectFieldDecl>(
- Import(From->getIndirectMember()));
- if (!ToIField && From->getIndirectMember())
- return nullptr;
+ ExpectedDecl ToIFieldOrErr = Import(From->getIndirectMember());
+ if (!ToIFieldOrErr)
+ return ToIFieldOrErr.takeError();
+
+ auto MemberLocOrErr = Import(From->getMemberLocation());
+ if (!MemberLocOrErr)
+ return MemberLocOrErr.takeError();
return new (ToContext) CXXCtorInitializer(
- ToContext, ToIField, Import(From->getMemberLocation()),
- Import(From->getLParenLoc()), ToExpr, Import(From->getRParenLoc()));
+ ToContext, cast_or_null<IndirectFieldDecl>(*ToIFieldOrErr),
+ *MemberLocOrErr, *LParenLocOrErr, *ToExprOrErr, *RParenLocOrErr);
} else if (From->isDelegatingInitializer()) {
- TypeSourceInfo *ToTInfo = Import(From->getTypeSourceInfo());
- if (!ToTInfo && From->getTypeSourceInfo())
- return nullptr;
+ auto ToTInfoOrErr = Import(From->getTypeSourceInfo());
+ if (!ToTInfoOrErr)
+ return ToTInfoOrErr.takeError();
return new (ToContext)
- CXXCtorInitializer(ToContext, ToTInfo, Import(From->getLParenLoc()),
- ToExpr, Import(From->getRParenLoc()));
+ CXXCtorInitializer(ToContext, *ToTInfoOrErr, *LParenLocOrErr,
+ *ToExprOrErr, *RParenLocOrErr);
} else {
- return nullptr;
+ // FIXME: assert?
+ return make_error<ImportError>();
}
}
Expected<CXXBaseSpecifier *>
-ASTImporter::Import_New(const CXXBaseSpecifier *From) {
- CXXBaseSpecifier *To = Import(From);
- if (!To && From)
- return llvm::make_error<ImportError>();
- return To;
-}
-CXXBaseSpecifier *ASTImporter::Import(const CXXBaseSpecifier *BaseSpec) {
+ASTImporter::Import(const CXXBaseSpecifier *BaseSpec) {
auto Pos = ImportedCXXBaseSpecifiers.find(BaseSpec);
if (Pos != ImportedCXXBaseSpecifiers.end())
return Pos->second;
+ Expected<SourceRange> ToSourceRange = Import(BaseSpec->getSourceRange());
+ if (!ToSourceRange)
+ return ToSourceRange.takeError();
+ Expected<TypeSourceInfo *> ToTSI = Import(BaseSpec->getTypeSourceInfo());
+ if (!ToTSI)
+ return ToTSI.takeError();
+ ExpectedSLoc ToEllipsisLoc = Import(BaseSpec->getEllipsisLoc());
+ if (!ToEllipsisLoc)
+ return ToEllipsisLoc.takeError();
CXXBaseSpecifier *Imported = new (ToContext) CXXBaseSpecifier(
- Import(BaseSpec->getSourceRange()),
- BaseSpec->isVirtual(), BaseSpec->isBaseOfClass(),
- BaseSpec->getAccessSpecifierAsWritten(),
- Import(BaseSpec->getTypeSourceInfo()),
- Import(BaseSpec->getEllipsisLoc()));
+ *ToSourceRange, BaseSpec->isVirtual(), BaseSpec->isBaseOfClass(),
+ BaseSpec->getAccessSpecifierAsWritten(), *ToTSI, *ToEllipsisLoc);
ImportedCXXBaseSpecifiers[BaseSpec] = Imported;
return Imported;
}
-Error ASTImporter::ImportDefinition_New(Decl *From) {
- Decl *To = Import(From);
- if (!To)
- return llvm::make_error<ImportError>();
+Error ASTImporter::ImportDefinition(Decl *From) {
+ ExpectedDecl ToOrErr = Import(From);
+ if (!ToOrErr)
+ return ToOrErr.takeError();
+ Decl *To = *ToOrErr;
- if (auto *FromDC = cast<DeclContext>(From)) {
- ASTNodeImporter Importer(*this);
+ auto *FromDC = cast<DeclContext>(From);
+ ASTNodeImporter Importer(*this);
- if (auto *ToRecord = dyn_cast<RecordDecl>(To)) {
- if (!ToRecord->getDefinition()) {
- return Importer.ImportDefinition(
- cast<RecordDecl>(FromDC), ToRecord,
- ASTNodeImporter::IDK_Everything);
- }
+ if (auto *ToRecord = dyn_cast<RecordDecl>(To)) {
+ if (!ToRecord->getDefinition()) {
+ return Importer.ImportDefinition(
+ cast<RecordDecl>(FromDC), ToRecord,
+ ASTNodeImporter::IDK_Everything);
}
+ }
- if (auto *ToEnum = dyn_cast<EnumDecl>(To)) {
- if (!ToEnum->getDefinition()) {
- return Importer.ImportDefinition(
- cast<EnumDecl>(FromDC), ToEnum, ASTNodeImporter::IDK_Everything);
- }
+ if (auto *ToEnum = dyn_cast<EnumDecl>(To)) {
+ if (!ToEnum->getDefinition()) {
+ return Importer.ImportDefinition(
+ cast<EnumDecl>(FromDC), ToEnum, ASTNodeImporter::IDK_Everything);
}
+ }
- if (auto *ToIFace = dyn_cast<ObjCInterfaceDecl>(To)) {
- if (!ToIFace->getDefinition()) {
- return Importer.ImportDefinition(
- cast<ObjCInterfaceDecl>(FromDC), ToIFace,
- ASTNodeImporter::IDK_Everything);
- }
+ if (auto *ToIFace = dyn_cast<ObjCInterfaceDecl>(To)) {
+ if (!ToIFace->getDefinition()) {
+ return Importer.ImportDefinition(
+ cast<ObjCInterfaceDecl>(FromDC), ToIFace,
+ ASTNodeImporter::IDK_Everything);
}
+ }
- if (auto *ToProto = dyn_cast<ObjCProtocolDecl>(To)) {
- if (!ToProto->getDefinition()) {
- return Importer.ImportDefinition(
- cast<ObjCProtocolDecl>(FromDC), ToProto,
- ASTNodeImporter::IDK_Everything);
- }
+ if (auto *ToProto = dyn_cast<ObjCProtocolDecl>(To)) {
+ if (!ToProto->getDefinition()) {
+ return Importer.ImportDefinition(
+ cast<ObjCProtocolDecl>(FromDC), ToProto,
+ ASTNodeImporter::IDK_Everything);
}
-
- return Importer.ImportDeclContext(FromDC, true);
}
- return Error::success();
+ return Importer.ImportDeclContext(FromDC, true);
}
-void ASTImporter::ImportDefinition(Decl *From) {
- Error Err = ImportDefinition_New(From);
- llvm::consumeError(std::move(Err));
-}
-
-Expected<DeclarationName> ASTImporter::Import_New(DeclarationName FromName) {
- DeclarationName ToName = Import(FromName);
- if (!ToName && FromName)
- return llvm::make_error<ImportError>();
- return ToName;
-}
-DeclarationName ASTImporter::Import(DeclarationName FromName) {
+Expected<DeclarationName> ASTImporter::Import(DeclarationName FromName) {
if (!FromName)
- return {};
+ return DeclarationName{};
switch (FromName.getNameKind()) {
case DeclarationName::Identifier:
- return Import(FromName.getAsIdentifierInfo());
+ return DeclarationName(Import(FromName.getAsIdentifierInfo()));
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
- return Import(FromName.getObjCSelector());
+ if (auto ToSelOrErr = Import(FromName.getObjCSelector()))
+ return DeclarationName(*ToSelOrErr);
+ else
+ return ToSelOrErr.takeError();
case DeclarationName::CXXConstructorName: {
- QualType T = Import(FromName.getCXXNameType());
- if (T.isNull())
- return {};
-
- return ToContext.DeclarationNames.getCXXConstructorName(
- ToContext.getCanonicalType(T));
+ if (auto ToTyOrErr = Import(FromName.getCXXNameType()))
+ return ToContext.DeclarationNames.getCXXConstructorName(
+ ToContext.getCanonicalType(*ToTyOrErr));
+ else
+ return ToTyOrErr.takeError();
}
case DeclarationName::CXXDestructorName: {
- QualType T = Import(FromName.getCXXNameType());
- if (T.isNull())
- return {};
-
- return ToContext.DeclarationNames.getCXXDestructorName(
- ToContext.getCanonicalType(T));
+ if (auto ToTyOrErr = Import(FromName.getCXXNameType()))
+ return ToContext.DeclarationNames.getCXXDestructorName(
+ ToContext.getCanonicalType(*ToTyOrErr));
+ else
+ return ToTyOrErr.takeError();
}
case DeclarationName::CXXDeductionGuideName: {
- auto *Template = cast_or_null<TemplateDecl>(
- Import(FromName.getCXXDeductionGuideTemplate()));
- if (!Template)
- return {};
- return ToContext.DeclarationNames.getCXXDeductionGuideName(Template);
+ if (auto ToTemplateOrErr = Import(FromName.getCXXDeductionGuideTemplate()))
+ return ToContext.DeclarationNames.getCXXDeductionGuideName(
+ cast<TemplateDecl>(*ToTemplateOrErr));
+ else
+ return ToTemplateOrErr.takeError();
}
case DeclarationName::CXXConversionFunctionName: {
- QualType T = Import(FromName.getCXXNameType());
- if (T.isNull())
- return {};
-
- return ToContext.DeclarationNames.getCXXConversionFunctionName(
- ToContext.getCanonicalType(T));
+ if (auto ToTyOrErr = Import(FromName.getCXXNameType()))
+ return ToContext.DeclarationNames.getCXXConversionFunctionName(
+ ToContext.getCanonicalType(*ToTyOrErr));
+ else
+ return ToTyOrErr.takeError();
}
case DeclarationName::CXXOperatorName:
@@ -8406,7 +8607,7 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) {
case DeclarationName::CXXLiteralOperatorName:
return ToContext.DeclarationNames.getCXXLiteralOperatorName(
- Import(FromName.getCXXLiteralIdentifier()));
+ Import(FromName.getCXXLiteralIdentifier()));
case DeclarationName::CXXUsingDirective:
// FIXME: STATICS!
@@ -8428,15 +8629,9 @@ IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) {
return ToId;
}
-Expected<Selector> ASTImporter::Import_New(Selector FromSel) {
- Selector ToSel = Import(FromSel);
- if (ToSel.isNull() && !FromSel.isNull())
- return llvm::make_error<ImportError>();
- return ToSel;
-}
-Selector ASTImporter::Import(Selector FromSel) {
+Expected<Selector> ASTImporter::Import(Selector FromSel) {
if (FromSel.isNull())
- return {};
+ return Selector{};
SmallVector<IdentifierInfo *, 4> Idents;
Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0)));
@@ -8496,15 +8691,42 @@ Decl *ASTImporter::MapImported(Decl *From, Decl *To) {
if (Pos != ImportedDecls.end())
return Pos->second;
ImportedDecls[From] = To;
+ // This mapping should be maintained only in this function. Therefore do not
+ // check for additional consistency.
+ ImportedFromDecls[To] = From;
+ AddToLookupTable(To);
return To;
}
+llvm::Optional<ImportError>
+ASTImporter::getImportDeclErrorIfAny(Decl *FromD) const {
+ auto Pos = ImportDeclErrors.find(FromD);
+ if (Pos != ImportDeclErrors.end())
+ return Pos->second;
+ else
+ return Optional<ImportError>();
+}
+
+void ASTImporter::setImportDeclError(Decl *From, ImportError Error) {
+ auto InsertRes = ImportDeclErrors.insert({From, Error});
+ (void)InsertRes;
+ // Either we set the error for the first time, or we already had set one and
+ // now we want to set the same error.
+ assert(InsertRes.second || InsertRes.first->second.Error == Error.Error);
+}
+
bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To,
bool Complain) {
- llvm::DenseMap<const Type *, const Type *>::iterator Pos
- = ImportedTypes.find(From.getTypePtr());
- if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To))
- return true;
+ llvm::DenseMap<const Type *, const Type *>::iterator Pos =
+ ImportedTypes.find(From.getTypePtr());
+ if (Pos != ImportedTypes.end()) {
+ if (ExpectedType ToFromOrErr = Import(From)) {
+ if (ToContext.hasSameType(*ToFromOrErr, To))
+ return true;
+ } else {
+ llvm::consumeError(ToFromOrErr.takeError());
+ }
+ }
StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls,
getStructuralEquivalenceKind(*this), false,
diff --git a/lib/AST/ASTImporterLookupTable.cpp b/lib/AST/ASTImporterLookupTable.cpp
index fbcd4f5cb3417..7390329d4ed8d 100644
--- a/lib/AST/ASTImporterLookupTable.cpp
+++ b/lib/AST/ASTImporterLookupTable.cpp
@@ -1,9 +1,8 @@
//===- ASTImporterLookupTable.cpp - ASTImporter specific lookup -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -27,17 +26,30 @@ struct Builder : RecursiveASTVisitor<Builder> {
LT.add(D);
return true;
}
+ // In most cases the FriendDecl contains the declaration of the befriended
+ // class as a child node, so it is discovered during the recursive
+ // visitation. However, there are cases when the befriended class is not a
+ // child, thus it must be fetched explicitly from the FriendDecl, and only
+ // then can we add it to the lookup table.
bool VisitFriendDecl(FriendDecl *D) {
if (D->getFriendType()) {
QualType Ty = D->getFriendType()->getType();
- // FIXME Can this be other than elaborated?
- QualType NamedTy = cast<ElaboratedType>(Ty)->getNamedType();
- if (!NamedTy->isDependentType()) {
- if (const auto *RTy = dyn_cast<RecordType>(NamedTy))
+ if (isa<ElaboratedType>(Ty))
+ Ty = cast<ElaboratedType>(Ty)->getNamedType();
+ // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization)
+ // always has that decl as child node.
+ // However, there are non-dependent cases which does not have the
+ // type as a child node. We have to dig up that type now.
+ if (!Ty->isDependentType()) {
+ if (const auto *RTy = dyn_cast<RecordType>(Ty))
LT.add(RTy->getAsCXXRecordDecl());
- else if (const auto *SpecTy =
- dyn_cast<TemplateSpecializationType>(NamedTy)) {
+ else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty))
LT.add(SpecTy->getAsCXXRecordDecl());
+ else if (isa<TypedefType>(Ty)) {
+ // We do not put friend typedefs to the lookup table because
+ // ASTImporter does not organize typedefs into redecl chains.
+ } else {
+ llvm_unreachable("Unhandled type of friend class");
}
}
}
diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp
index d19b89bb95b48..912db3c130c51 100644
--- a/lib/AST/ASTStructuralEquivalence.cpp
+++ b/lib/AST/ASTStructuralEquivalence.cpp
@@ -1,9 +1,8 @@
//===- ASTStructuralEquivalence.cpp ---------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -74,6 +73,7 @@
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
@@ -101,6 +101,59 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const TemplateArgument &Arg1,
const TemplateArgument &Arg2);
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ NestedNameSpecifier *NNS1,
+ NestedNameSpecifier *NNS2);
+static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
+ const IdentifierInfo *Name2);
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const DeclarationName Name1,
+ const DeclarationName Name2) {
+ if (Name1.getNameKind() != Name2.getNameKind())
+ return false;
+
+ switch (Name1.getNameKind()) {
+
+ case DeclarationName::Identifier:
+ return IsStructurallyEquivalent(Name1.getAsIdentifierInfo(),
+ Name2.getAsIdentifierInfo());
+
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ return IsStructurallyEquivalent(Context, Name1.getCXXNameType(),
+ Name2.getCXXNameType());
+
+ case DeclarationName::CXXDeductionGuideName: {
+ if (!IsStructurallyEquivalent(
+ Context, Name1.getCXXDeductionGuideTemplate()->getDeclName(),
+ Name2.getCXXDeductionGuideTemplate()->getDeclName()))
+ return false;
+ return IsStructurallyEquivalent(Context,
+ Name1.getCXXDeductionGuideTemplate(),
+ Name2.getCXXDeductionGuideTemplate());
+ }
+
+ case DeclarationName::CXXOperatorName:
+ return Name1.getCXXOverloadedOperator() == Name2.getCXXOverloadedOperator();
+
+ case DeclarationName::CXXLiteralOperatorName:
+ return IsStructurallyEquivalent(Name1.getCXXLiteralIdentifier(),
+ Name2.getCXXLiteralIdentifier());
+
+ case DeclarationName::CXXUsingDirective:
+ return true; // FIXME When do we consider two using directives equal?
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return true; // FIXME
+ }
+
+ llvm_unreachable("Unhandled kind of DeclarationName");
+ return true;
+}
/// Determine structural equivalence of two expressions.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
@@ -108,7 +161,26 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!E1 || !E2)
return E1 == E2;
- // FIXME: Actually perform a structural comparison!
+ if (auto *DE1 = dyn_cast<DependentScopeDeclRefExpr>(E1)) {
+ auto *DE2 = dyn_cast<DependentScopeDeclRefExpr>(E2);
+ if (!DE2)
+ return false;
+ if (!IsStructurallyEquivalent(Context, DE1->getDeclName(),
+ DE2->getDeclName()))
+ return false;
+ return IsStructurallyEquivalent(Context, DE1->getQualifier(),
+ DE2->getQualifier());
+ } else if (auto CastE1 = dyn_cast<ImplicitCastExpr>(E1)) {
+ auto *CastE2 = dyn_cast<ImplicitCastExpr>(E2);
+ if (!CastE2)
+ return false;
+ if (!IsStructurallyEquivalent(Context, CastE1->getType(),
+ CastE2->getType()))
+ return false;
+ return IsStructurallyEquivalent(Context, CastE1->getSubExpr(),
+ CastE2->getSubExpr());
+ }
+ // FIXME: Handle other kind of expressions!
return true;
}
@@ -181,6 +253,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return I1 == E1 && I2 == E2;
}
+ case TemplateName::AssumedTemplate: {
+ AssumedTemplateStorage *TN1 = N1.getAsAssumedTemplateName(),
+ *TN2 = N1.getAsAssumedTemplateName();
+ return TN1->getDeclName() == TN2->getDeclName();
+ }
+
case TemplateName::QualifiedTemplate: {
QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(),
*QN2 = N2.getAsQualifiedTemplateName();
@@ -297,6 +375,62 @@ static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
return true;
}
+/// Determine structural equivalence based on the ExtInfo of functions. This
+/// is inspired by ASTContext::mergeFunctionTypes(), we compare calling
+/// conventions bits but must not compare some other bits.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ FunctionType::ExtInfo EI1,
+ FunctionType::ExtInfo EI2) {
+ // Compatible functions must have compatible calling conventions.
+ if (EI1.getCC() != EI2.getCC())
+ return false;
+
+ // Regparm is part of the calling convention.
+ if (EI1.getHasRegParm() != EI2.getHasRegParm())
+ return false;
+ if (EI1.getRegParm() != EI2.getRegParm())
+ return false;
+
+ if (EI1.getProducesResult() != EI2.getProducesResult())
+ return false;
+ if (EI1.getNoCallerSavedRegs() != EI2.getNoCallerSavedRegs())
+ return false;
+ if (EI1.getNoCfCheck() != EI2.getNoCfCheck())
+ return false;
+
+ return true;
+}
+
+/// Check the equivalence of exception specifications.
+static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context,
+ const FunctionProtoType *Proto1,
+ const FunctionProtoType *Proto2) {
+
+ auto Spec1 = Proto1->getExceptionSpecType();
+ auto Spec2 = Proto2->getExceptionSpecType();
+
+ if (isUnresolvedExceptionSpec(Spec1) || isUnresolvedExceptionSpec(Spec2))
+ return true;
+
+ if (Spec1 != Spec2)
+ return false;
+ if (Spec1 == EST_Dynamic) {
+ if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
+ return false;
+ for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I),
+ Proto2->getExceptionType(I)))
+ return false;
+ }
+ } else if (isComputedNoexcept(Spec1)) {
+ if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(),
+ Proto2->getNoexceptExpr()))
+ return false;
+ }
+
+ return true;
+}
+
/// Determine structural equivalence of two types.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
QualType T1, QualType T2) {
@@ -503,7 +637,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Proto1->isVariadic() != Proto2->isVariadic())
return false;
- if (Proto1->getTypeQuals() != Proto2->getTypeQuals())
+ if (Proto1->getMethodQuals() != Proto2->getMethodQuals())
return false;
// Check exceptions, this information is lost in canonical type.
@@ -511,24 +645,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx));
const auto *OrigProto2 =
cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx));
- auto Spec1 = OrigProto1->getExceptionSpecType();
- auto Spec2 = OrigProto2->getExceptionSpecType();
-
- if (Spec1 != Spec2)
+ if (!IsEquivalentExceptionSpec(Context, OrigProto1, OrigProto2))
return false;
- if (Spec1 == EST_Dynamic) {
- if (OrigProto1->getNumExceptions() != OrigProto2->getNumExceptions())
- return false;
- for (unsigned I = 0, N = OrigProto1->getNumExceptions(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, OrigProto1->getExceptionType(I),
- OrigProto2->getExceptionType(I)))
- return false;
- }
- } else if (isComputedNoexcept(Spec1)) {
- if (!IsStructurallyEquivalent(Context, OrigProto1->getNoexceptExpr(),
- OrigProto2->getNoexceptExpr()))
- return false;
- }
// Fall through to check the bits common with FunctionNoProtoType.
LLVM_FALLTHROUGH;
@@ -540,7 +658,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, Function1->getReturnType(),
Function2->getReturnType()))
return false;
- if (Function1->getExtInfo() != Function2->getExtInfo())
+ if (!IsStructurallyEquivalent(Context, Function1->getExtInfo(),
+ Function2->getExtInfo()))
return false;
break;
}
@@ -569,6 +688,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
+ case Type::MacroQualified:
+ if (!IsStructurallyEquivalent(
+ Context, cast<MacroQualifiedType>(T1)->getUnderlyingType(),
+ cast<MacroQualifiedType>(T2)->getUnderlyingType()))
+ return false;
+ break;
+
case Type::Typedef:
if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
cast<TypedefType>(T2)->getDecl()))
@@ -834,10 +960,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
IdentifierInfo *Name2 = Field2->getIdentifier();
if (!::IsStructurallyEquivalent(Name1, Name2)) {
if (Context.Complain) {
- Context.Diag2(Owner2->getLocation(),
- Context.ErrorOnTagTypeMismatch
- ? diag::err_odr_tag_type_inconsistent
- : diag::warn_odr_tag_type_inconsistent)
+ Context.Diag2(
+ Owner2->getLocation(),
+ Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(Owner2);
Context.Diag2(Field2->getLocation(), diag::note_odr_field_name)
<< Field2->getDeclName();
@@ -850,10 +975,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, Field1->getType(),
Field2->getType())) {
if (Context.Complain) {
- Context.Diag2(Owner2->getLocation(),
- Context.ErrorOnTagTypeMismatch
- ? diag::err_odr_tag_type_inconsistent
- : diag::warn_odr_tag_type_inconsistent)
+ Context.Diag2(
+ Owner2->getLocation(),
+ Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(Owner2);
Context.Diag2(Field2->getLocation(), diag::note_odr_field)
<< Field2->getDeclName() << Field2->getType();
@@ -865,10 +989,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Field1->isBitField() != Field2->isBitField()) {
if (Context.Complain) {
- Context.Diag2(Owner2->getLocation(),
- Context.ErrorOnTagTypeMismatch
- ? diag::err_odr_tag_type_inconsistent
- : diag::warn_odr_tag_type_inconsistent)
+ Context.Diag2(
+ Owner2->getLocation(),
+ Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(Owner2);
if (Field1->isBitField()) {
Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
@@ -895,9 +1018,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Bits1 != Bits2) {
if (Context.Complain) {
Context.Diag2(Owner2->getLocation(),
- Context.ErrorOnTagTypeMismatch
- ? diag::err_odr_tag_type_inconsistent
- : diag::warn_odr_tag_type_inconsistent)
+ Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(Owner2);
Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
<< Field2->getDeclName() << Field2->getType() << Bits2;
@@ -933,13 +1055,15 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {
auto *Constructor2 = cast<CXXConstructorDecl>(Method2);
- if (Constructor1->isExplicit() != Constructor2->isExplicit())
+ if (!Constructor1->getExplicitSpecifier().isEquivalent(
+ Constructor2->getExplicitSpecifier()))
return false;
}
if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {
auto *Conversion2 = cast<CXXConversionDecl>(Method2);
- if (Conversion1->isExplicit() != Conversion2->isExplicit())
+ if (!Conversion1->getExplicitSpecifier().isEquivalent(
+ Conversion2->getExplicitSpecifier()))
return false;
if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),
Conversion2->getConversionType()))
@@ -961,15 +1085,26 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return true;
}
+/// Determine structural equivalence of two lambda classes.
+static bool
+IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context,
+ CXXRecordDecl *D1, CXXRecordDecl *D2) {
+ assert(D1->isLambda() && D2->isLambda() &&
+ "Must be called on lambda classes");
+ if (!IsStructurallyEquivalent(Context, D1->getLambdaCallOperator(),
+ D2->getLambdaCallOperator()))
+ return false;
+
+ return true;
+}
+
/// Determine structural equivalence of two records.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
RecordDecl *D1, RecordDecl *D2) {
if (D1->isUnion() != D2->isUnion()) {
if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.ErrorOnTagTypeMismatch
- ? diag::err_odr_tag_type_inconsistent
- : diag::warn_odr_tag_type_inconsistent)
+ Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(D2);
Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
<< D1->getDeclName() << (unsigned)D1->getTagKind();
@@ -1044,9 +1179,18 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX);
}
+ if (D1CXX->isLambda() != D2CXX->isLambda())
+ return false;
+ if (D1CXX->isLambda()) {
+ if (!IsStructurallyEquivalentLambdas(Context, D1CXX, D2CXX))
+ return false;
+ }
+
if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ Context.Diag2(D2->getLocation(),
+ Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(D2);
Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
<< D2CXX->getNumBases();
@@ -1065,7 +1209,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Base2->getType())) {
if (Context.Complain) {
Context.Diag2(D2->getLocation(),
- diag::warn_odr_tag_type_inconsistent)
+ Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(D2);
Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base)
<< Base2->getType() << Base2->getSourceRange();
@@ -1079,7 +1224,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Base1->isVirtual() != Base2->isVirtual()) {
if (Context.Complain) {
Context.Diag2(D2->getLocation(),
- diag::warn_odr_tag_type_inconsistent)
+ Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(D2);
Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base)
<< Base2->isVirtual() << Base2->getSourceRange();
@@ -1092,15 +1238,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
// Check the friends for consistency.
CXXRecordDecl::friend_iterator Friend2 = D2CXX->friend_begin(),
- Friend2End = D2CXX->friend_end();
+ Friend2End = D2CXX->friend_end();
for (CXXRecordDecl::friend_iterator Friend1 = D1CXX->friend_begin(),
- Friend1End = D1CXX->friend_end();
+ Friend1End = D1CXX->friend_end();
Friend1 != Friend1End; ++Friend1, ++Friend2) {
if (Friend2 == Friend2End) {
if (Context.Complain) {
Context.Diag2(D2->getLocation(),
- diag::warn_odr_tag_type_inconsistent)
- << Context.ToCtx.getTypeDeclType(D2CXX);
+ Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
+ << Context.ToCtx.getTypeDeclType(D2CXX);
Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend);
}
@@ -1109,8 +1256,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, *Friend1, *Friend2)) {
if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.ToCtx.getTypeDeclType(D2CXX);
+ Context.Diag2(D2->getLocation(),
+ Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
+ << Context.ToCtx.getTypeDeclType(D2CXX);
Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
}
@@ -1120,8 +1269,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Friend2 != Friend2End) {
if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(D2->getLocation(),
+ Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
+ << Context.ToCtx.getTypeDeclType(D2);
Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend);
}
@@ -1129,7 +1280,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
}
} else if (D1CXX->getNumBases() > 0) {
if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ Context.Diag2(D2->getLocation(),
+ Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(D2);
const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
@@ -1149,9 +1302,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Field2 == Field2End) {
if (Context.Complain) {
Context.Diag2(D2->getLocation(),
- Context.ErrorOnTagTypeMismatch
- ? diag::err_odr_tag_type_inconsistent
- : diag::warn_odr_tag_type_inconsistent)
+ Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(D2);
Context.Diag1(Field1->getLocation(), diag::note_odr_field)
<< Field1->getDeclName() << Field1->getType();
@@ -1166,10 +1318,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Field2 != Field2End) {
if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.ErrorOnTagTypeMismatch
- ? diag::err_odr_tag_type_inconsistent
- : diag::warn_odr_tag_type_inconsistent)
+ Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(D2);
Context.Diag2(Field2->getLocation(), diag::note_odr_field)
<< Field2->getDeclName() << Field2->getType();
@@ -1200,9 +1350,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (EC2 == EC2End) {
if (Context.Complain) {
Context.Diag2(D2->getLocation(),
- Context.ErrorOnTagTypeMismatch
- ? diag::err_odr_tag_type_inconsistent
- : diag::warn_odr_tag_type_inconsistent)
+ Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(D2);
Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
<< EC1->getDeclName() << EC1->getInitVal().toString(10);
@@ -1217,9 +1366,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
!IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {
if (Context.Complain) {
Context.Diag2(D2->getLocation(),
- Context.ErrorOnTagTypeMismatch
- ? diag::err_odr_tag_type_inconsistent
- : diag::warn_odr_tag_type_inconsistent)
+ Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(D2);
Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
<< EC2->getDeclName() << EC2->getInitVal().toString(10);
@@ -1232,10 +1380,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (EC2 != EC2End) {
if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- Context.ErrorOnTagTypeMismatch
- ? diag::err_odr_tag_type_inconsistent
- : diag::warn_odr_tag_type_inconsistent)
+ Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
+ diag::err_odr_tag_type_inconsistent))
<< Context.ToCtx.getTypeDeclType(D2);
Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
<< EC2->getDeclName() << EC2->getInitVal().toString(10);
@@ -1253,7 +1399,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Params1->size() != Params2->size()) {
if (Context.Complain) {
Context.Diag2(Params2->getTemplateLoc(),
- diag::err_odr_different_num_template_parameters)
+ Context.getApplicableDiagnostic(
+ diag::err_odr_different_num_template_parameters))
<< Params1->size() << Params2->size();
Context.Diag1(Params1->getTemplateLoc(),
diag::note_odr_template_parameter_list);
@@ -1265,7 +1412,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
if (Context.Complain) {
Context.Diag2(Params2->getParam(I)->getLocation(),
- diag::err_odr_different_template_parameter_kind);
+ Context.getApplicableDiagnostic(
+ diag::err_odr_different_template_parameter_kind));
Context.Diag1(Params1->getParam(I)->getLocation(),
diag::note_odr_template_parameter_here);
}
@@ -1285,7 +1433,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
TemplateTypeParmDecl *D2) {
if (D1->isParameterPack() != D2->isParameterPack()) {
if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ Context.Diag2(D2->getLocation(),
+ Context.getApplicableDiagnostic(
+ diag::err_odr_parameter_pack_non_pack))
<< D2->isParameterPack();
Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
<< D1->isParameterPack();
@@ -1301,7 +1451,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
NonTypeTemplateParmDecl *D2) {
if (D1->isParameterPack() != D2->isParameterPack()) {
if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ Context.Diag2(D2->getLocation(),
+ Context.getApplicableDiagnostic(
+ diag::err_odr_parameter_pack_non_pack))
<< D2->isParameterPack();
Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
<< D1->isParameterPack();
@@ -1313,7 +1465,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType())) {
if (Context.Complain) {
Context.Diag2(D2->getLocation(),
- diag::err_odr_non_type_parameter_type_inconsistent)
+ Context.getApplicableDiagnostic(
+ diag::err_odr_non_type_parameter_type_inconsistent))
<< D2->getType() << D1->getType();
Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
<< D1->getType();
@@ -1329,7 +1482,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
TemplateTemplateParmDecl *D2) {
if (D1->isParameterPack() != D2->isParameterPack()) {
if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ Context.Diag2(D2->getLocation(),
+ Context.getApplicableDiagnostic(
+ diag::err_odr_parameter_pack_non_pack))
<< D2->isParameterPack();
Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
<< D1->isParameterPack();
@@ -1378,6 +1533,18 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
}
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ ConceptDecl *D1,
+ ConceptDecl *D2) {
+ // Check template parameters.
+ if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
+ return false;
+
+ // Check the constraint expression.
+ return IsStructurallyEquivalent(Context, D1->getConstraintExpr(),
+ D2->getConstraintExpr());
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
FriendDecl *D1, FriendDecl *D2) {
if ((D1->getFriendType() && D2->getFriendDecl()) ||
(D1->getFriendDecl() && D2->getFriendType())) {
@@ -1485,6 +1652,52 @@ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
return Index;
}
+unsigned StructuralEquivalenceContext::getApplicableDiagnostic(
+ unsigned ErrorDiagnostic) {
+ if (ErrorOnTagTypeMismatch)
+ return ErrorDiagnostic;
+
+ switch (ErrorDiagnostic) {
+ case diag::err_odr_variable_type_inconsistent:
+ return diag::warn_odr_variable_type_inconsistent;
+ case diag::err_odr_variable_multiple_def:
+ return diag::warn_odr_variable_multiple_def;
+ case diag::err_odr_function_type_inconsistent:
+ return diag::warn_odr_function_type_inconsistent;
+ case diag::err_odr_tag_type_inconsistent:
+ return diag::warn_odr_tag_type_inconsistent;
+ case diag::err_odr_field_type_inconsistent:
+ return diag::warn_odr_field_type_inconsistent;
+ case diag::err_odr_ivar_type_inconsistent:
+ return diag::warn_odr_ivar_type_inconsistent;
+ case diag::err_odr_objc_superclass_inconsistent:
+ return diag::warn_odr_objc_superclass_inconsistent;
+ case diag::err_odr_objc_method_result_type_inconsistent:
+ return diag::warn_odr_objc_method_result_type_inconsistent;
+ case diag::err_odr_objc_method_num_params_inconsistent:
+ return diag::warn_odr_objc_method_num_params_inconsistent;
+ case diag::err_odr_objc_method_param_type_inconsistent:
+ return diag::warn_odr_objc_method_param_type_inconsistent;
+ case diag::err_odr_objc_method_variadic_inconsistent:
+ return diag::warn_odr_objc_method_variadic_inconsistent;
+ case diag::err_odr_objc_property_type_inconsistent:
+ return diag::warn_odr_objc_property_type_inconsistent;
+ case diag::err_odr_objc_property_impl_kind_inconsistent:
+ return diag::warn_odr_objc_property_impl_kind_inconsistent;
+ case diag::err_odr_objc_synthesize_ivar_inconsistent:
+ return diag::warn_odr_objc_synthesize_ivar_inconsistent;
+ case diag::err_odr_different_num_template_parameters:
+ return diag::warn_odr_different_num_template_parameters;
+ case diag::err_odr_different_template_parameter_kind:
+ return diag::warn_odr_different_template_parameter_kind;
+ case diag::err_odr_parameter_pack_non_pack:
+ return diag::warn_odr_parameter_pack_non_pack;
+ case diag::err_odr_non_type_parameter_type_inconsistent:
+ return diag::warn_odr_non_type_parameter_type_inconsistent;
+ }
+ llvm_unreachable("Diagnostic kind not handled in preceding switch");
+}
+
bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {
// Ensure that the implementation functions (all static functions in this TU)
@@ -1590,6 +1803,14 @@ bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
// Class template/non-class-template mismatch.
return false;
}
+ } else if (auto *ConceptDecl1 = dyn_cast<ConceptDecl>(D1)) {
+ if (auto *ConceptDecl2 = dyn_cast<ConceptDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(*this, ConceptDecl1, ConceptDecl2))
+ return false;
+ } else {
+ // Concept/non-concept mismatch.
+ return false;
+ }
} else if (auto *TTP1 = dyn_cast<TemplateTypeParmDecl>(D1)) {
if (auto *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) {
if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
@@ -1624,6 +1845,12 @@ bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
}
} else if (FunctionDecl *FD1 = dyn_cast<FunctionDecl>(D1)) {
if (FunctionDecl *FD2 = dyn_cast<FunctionDecl>(D2)) {
+ if (FD1->isOverloadedOperator()) {
+ if (!FD2->isOverloadedOperator())
+ return false;
+ if (FD1->getOverloadedOperator() != FD2->getOverloadedOperator())
+ return false;
+ }
if (!::IsStructurallyEquivalent(FD1->getIdentifier(),
FD2->getIdentifier()))
return false;
diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp
index 461084ce707ce..ba1581bd3f6b6 100644
--- a/lib/AST/ASTTypeTraits.cpp
+++ b/lib/AST/ASTTypeTraits.cpp
@@ -1,9 +1,8 @@
//===--- ASTTypeTraits.cpp --------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -38,6 +37,9 @@ const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
{ NKI_None, "Type" },
#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" },
#include "clang/AST/TypeNodes.def"
+ { NKI_None, "OMPClause" },
+#define OPENMP_CLAUSE(TextualSpelling, Class) {NKI_OMPClause, #Class},
+#include "clang/Basic/OpenMPKinds.def"
};
bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const {
@@ -104,6 +106,19 @@ ASTNodeKind ASTNodeKind::getFromNode(const Type &T) {
#include "clang/AST/TypeNodes.def"
}
llvm_unreachable("invalid type kind");
+ }
+
+ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) {
+ switch (C.getClauseKind()) {
+#define OPENMP_CLAUSE(Name, Class) \
+ case OMPC_##Name: return ASTNodeKind(NKI_##Class);
+#include "clang/Basic/OpenMPKinds.def"
+ case OMPC_threadprivate:
+ case OMPC_uniform:
+ case OMPC_unknown:
+ llvm_unreachable("unexpected OpenMP clause kind");
+ }
+ llvm_unreachable("invalid stmt kind");
}
void DynTypedNode::print(llvm::raw_ostream &OS,
@@ -152,6 +167,8 @@ SourceRange DynTypedNode::getSourceRange() const {
return D->getSourceRange();
if (const Stmt *S = get<Stmt>())
return S->getSourceRange();
+ if (const auto *C = get<OMPClause>())
+ return SourceRange(C->getBeginLoc(), C->getEndLoc());
return SourceRange();
}
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index b06b50c9b4b88..0ef925ec1c901 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -1,9 +1,8 @@
//===--- AttrImpl.cpp - Classes for representing attributes -----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h
index 06295b58178bf..31cb369187266 100644
--- a/lib/AST/CXXABI.h
+++ b/lib/AST/CXXABI.h
@@ -1,9 +1,8 @@
//===----- CXXABI.h - Interface to C++ ABIs ---------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index ddb350e72bbd0..ecf451b175afb 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -1,9 +1,8 @@
//===- CXXInheritance.cpp - C++ Inheritance -------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -487,6 +486,21 @@ bool CXXRecordDecl::FindOMPReductionMember(const CXXBaseSpecifier *Specifier,
return false;
}
+bool CXXRecordDecl::FindOMPMapperMember(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ DeclarationName Name) {
+ RecordDecl *BaseRecord =
+ Specifier->getType()->castAs<RecordType>()->getDecl();
+
+ for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
+ if (Path.Decls.front()->isInIdentifierNamespace(IDNS_OMPMapper))
+ return true;
+ }
+
+ return false;
+}
+
bool CXXRecordDecl::
FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
@@ -540,8 +554,7 @@ void OverridingMethods::add(unsigned OverriddenSubobject,
UniqueVirtualMethod Overriding) {
SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides
= Overrides[OverriddenSubobject];
- if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(),
- Overriding) == SubobjectOverrides.end())
+ if (llvm::find(SubobjectOverrides, Overriding) == SubobjectOverrides.end())
SubobjectOverrides.push_back(Overriding);
}
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 0d759e226c427..25339c7901e30 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -1,9 +1,8 @@
//===--- Comment.cpp - Comment AST node implementation --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp
index 5ec7586a475d2..2b648cbb1d4b4 100644
--- a/lib/AST/CommentBriefParser.cpp
+++ b/lib/AST/CommentBriefParser.cpp
@@ -1,9 +1,8 @@
//===--- CommentBriefParser.cpp - Dumb comment parser ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp
index 7378a7c3ac060..b306fcbb154f3 100644
--- a/lib/AST/CommentCommandTraits.cpp
+++ b/lib/AST/CommentCommandTraits.cpp
@@ -1,9 +1,8 @@
//===--- CommentCommandTraits.cpp - Comment command properties --*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index c43275318dd76..19485f6018c02 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -1,9 +1,8 @@
//===--- CommentLexer.cpp -------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index 7f70b95e98121..c7f8aa7e16a0a 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -1,9 +1,8 @@
//===--- CommentParser.cpp - Doxygen comment parser -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index 88588a7a89e60..067b3ae4222e3 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -1,9 +1,8 @@
//===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/ComparisonCategories.cpp b/lib/AST/ComparisonCategories.cpp
index 87f51facc59b9..ee4c1b0443a32 100644
--- a/lib/AST/ComparisonCategories.cpp
+++ b/lib/AST/ComparisonCategories.cpp
@@ -1,9 +1,8 @@
//===- ComparisonCategories.cpp - Three Way Comparison Data -----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/DataCollection.cpp b/lib/AST/DataCollection.cpp
index c2ecabe8e6f8a..8e67c101dee1f 100644
--- a/lib/AST/DataCollection.cpp
+++ b/lib/AST/DataCollection.cpp
@@ -1,9 +1,8 @@
//===-- DataCollection.cpp --------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 5536358b1ecf1..21cf9da18a8b2 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1,9 +1,8 @@
//===- Decl.cpp - Declaration AST Node Implementation ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -568,7 +567,14 @@ static bool isSingleLineLanguageLinkage(const Decl &D) {
return false;
}
-static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) {
+/// Determine whether D is declared in the purview of a named module.
+static bool isInModulePurview(const NamedDecl *D) {
+ if (auto *M = D->getOwningModule())
+ return M->isModulePurview();
+ return false;
+}
+
+static bool isExportedFromModuleInterfaceUnit(const NamedDecl *D) {
// FIXME: Handle isModulePrivate.
switch (D->getModuleOwnershipKind()) {
case Decl::ModuleOwnershipKind::Unowned:
@@ -576,8 +582,7 @@ static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) {
return false;
case Decl::ModuleOwnershipKind::Visible:
case Decl::ModuleOwnershipKind::VisibleWhenImported:
- if (auto *M = D->getOwningModule())
- return M->Kind == Module::ModuleInterfaceUnit;
+ return isInModulePurview(D);
}
llvm_unreachable("unexpected module ownership kind");
}
@@ -587,9 +592,8 @@ static LinkageInfo getInternalLinkageFor(const NamedDecl *D) {
// as "module-internal linkage", which means that they have internal linkage
// formally but can be indirectly accessed from outside the module via inline
// functions and templates defined within the module.
- if (auto *M = D->getOwningModule())
- if (M->Kind == Module::ModuleInterfaceUnit)
- return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false);
+ if (isInModulePurview(D))
+ return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false);
return LinkageInfo::internal();
}
@@ -599,15 +603,25 @@ static LinkageInfo getExternalLinkageFor(const NamedDecl *D) {
// - A name declared at namespace scope that does not have internal linkage
// by the previous rules and that is introduced by a non-exported
// declaration has module linkage.
- if (auto *M = D->getOwningModule())
- if (M->Kind == Module::ModuleInterfaceUnit)
- if (!isExportedFromModuleIntefaceUnit(
- cast<NamedDecl>(D->getCanonicalDecl())))
- return LinkageInfo(ModuleLinkage, DefaultVisibility, false);
+ if (isInModulePurview(D) && !isExportedFromModuleInterfaceUnit(
+ cast<NamedDecl>(D->getCanonicalDecl())))
+ return LinkageInfo(ModuleLinkage, DefaultVisibility, false);
return LinkageInfo::external();
}
+static StorageClass getStorageClass(const Decl *D) {
+ if (auto *TD = dyn_cast<TemplateDecl>(D))
+ D = TD->getTemplatedDecl();
+ if (D) {
+ if (auto *VD = dyn_cast<VarDecl>(D))
+ return VD->getStorageClass();
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getStorageClass();
+ }
+ return SC_None;
+}
+
LinkageInfo
LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
LVComputationKind computation,
@@ -619,24 +633,28 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
// C++ [basic.link]p3:
// A name having namespace scope (3.3.6) has internal linkage if it
// is the name of
- // - an object, reference, function or function template that is
- // explicitly declared static; or,
- // (This bullet corresponds to C99 6.2.2p3.)
+
+ if (getStorageClass(D->getCanonicalDecl()) == SC_Static) {
+ // - a variable, variable template, function, or function template
+ // that is explicitly declared static; or
+ // (This bullet corresponds to C99 6.2.2p3.)
+ return getInternalLinkageFor(D);
+ }
+
if (const auto *Var = dyn_cast<VarDecl>(D)) {
- // Explicitly declared static.
- if (Var->getStorageClass() == SC_Static)
- return getInternalLinkageFor(Var);
-
- // - a non-inline, non-volatile object or reference that is explicitly
- // declared const or constexpr and neither explicitly declared extern
- // nor previously declared to have external linkage; or (there is no
- // equivalent in C99)
- // The C++ modules TS adds "non-exported" to this list.
+ // - a non-template variable of non-volatile const-qualified type, unless
+ // - it is explicitly declared extern, or
+ // - it is inline or exported, or
+ // - it was previously declared and the prior declaration did not have
+ // internal linkage
+ // (There is no equivalent in C99.)
if (Context.getLangOpts().CPlusPlus &&
Var->getType().isConstQualified() &&
!Var->getType().isVolatileQualified() &&
!Var->isInline() &&
- !isExportedFromModuleIntefaceUnit(Var)) {
+ !isExportedFromModuleInterfaceUnit(Var) &&
+ !isa<VarTemplateSpecializationDecl>(Var) &&
+ !Var->getDescribedVarTemplate()) {
const VarDecl *PrevVar = Var->getPreviousDecl();
if (PrevVar)
return getLVForDecl(PrevVar, computation);
@@ -656,14 +674,6 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
if (PrevVar->getStorageClass() == SC_Static)
return getInternalLinkageFor(Var);
}
- } else if (const FunctionDecl *Function = D->getAsFunction()) {
- // C++ [temp]p4:
- // A non-member function template can have internal linkage; any
- // other template name shall have external linkage.
-
- // Explicitly declared static.
- if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
- return getInternalLinkageFor(Function);
} else if (const auto *IFD = dyn_cast<IndirectFieldDecl>(D)) {
// - a data member of an anonymous union.
const VarDecl *VD = IFD->getVarDecl();
@@ -672,6 +682,8 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
}
assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!");
+ // FIXME: This gives internal linkage to names that should have no linkage
+ // (those not covered by [basic.link]p6).
if (D->isInAnonymousNamespace()) {
const auto *Var = dyn_cast<VarDecl>(D);
const auto *Func = dyn_cast<FunctionDecl>(D);
@@ -731,10 +743,20 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
// C++ [basic.link]p4:
- // A name having namespace scope has external linkage if it is the
- // name of
+ // A name having namespace scope that has not been given internal linkage
+ // above and that is the name of
+ // [...bullets...]
+ // has its linkage determined as follows:
+ // - if the enclosing namespace has internal linkage, the name has
+ // internal linkage; [handled above]
+ // - otherwise, if the declaration of the name is attached to a named
+ // module and is not exported, the name has module linkage;
+ // - otherwise, the name has external linkage.
+ // LV is currently set up to handle the last two bullets.
//
- // - an object or reference, unless it has internal linkage; or
+ // The bullets are:
+
+ // - a variable; or
if (const auto *Var = dyn_cast<VarDecl>(D)) {
// GCC applies the following optimization to variables and static
// data members, but not to functions:
@@ -780,7 +802,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
mergeTemplateLV(LV, spec, computation);
}
- // - a function, unless it has internal linkage; or
+ // - a function; or
} else if (const auto *Function = dyn_cast<FunctionDecl>(D)) {
// In theory, we can modify the function's LV by the LV of its
// type unless it has C linkage (see comment above about variables
@@ -834,7 +856,8 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
mergeTemplateLV(LV, spec, computation);
}
- // - an enumerator belonging to an enumeration with external linkage;
+ // FIXME: This is not part of the C++ standard any more.
+ // - an enumerator belonging to an enumeration with external linkage; or
} else if (isa<EnumConstantDecl>(D)) {
LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()),
computation);
@@ -842,16 +865,16 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
return LinkageInfo::none();
LV.merge(EnumLV);
- // - a template, unless it is a function template that has
- // internal linkage (Clause 14);
+ // - a template
} else if (const auto *temp = dyn_cast<TemplateDecl>(D)) {
bool considerVisibility = !hasExplicitVisibilityAlready(computation);
LinkageInfo tempLV =
getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
- // - a namespace (7.3), unless it is declared within an unnamed
- // namespace.
+ // An unnamed namespace or a namespace declared directly or indirectly
+ // within an unnamed namespace has internal linkage. All other namespaces
+ // have external linkage.
//
// We handled names in anonymous namespaces above.
} else if (isa<NamespaceDecl>(D)) {
@@ -1508,6 +1531,11 @@ Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const {
}
return InternalLinkage ? M->Parent : nullptr;
}
+
+ case Module::PrivateModuleFragment:
+ // The private module fragment is part of its containing module for linkage
+ // purposes.
+ return M->Parent;
}
llvm_unreachable("unknown module kind");
@@ -1532,10 +1560,16 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
const PrintingPolicy &P) const {
const DeclContext *Ctx = getDeclContext();
- // For ObjC methods, look through categories and use the interface as context.
+ // For ObjC methods and properties, look through categories and use the
+ // interface as context.
if (auto *MD = dyn_cast<ObjCMethodDecl>(this))
if (auto *ID = MD->getClassInterface())
Ctx = ID;
+ if (auto *PD = dyn_cast<ObjCPropertyDecl>(this)) {
+ if (auto *MD = PD->getGetterMethodDecl())
+ if (auto *ID = MD->getClassInterface())
+ Ctx = ID;
+ }
if (Ctx->isFunctionOrMethod()) {
printName(OS);
@@ -2211,12 +2245,16 @@ void VarDecl::setInit(Expr *I) {
Init = I;
}
-bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
+bool VarDecl::mightBeUsableInConstantExpressions(ASTContext &C) const {
const LangOptions &Lang = C.getLangOpts();
if (!Lang.CPlusPlus)
return false;
+ // Function parameters are never usable in constant expressions.
+ if (isa<ParmVarDecl>(this))
+ return false;
+
// In C++11, any variable of reference type can be used in a constant
// expression if it is initialized by a constant expression.
if (Lang.CPlusPlus11 && getType()->isReferenceType())
@@ -2238,6 +2276,22 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
return Lang.CPlusPlus11 && isConstexpr();
}
+bool VarDecl::isUsableInConstantExpressions(ASTContext &Context) const {
+ // C++2a [expr.const]p3:
+ // A variable is usable in constant expressions after its initializing
+ // declaration is encountered...
+ const VarDecl *DefVD = nullptr;
+ const Expr *Init = getAnyInitializer(DefVD);
+ if (!Init || Init->isValueDependent() || getType()->isDependentType())
+ return false;
+ // ... if it is a constexpr variable, or it is of reference type or of
+ // const-qualified integral or enumeration type, ...
+ if (!DefVD->mightBeUsableInConstantExpressions(Context))
+ return false;
+ // ... and its initializer is a constant initializer.
+ return DefVD->checkInitIsICE();
+}
+
/// Convert the initializer for this declaration to the elaborated EvaluatedStmt
/// form, which contains extra information on the evaluated value of the
/// initializer.
@@ -2268,7 +2322,7 @@ APValue *VarDecl::evaluateValue(
// first time it is evaluated. FIXME: The notes won't always be emitted the
// first time we try evaluation, so might not be produced at all.
if (Eval->WasEvaluated)
- return Eval->Evaluated.isUninit() ? nullptr : &Eval->Evaluated;
+ return Eval->Evaluated.isAbsent() ? nullptr : &Eval->Evaluated;
const auto *Init = cast<Expr>(Eval->Value);
assert(!Init->isValueDependent());
@@ -2363,6 +2417,10 @@ bool VarDecl::checkInitIsICE() const {
return Eval->IsICE;
}
+bool VarDecl::isParameterPack() const {
+ return isa<PackExpansionType>(getType());
+}
+
template<typename DeclT>
static DeclT *getDefinitionOrSelf(DeclT *D) {
assert(D);
@@ -2380,48 +2438,61 @@ bool VarDecl::isNonEscapingByref() const {
}
VarDecl *VarDecl::getTemplateInstantiationPattern() const {
- // If it's a variable template specialization, find the template or partial
- // specialization from which it was instantiated.
- if (auto *VDTemplSpec = dyn_cast<VarTemplateSpecializationDecl>(this)) {
- auto From = VDTemplSpec->getInstantiatedFrom();
- if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
- while (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) {
- if (NewVTD->isMemberSpecialization())
- break;
- VTD = NewVTD;
- }
- return getDefinitionOrSelf(VTD->getTemplatedDecl());
- }
- if (auto *VTPSD =
- From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
- while (auto *NewVTPSD = VTPSD->getInstantiatedFromMember()) {
- if (NewVTPSD->isMemberSpecialization())
- break;
- VTPSD = NewVTPSD;
- }
- return getDefinitionOrSelf<VarDecl>(VTPSD);
- }
- }
+ const VarDecl *VD = this;
- if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) {
+ // If this is an instantiated member, walk back to the template from which
+ // it was instantiated.
+ if (MemberSpecializationInfo *MSInfo = VD->getMemberSpecializationInfo()) {
if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) {
- VarDecl *VD = getInstantiatedFromStaticDataMember();
+ VD = VD->getInstantiatedFromStaticDataMember();
while (auto *NewVD = VD->getInstantiatedFromStaticDataMember())
VD = NewVD;
- return getDefinitionOrSelf(VD);
}
}
- if (VarTemplateDecl *VarTemplate = getDescribedVarTemplate()) {
- while (VarTemplate->getInstantiatedFromMemberTemplate()) {
- if (VarTemplate->isMemberSpecialization())
+ // If it's an instantiated variable template specialization, find the
+ // template or partial specialization from which it was instantiated.
+ if (auto *VDTemplSpec = dyn_cast<VarTemplateSpecializationDecl>(VD)) {
+ if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) {
+ auto From = VDTemplSpec->getInstantiatedFrom();
+ if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
+ while (!VTD->isMemberSpecialization()) {
+ auto *NewVTD = VTD->getInstantiatedFromMemberTemplate();
+ if (!NewVTD)
+ break;
+ VTD = NewVTD;
+ }
+ return getDefinitionOrSelf(VTD->getTemplatedDecl());
+ }
+ if (auto *VTPSD =
+ From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+ while (!VTPSD->isMemberSpecialization()) {
+ auto *NewVTPSD = VTPSD->getInstantiatedFromMember();
+ if (!NewVTPSD)
+ break;
+ VTPSD = NewVTPSD;
+ }
+ return getDefinitionOrSelf<VarDecl>(VTPSD);
+ }
+ }
+ }
+
+ // If this is the pattern of a variable template, find where it was
+ // instantiated from. FIXME: Is this necessary?
+ if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) {
+ while (!VarTemplate->isMemberSpecialization()) {
+ auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate();
+ if (!NewVT)
break;
- VarTemplate = VarTemplate->getInstantiatedFromMemberTemplate();
+ VarTemplate = NewVT;
}
return getDefinitionOrSelf(VarTemplate->getTemplatedDecl());
}
- return nullptr;
+
+ if (VD == this)
+ return nullptr;
+ return getDefinitionOrSelf(const_cast<VarDecl*>(VD));
}
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
@@ -2441,6 +2512,17 @@ TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
return TSK_Undeclared;
}
+TemplateSpecializationKind
+VarDecl::getTemplateSpecializationKindForInstantiation() const {
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
+ return MSI->getTemplateSpecializationKind();
+
+ if (const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(this))
+ return Spec->getSpecializationKind();
+
+ return TSK_Undeclared;
+}
+
SourceLocation VarDecl::getPointOfInstantiation() const {
if (const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(this))
return Spec->getPointOfInstantiation();
@@ -2501,15 +2583,14 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
if (VarTemplateSpecializationDecl *Spec =
dyn_cast<VarTemplateSpecializationDecl>(this)) {
Spec->setSpecializationKind(TSK);
- if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
+ if (TSK != TSK_ExplicitSpecialization &&
+ PointOfInstantiation.isValid() &&
Spec->getPointOfInstantiation().isInvalid()) {
Spec->setPointOfInstantiation(PointOfInstantiation);
if (ASTMutationListener *L = getASTContext().getASTMutationListener())
L->InstantiationRequested(this);
}
- }
-
- if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) {
+ } else if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) {
MSI->setTemplateSpecializationKind(TSK);
if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
MSI->getPointOfInstantiation().isInvalid()) {
@@ -2626,10 +2707,6 @@ bool ParmVarDecl::hasDefaultArg() const {
!Init.isNull();
}
-bool ParmVarDecl::isParameterPack() const {
- return isa<PackExpansionType>(getType());
-}
-
void ParmVarDecl::setParameterIndexLarge(unsigned parameterIndex) {
getASTContext().setParameterIndex(this, parameterIndex);
ParmVarDeclBits.ParameterIndex = ParameterIndexSentinel;
@@ -2647,7 +2724,8 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, StorageClass S,
- bool isInlineSpecified, bool isConstexprSpecified)
+ bool isInlineSpecified,
+ ConstexprSpecKind ConstexprKind)
: DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
StartLoc),
DeclContext(DK), redeclarable_base(C), ODRHash(0),
@@ -2656,7 +2734,6 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
FunctionDeclBits.SClass = S;
FunctionDeclBits.IsInline = isInlineSpecified;
FunctionDeclBits.IsInlineSpecified = isInlineSpecified;
- FunctionDeclBits.IsExplicitSpecified = false;
FunctionDeclBits.IsVirtualAsWritten = false;
FunctionDeclBits.IsPure = false;
FunctionDeclBits.HasInheritedPrototype = false;
@@ -2668,7 +2745,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
FunctionDeclBits.IsExplicitlyDefaulted = false;
FunctionDeclBits.HasImplicitReturnZero = false;
FunctionDeclBits.IsLateTemplateParsed = false;
- FunctionDeclBits.IsConstexpr = isConstexprSpecified;
+ FunctionDeclBits.ConstexprKind = ConstexprKind;
FunctionDeclBits.InstantiationIsPending = false;
FunctionDeclBits.UsesSEHTry = false;
FunctionDeclBits.HasSkippedBody = false;
@@ -2904,6 +2981,8 @@ bool FunctionDecl::isExternC() const {
}
bool FunctionDecl::isInExternCContext() const {
+ if (hasAttr<OpenCLKernelAttr>())
+ return true;
return getLexicalDeclContext()->isExternCContext();
}
@@ -2982,16 +3061,20 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); }
-/// Returns a value indicating whether this function
-/// corresponds to a builtin function.
+/// Returns a value indicating whether this function corresponds to a builtin
+/// function.
///
-/// The function corresponds to a built-in function if it is
-/// declared at translation scope or within an extern "C" block and
-/// its name matches with the name of a builtin. The returned value
-/// will be 0 for functions that do not correspond to a builtin, a
-/// value of type \c Builtin::ID if in the target-independent range
-/// \c [1,Builtin::First), or a target-specific builtin value.
-unsigned FunctionDecl::getBuiltinID() const {
+/// The function corresponds to a built-in function if it is declared at
+/// translation scope or within an extern "C" block and its name matches with
+/// the name of a builtin. The returned value will be 0 for functions that do
+/// not correspond to a builtin, a value of type \c Builtin::ID if in the
+/// target-independent range \c [1,Builtin::First), or a target-specific builtin
+/// value.
+///
+/// \param ConsiderWrapperFunctions If true, we should consider wrapper
+/// 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;
@@ -3019,7 +3102,7 @@ unsigned FunctionDecl::getBuiltinID() const {
// If the function is marked "overloadable", it has a different mangled name
// and is not the C library function.
- if (hasAttr<OverloadableAttr>())
+ if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>())
return 0;
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
@@ -3030,7 +3113,7 @@ unsigned FunctionDecl::getBuiltinID() const {
// function or whether it just has the same name.
// If this is a static function, it's not a builtin.
- if (getStorageClass() == SC_Static)
+ if (!ConsiderWrapperFunctions && getStorageClass() == SC_Static)
return 0;
// OpenCL v1.2 s6.9.f - The library functions defined in
@@ -3337,7 +3420,13 @@ FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
}
MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
- return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>();
+ if (auto *MSI =
+ TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>())
+ return MSI;
+ if (auto *FTSI = TemplateOrSpecialization
+ .dyn_cast<FunctionTemplateSpecializationInfo *>())
+ return FTSI->getMemberSpecializationInfo();
+ return nullptr;
}
void
@@ -3356,6 +3445,8 @@ FunctionTemplateDecl *FunctionDecl::getDescribedFunctionTemplate() const {
}
void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template) {
+ assert(TemplateOrSpecialization.isNull() &&
+ "Member function is already a specialization");
TemplateOrSpecialization = Template;
}
@@ -3364,19 +3455,15 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
if (isInvalidDecl())
return false;
- switch (getTemplateSpecializationKind()) {
+ switch (getTemplateSpecializationKindForInstantiation()) {
case TSK_Undeclared:
case TSK_ExplicitInstantiationDefinition:
+ case TSK_ExplicitSpecialization:
return false;
case TSK_ImplicitInstantiation:
return true;
- // It is possible to instantiate TSK_ExplicitSpecialization kind
- // if the FunctionDecl has a class scope specialization pattern.
- case TSK_ExplicitSpecialization:
- return getClassScopeSpecializationPattern() != nullptr;
-
case TSK_ExplicitInstantiationDeclaration:
// Handled below.
break;
@@ -3399,26 +3486,12 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
}
bool FunctionDecl::isTemplateInstantiation() const {
- switch (getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- return false;
- case TSK_ImplicitInstantiation:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- return true;
- }
- llvm_unreachable("All TSK values handled.");
+ // FIXME: Remove this, it's not clear what it means. (Which template
+ // specialization kind?)
+ return clang::isTemplateInstantiation(getTemplateSpecializationKind());
}
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
- // Handle class scope explicit specialization special case.
- if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
- if (auto *Spec = getClassScopeSpecializationPattern())
- return getDefinitionOrSelf(Spec);
- return nullptr;
- }
-
// If this is a generic lambda call operator specialization, its
// instantiation pattern is always its primary template's pattern
// even if its primary template was instantiated from another
@@ -3434,21 +3507,28 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
return getDefinitionOrSelf(getPrimaryTemplate()->getTemplatedDecl());
}
+ if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) {
+ if (!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind()))
+ return nullptr;
+ return getDefinitionOrSelf(cast<FunctionDecl>(Info->getInstantiatedFrom()));
+ }
+
+ if (!clang::isTemplateInstantiation(getTemplateSpecializationKind()))
+ return nullptr;
+
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
- while (Primary->getInstantiatedFromMemberTemplate()) {
- // If we have hit a point where the user provided a specialization of
- // this template, we're done looking.
- if (Primary->isMemberSpecialization())
+ // If we hit a point where the user provided a specialization of this
+ // template, we're done looking.
+ while (!Primary->isMemberSpecialization()) {
+ auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
+ if (!NewPrimary)
break;
- Primary = Primary->getInstantiatedFromMemberTemplate();
+ Primary = NewPrimary;
}
return getDefinitionOrSelf(Primary->getTemplatedDecl());
}
- if (auto *MFD = getInstantiatedFromMemberFunction())
- return getDefinitionOrSelf(MFD);
-
return nullptr;
}
@@ -3456,15 +3536,11 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
if (FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
- return Info->Template.getPointer();
+ return Info->getTemplate();
}
return nullptr;
}
-FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const {
- return getASTContext().getClassScopeSpecializationPattern(this);
-}
-
FunctionTemplateSpecializationInfo *
FunctionDecl::getTemplateSpecializationInfo() const {
return TemplateOrSpecialization
@@ -3499,15 +3575,19 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C,
TemplateSpecializationKind TSK,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation PointOfInstantiation) {
+ assert((TemplateOrSpecialization.isNull() ||
+ TemplateOrSpecialization.is<MemberSpecializationInfo *>()) &&
+ "Member function is already a specialization");
assert(TSK != TSK_Undeclared &&
"Must specify the type of function template specialization");
- FunctionTemplateSpecializationInfo *Info
- = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
- if (!Info)
- Info = FunctionTemplateSpecializationInfo::Create(C, this, Template, TSK,
- TemplateArgs,
- TemplateArgsAsWritten,
- PointOfInstantiation);
+ assert((TemplateOrSpecialization.isNull() ||
+ TSK == TSK_ExplicitSpecialization) &&
+ "Member specialization must be an explicit specialization");
+ FunctionTemplateSpecializationInfo *Info =
+ FunctionTemplateSpecializationInfo::Create(
+ C, this, Template, TSK, TemplateArgs, TemplateArgsAsWritten,
+ PointOfInstantiation,
+ TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>());
TemplateOrSpecialization = Info;
Template->addSpecialization(Info, InsertPos);
}
@@ -3558,14 +3638,47 @@ DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts,
TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
// For a function template specialization, query the specialization
// information object.
- FunctionTemplateSpecializationInfo *FTSInfo
- = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
- if (FTSInfo)
+ if (FunctionTemplateSpecializationInfo *FTSInfo =
+ TemplateOrSpecialization
+ .dyn_cast<FunctionTemplateSpecializationInfo *>())
+ return FTSInfo->getTemplateSpecializationKind();
+
+ if (MemberSpecializationInfo *MSInfo =
+ TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>())
+ return MSInfo->getTemplateSpecializationKind();
+
+ return TSK_Undeclared;
+}
+
+TemplateSpecializationKind
+FunctionDecl::getTemplateSpecializationKindForInstantiation() const {
+ // This is the same as getTemplateSpecializationKind(), except that for a
+ // function that is both a function template specialization and a member
+ // specialization, we prefer the member specialization information. Eg:
+ //
+ // template<typename T> struct A {
+ // template<typename U> void f() {}
+ // template<> void f<int>() {}
+ // };
+ //
+ // For A<int>::f<int>():
+ // * getTemplateSpecializationKind() will return TSK_ExplicitSpecialization
+ // * getTemplateSpecializationKindForInstantiation() will return
+ // TSK_ImplicitInstantiation
+ //
+ // This reflects the facts that A<int>::f<int> is an explicit specialization
+ // of A<int>::f, and that A<int>::f<int> should be implicitly instantiated
+ // from A::f<int> if a definition is needed.
+ if (FunctionTemplateSpecializationInfo *FTSInfo =
+ TemplateOrSpecialization
+ .dyn_cast<FunctionTemplateSpecializationInfo *>()) {
+ if (auto *MSInfo = FTSInfo->getMemberSpecializationInfo())
+ return MSInfo->getTemplateSpecializationKind();
return FTSInfo->getTemplateSpecializationKind();
+ }
- MemberSpecializationInfo *MSInfo
- = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
- if (MSInfo)
+ if (MemberSpecializationInfo *MSInfo =
+ TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>())
return MSInfo->getTemplateSpecializationKind();
return TSK_Undeclared;
@@ -3673,6 +3786,10 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
case Builtin::BImemcmp:
return Builtin::BImemcmp;
+ case Builtin::BI__builtin_bcmp:
+ case Builtin::BIbcmp:
+ return Builtin::BIbcmp;
+
case Builtin::BI__builtin_strncpy:
case Builtin::BI__builtin___strncpy_chk:
case Builtin::BIstrncpy:
@@ -3713,6 +3830,8 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
return Builtin::BImemmove;
else if (FnInfo->isStr("memcmp"))
return Builtin::BImemcmp;
+ else if (FnInfo->isStr("bcmp"))
+ return Builtin::BIbcmp;
else if (FnInfo->isStr("strncpy"))
return Builtin::BIstrncpy;
else if (FnInfo->isStr("strncmp"))
@@ -3794,6 +3913,39 @@ bool FieldDecl::isZeroLengthBitField(const ASTContext &Ctx) const {
getBitWidthValue(Ctx) == 0;
}
+bool FieldDecl::isZeroSize(const ASTContext &Ctx) const {
+ if (isZeroLengthBitField(Ctx))
+ return true;
+
+ // C++2a [intro.object]p7:
+ // An object has nonzero size if it
+ // -- is not a potentially-overlapping subobject, or
+ if (!hasAttr<NoUniqueAddressAttr>())
+ return false;
+
+ // -- is not of class type, or
+ const auto *RT = getType()->getAs<RecordType>();
+ if (!RT)
+ return false;
+ const RecordDecl *RD = RT->getDecl()->getDefinition();
+ if (!RD) {
+ assert(isInvalidDecl() && "valid field has incomplete type");
+ return false;
+ }
+
+ // -- [has] virtual member functions or virtual base classes, or
+ // -- has subobjects of nonzero size or bit-fields of nonzero length
+ const auto *CXXRD = cast<CXXRecordDecl>(RD);
+ if (!CXXRD->isEmpty())
+ return false;
+
+ // Otherwise, [...] the circumstances under which the object has zero size
+ // are implementation-defined.
+ // FIXME: This might be Itanium ABI specific; we don't yet know what the MS
+ // ABI will do.
+ return true;
+}
+
unsigned FieldDecl::getFieldIndex() const {
const FieldDecl *Canonical = getCanonicalDecl();
if (Canonical != this)
@@ -4100,6 +4252,9 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C,
setNonTrivialToPrimitiveDefaultInitialize(false);
setNonTrivialToPrimitiveCopy(false);
setNonTrivialToPrimitiveDestroy(false);
+ setHasNonTrivialToPrimitiveDefaultInitializeCUnion(false);
+ setHasNonTrivialToPrimitiveDestructCUnion(false);
+ setHasNonTrivialToPrimitiveCopyCUnion(false);
setParamDestroyedInCallee(false);
setArgPassingRestrictions(APK_CanPassInRegs);
}
@@ -4260,6 +4415,7 @@ BlockDecl::BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
setBlockMissingReturnType(true);
setIsConversionFromLambda(false);
setDoesNotEscape(false);
+ setCanAvoidCopyToHeap(false);
}
void BlockDecl::setParams(ArrayRef<ParmVarDecl *> NewParamInfo) {
@@ -4422,13 +4578,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- StorageClass SC,
- bool isInlineSpecified,
+ StorageClass SC, bool isInlineSpecified,
bool hasWrittenPrototype,
- bool isConstexprSpecified) {
+ ConstexprSpecKind ConstexprKind) {
FunctionDecl *New =
new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo,
- SC, isInlineSpecified, isConstexprSpecified);
+ SC, isInlineSpecified, ConstexprKind);
New->setHasWrittenPrototype(hasWrittenPrototype);
return New;
}
@@ -4436,7 +4591,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, false);
+ SC_None, false, CSK_unspecified);
}
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index b83082e9eb08c..fd80e1532eb5d 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -1,9 +1,8 @@
//===- DeclBase.cpp - Declaration AST Node Implementation -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -209,8 +208,8 @@ bool Decl::isTemplateParameterPack() const {
}
bool Decl::isParameterPack() const {
- if (const auto *Parm = dyn_cast<ParmVarDecl>(this))
- return Parm->isParameterPack();
+ if (const auto *Var = dyn_cast<VarDecl>(this))
+ return Var->isParameterPack();
return isTemplateParameterPack();
}
@@ -355,7 +354,8 @@ bool Decl::isInAnonymousNamespace() const {
}
bool Decl::isInStdNamespace() const {
- return getDeclContext()->isStdNamespace();
+ const DeclContext *DC = getDeclContext();
+ return DC && DC->isStdNamespace();
}
TranslationUnitDecl *Decl::getTranslationUnitDecl() {
@@ -431,22 +431,6 @@ bool Decl::isReferenced() const {
return false;
}
-bool Decl::isExported() const {
- if (isModulePrivate())
- return false;
- // Namespaces are always exported.
- if (isa<TranslationUnitDecl>(this) || isa<NamespaceDecl>(this))
- return true;
- // Otherwise, this is a strictly lexical check.
- for (auto *DC = getLexicalDeclContext(); DC; DC = DC->getLexicalParent()) {
- if (cast<Decl>(DC)->isModulePrivate())
- return false;
- if (isa<ExportDecl>(DC))
- return true;
- }
- return false;
-}
-
ExternalSourceSymbolAttr *Decl::getExternalSourceSymbolAttr() const {
const Decl *Definition = nullptr;
if (auto *ID = dyn_cast<ObjCInterfaceDecl>(this)) {
@@ -726,6 +710,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Binding:
case NonTypeTemplateParm:
case VarTemplate:
+ case Concept:
// These (C++-only) declarations are found by redeclaration lookup for
// tag types, so we include them in the tag namespace.
return IDNS_Ordinary | IDNS_Tag;
@@ -781,6 +766,9 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case OMPDeclareReduction:
return IDNS_OMPReduction;
+ case OMPDeclareMapper:
+ return IDNS_OMPMapper;
+
// Never have names.
case Friend:
case FriendTemplate:
@@ -810,6 +798,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCCategoryImpl:
case Import:
case OMPThreadPrivate:
+ case OMPAllocate:
case OMPRequires:
case OMPCapturedExpr:
case Empty:
@@ -932,6 +921,7 @@ bool Decl::AccessDeclContextSanity() const {
if (isa<TranslationUnitDecl>(this) ||
isa<TemplateTypeParmDecl>(this) ||
isa<NonTypeTemplateParmDecl>(this) ||
+ !getDeclContext() ||
!isa<CXXRecordDecl>(getDeclContext()) ||
isInvalidDecl() ||
isa<StaticAssertDecl>(this) ||
@@ -969,6 +959,8 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const {
if (Ty->isFunctionPointerType())
Ty = Ty->getAs<PointerType>()->getPointeeType();
+ else if (Ty->isFunctionReferenceType())
+ Ty = Ty->getAs<ReferenceType>()->getPointeeType();
else if (BlocksToo && Ty->isBlockPointerType())
Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
@@ -1054,6 +1046,18 @@ DeclContext *DeclContext::getLookupParent() {
return getParent();
}
+const BlockDecl *DeclContext::getInnermostBlockDecl() const {
+ const DeclContext *Ctx = this;
+
+ do {
+ if (Ctx->isClosure())
+ return cast<BlockDecl>(Ctx);
+ Ctx = Ctx->getParent();
+ } while (Ctx);
+
+ return nullptr;
+}
+
bool DeclContext::isInlineNamespace() const {
return isNamespace() &&
cast<NamespaceDecl>(this)->isInline();
@@ -1164,6 +1168,7 @@ DeclContext *DeclContext::getPrimaryContext() {
case Decl::Block:
case Decl::Captured:
case Decl::OMPDeclareReduction:
+ case Decl::OMPDeclareMapper:
// There is only one DeclContext for these entities.
return this;
@@ -1175,13 +1180,15 @@ DeclContext *DeclContext::getPrimaryContext() {
return this;
case Decl::ObjCInterface:
- if (auto *Def = cast<ObjCInterfaceDecl>(this)->getDefinition())
- return Def;
+ if (auto *OID = dyn_cast<ObjCInterfaceDecl>(this))
+ if (auto *Def = OID->getDefinition())
+ return Def;
return this;
case Decl::ObjCProtocol:
- if (auto *Def = cast<ObjCProtocolDecl>(this)->getDefinition())
- return Def;
+ if (auto *OPD = dyn_cast<ObjCProtocolDecl>(this))
+ if (auto *Def = OPD->getDefinition())
+ return Def;
return this;
case Decl::ObjCCategory:
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 31ffeb0dcd1e2..59710a55498f2 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1,9 +1,8 @@
//===- DeclCXX.cpp - C++ Declaration AST Node Implementation --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -606,14 +605,19 @@ bool CXXRecordDecl::hasSubobjectAtOffsetZeroOfEmptyBaseType(
// that sure looks like a wording bug.
// -- If X is a non-union class type with a non-static data member
- // [recurse to] the first non-static data member of X
+ // [recurse to each field] that is either of zero size or is the
+ // first non-static data member of X
// -- If X is a union type, [recurse to union members]
+ bool IsFirstField = true;
for (auto *FD : X->fields()) {
// FIXME: Should we really care about the type of the first non-static
// data member of a non-union if there are preceding unnamed bit-fields?
if (FD->isUnnamedBitfield())
continue;
+ if (!IsFirstField && !FD->isZeroSize(Ctx))
+ continue;
+
// -- If X is n array type, [visit the element type]
QualType T = Ctx.getBaseElementType(FD->getType());
if (auto *RD = T->getAsCXXRecordDecl())
@@ -621,7 +625,7 @@ bool CXXRecordDecl::hasSubobjectAtOffsetZeroOfEmptyBaseType(
return true;
if (!X->isUnion())
- break;
+ IsFirstField = false;
}
}
@@ -641,7 +645,8 @@ bool CXXRecordDecl::lambdaIsDefaultConstructibleAndAssignable() const {
// C++17 [expr.prim.lambda]p21:
// The closure type associated with a lambda-expression has no default
// constructor and a deleted copy assignment operator.
- if (getLambdaCaptureDefault() != LCD_None)
+ if (getLambdaCaptureDefault() != LCD_None ||
+ getLambdaData().NumCaptures != 0)
return false;
return getASTContext().getLangOpts().CPlusPlus2a;
}
@@ -992,6 +997,17 @@ void CXXRecordDecl::addedMember(Decl *D) {
setArgPassingRestrictions(RecordDecl::APK_CanNeverPassInRegs);
Data.HasIrrelevantDestructor = false;
+
+ if (isUnion()) {
+ data().DefaultedCopyConstructorIsDeleted = true;
+ data().DefaultedMoveConstructorIsDeleted = true;
+ data().DefaultedMoveAssignmentIsDeleted = true;
+ data().DefaultedDestructorIsDeleted = true;
+ data().NeedOverloadResolutionForCopyConstructor = true;
+ data().NeedOverloadResolutionForMoveConstructor = true;
+ data().NeedOverloadResolutionForMoveAssignment = true;
+ data().NeedOverloadResolutionForDestructor = true;
+ }
} else if (!Context.getLangOpts().ObjCAutoRefCount) {
setHasObjectMember(true);
}
@@ -1058,6 +1074,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (T->isReferenceType())
data().DefaultedMoveAssignmentIsDeleted = true;
+ // Bitfields of length 0 are also zero-sized, but we already bailed out for
+ // those because they are always unnamed.
+ bool IsZeroSize = Field->isZeroSize(Context);
+
if (const auto *RecordTy = T->getAs<RecordType>()) {
auto *FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldRec->getDefinition()) {
@@ -1173,7 +1193,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
// A standard-layout class is a class that:
// [...]
// -- has no element of the set M(S) of types as a base class.
- if (data().IsStandardLayout && (isUnion() || IsFirstField) &&
+ if (data().IsStandardLayout &&
+ (isUnion() || IsFirstField || IsZeroSize) &&
hasSubobjectAtOffsetZeroOfEmptyBaseType(Context, FieldRec))
data().IsStandardLayout = false;
@@ -1255,8 +1276,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
}
// C++14 [meta.unary.prop]p4:
- // T is a class type [...] with [...] no non-static data members
- data().Empty = false;
+ // T is a class type [...] with [...] no non-static data members other
+ // than subobjects of zero size
+ if (data().Empty && !IsZeroSize)
+ data().Empty = false;
}
// Handle using declarations of conversion functions.
@@ -1411,13 +1434,28 @@ void CXXRecordDecl::getCaptureFields(
TemplateParameterList *
CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
- if (!isLambda()) return nullptr;
+ if (!isGenericLambda()) return nullptr;
CXXMethodDecl *CallOp = getLambdaCallOperator();
if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate())
return Tmpl->getTemplateParameters();
return nullptr;
}
+ArrayRef<NamedDecl *>
+CXXRecordDecl::getLambdaExplicitTemplateParameters() const {
+ TemplateParameterList *List = getGenericLambdaTemplateParameterList();
+ if (!List)
+ return {};
+
+ assert(std::is_partitioned(List->begin(), List->end(),
+ [](const NamedDecl *D) { return !D->isImplicit(); })
+ && "Explicit template params should be ordered before implicit ones");
+
+ const auto ExplicitEnd = llvm::partition_point(
+ *List, [](const NamedDecl *D) { return !D->isImplicit(); });
+ return llvm::makeArrayRef(List->begin(), ExplicitEnd);
+}
+
Decl *CXXRecordDecl::getLambdaContextDecl() const {
assert(isLambda() && "Not a lambda closure type!");
ExternalASTSource *Source = getParentASTContext().getExternalSource();
@@ -1586,8 +1624,8 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
if (Convs[I].getDecl() == ConvDecl) {
Convs.erase(I);
- assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end()
- && "conversion was found multiple times in unresolved set");
+ assert(llvm::find(Convs, ConvDecl) == Convs.end() &&
+ "conversion was found multiple times in unresolved set");
return;
}
}
@@ -1852,19 +1890,47 @@ bool CXXRecordDecl::mayBeAbstract() const {
void CXXDeductionGuideDecl::anchor() {}
+bool ExplicitSpecifier::isEquivalent(const ExplicitSpecifier Other) const {
+ if ((getKind() != Other.getKind() ||
+ getKind() == ExplicitSpecKind::Unresolved)) {
+ if (getKind() == ExplicitSpecKind::Unresolved &&
+ Other.getKind() == ExplicitSpecKind::Unresolved) {
+ ODRHash SelfHash, OtherHash;
+ SelfHash.AddStmt(getExpr());
+ OtherHash.AddStmt(Other.getExpr());
+ return SelfHash.CalculateHash() == OtherHash.CalculateHash();
+ } else
+ return false;
+ }
+ return true;
+}
+
+ExplicitSpecifier ExplicitSpecifier::getFromDecl(FunctionDecl *Function) {
+ switch (Function->getDeclKind()) {
+ case Decl::Kind::CXXConstructor:
+ return cast<CXXConstructorDecl>(Function)->getExplicitSpecifier();
+ case Decl::Kind::CXXConversion:
+ return cast<CXXConversionDecl>(Function)->getExplicitSpecifier();
+ case Decl::Kind::CXXDeductionGuide:
+ return cast<CXXDeductionGuideDecl>(Function)->getExplicitSpecifier();
+ default:
+ return {};
+ }
+}
+
CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
- ASTContext &C, DeclContext *DC, SourceLocation StartLoc, bool IsExplicit,
- const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
- SourceLocation EndLocation) {
- return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, IsExplicit,
- NameInfo, T, TInfo, EndLocation);
+ ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+ ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
+ TypeSourceInfo *TInfo, SourceLocation EndLocation) {
+ return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T,
+ TInfo, EndLocation);
}
CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- return new (C, ID) CXXDeductionGuideDecl(C, nullptr, SourceLocation(), false,
- DeclarationNameInfo(), QualType(),
- nullptr, SourceLocation());
+ return new (C, ID) CXXDeductionGuideDecl(
+ C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(),
+ QualType(), nullptr, SourceLocation());
}
void CXXMethodDecl::anchor() {}
@@ -1891,8 +1957,8 @@ static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD,
}
CXXMethodDecl *
-CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
- bool MayBeBase) {
+CXXMethodDecl::getCorrespondingMethodDeclaredInClass(const CXXRecordDecl *RD,
+ bool MayBeBase) {
if (this->getParent()->getCanonicalDecl() == RD->getCanonicalDecl())
return this;
@@ -1918,6 +1984,15 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
return MD;
}
+ return nullptr;
+}
+
+CXXMethodDecl *
+CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
+ bool MayBeBase) {
+ if (auto *MD = getCorrespondingMethodDeclaredInClass(RD, MayBeBase))
+ return MD;
+
for (const auto &I : RD->bases()) {
const RecordType *RT = I.getType()->getAs<RecordType>();
if (!RT)
@@ -1931,22 +2006,22 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
return nullptr;
}
-CXXMethodDecl *
-CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
- SourceLocation StartLoc,
- const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- StorageClass SC, bool isInline,
- bool isConstexpr, SourceLocation EndLocation) {
- return new (C, RD) CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo,
- T, TInfo, SC, isInline, isConstexpr,
- EndLocation);
+CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
+ const DeclarationNameInfo &NameInfo,
+ QualType T, TypeSourceInfo *TInfo,
+ StorageClass SC, bool isInline,
+ ConstexprSpecKind ConstexprKind,
+ SourceLocation EndLocation) {
+ return new (C, RD)
+ CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC,
+ isInline, ConstexprKind, EndLocation);
}
CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- return new (C, ID) CXXMethodDecl(CXXMethod, C, nullptr, SourceLocation(),
- DeclarationNameInfo(), QualType(), nullptr,
- SC_None, false, false, SourceLocation());
+ return new (C, ID) CXXMethodDecl(
+ CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(),
+ QualType(), nullptr, SC_None, false, CSK_unspecified, SourceLocation());
}
CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
@@ -2081,8 +2156,13 @@ bool CXXMethodDecl::isUsualDeallocationFunction(
return false;
// In C++17 onwards, all potential usual deallocation functions are actual
- // usual deallocation functions.
- if (Context.getLangOpts().AlignedAllocation)
+ // usual deallocation functions. Honor this behavior when post-C++14
+ // deallocation functions are offered as extensions too.
+ // FIXME(EricWF): Destrying Delete should be a language option. How do we
+ // handle when destroying delete is used prior to C++17?
+ if (Context.getLangOpts().CPlusPlus17 ||
+ Context.getLangOpts().AlignedAllocation ||
+ isDestroyingOperatorDelete())
return true;
// This function is a usual deallocation function if there are no
@@ -2173,12 +2253,23 @@ CXXMethodDecl::overridden_methods() const {
return getASTContext().overridden_methods(this);
}
+static QualType getThisObjectType(ASTContext &C, const FunctionProtoType *FPT,
+ const CXXRecordDecl *Decl) {
+ QualType ClassTy = C.getTypeDeclType(Decl);
+ return C.getQualifiedType(ClassTy, FPT->getMethodQuals());
+}
+
QualType CXXMethodDecl::getThisType(const FunctionProtoType *FPT,
const CXXRecordDecl *Decl) {
ASTContext &C = Decl->getASTContext();
- QualType ClassTy = C.getTypeDeclType(Decl);
- ClassTy = C.getQualifiedType(ClassTy, FPT->getTypeQuals());
- return C.getPointerType(ClassTy);
+ QualType ObjectTy = ::getThisObjectType(C, FPT, Decl);
+ return C.getPointerType(ObjectTy);
+}
+
+QualType CXXMethodDecl::getThisObjectType(const FunctionProtoType *FPT,
+ const CXXRecordDecl *Decl) {
+ ASTContext &C = Decl->getASTContext();
+ return ::getThisObjectType(C, FPT, Decl);
}
QualType CXXMethodDecl::getThisType() const {
@@ -2193,6 +2284,14 @@ QualType CXXMethodDecl::getThisType() const {
getParent());
}
+QualType CXXMethodDecl::getThisObjectType() const {
+ // Ditto getThisType.
+ assert(isInstance() && "No 'this' for static methods!");
+
+ return CXXMethodDecl::getThisObjectType(getType()->getAs<FunctionProtoType>(),
+ getParent());
+}
+
bool CXXMethodDecl::hasInlineBody() const {
// If this function is a template instantiation, look at the template from
// which it was instantiated.
@@ -2297,47 +2396,55 @@ SourceRange CXXCtorInitializer::getSourceRange() const {
CXXConstructorDecl::CXXConstructorDecl(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
- bool isExplicitSpecified, bool isInline, bool isImplicitlyDeclared,
- bool isConstexpr, InheritedConstructor Inherited)
+ ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
+ ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited)
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
- SC_None, isInline, isConstexpr, SourceLocation()) {
+ SC_None, isInline, ConstexprKind, SourceLocation()) {
setNumCtorInitializers(0);
setInheritingConstructor(static_cast<bool>(Inherited));
setImplicit(isImplicitlyDeclared);
+ CXXConstructorDeclBits.HasTrailingExplicitSpecifier = ES.getExpr() ? 1 : 0;
if (Inherited)
*getTrailingObjects<InheritedConstructor>() = Inherited;
- setExplicitSpecified(isExplicitSpecified);
+ setExplicitSpecifier(ES);
}
void CXXConstructorDecl::anchor() {}
CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C,
unsigned ID,
- bool Inherited) {
- unsigned Extra = additionalSizeToAlloc<InheritedConstructor>(Inherited);
- auto *Result = new (C, ID, Extra) CXXConstructorDecl(
- C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
- false, false, false, false, InheritedConstructor());
- Result->setInheritingConstructor(Inherited);
+ uint64_t AllocKind) {
+ bool hasTraillingExplicit = static_cast<bool>(AllocKind & TAKHasTailExplicit);
+ bool isInheritingConstructor =
+ static_cast<bool>(AllocKind & TAKInheritsConstructor);
+ unsigned Extra =
+ additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>(
+ isInheritingConstructor, hasTraillingExplicit);
+ auto *Result = new (C, ID, Extra)
+ CXXConstructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(),
+ QualType(), nullptr, ExplicitSpecifier(), false, false,
+ CSK_unspecified, InheritedConstructor());
+ Result->setInheritingConstructor(isInheritingConstructor);
+ Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier =
+ hasTraillingExplicit;
+ Result->setExplicitSpecifier(ExplicitSpecifier());
return Result;
}
-CXXConstructorDecl *
-CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
- SourceLocation StartLoc,
- const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- bool isExplicit, bool isInline,
- bool isImplicitlyDeclared, bool isConstexpr,
- InheritedConstructor Inherited) {
+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) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
unsigned Extra =
- additionalSizeToAlloc<InheritedConstructor>(Inherited ? 1 : 0);
- return new (C, RD, Extra) CXXConstructorDecl(
- C, RD, StartLoc, NameInfo, T, TInfo, isExplicit, isInline,
- isImplicitlyDeclared, isConstexpr, Inherited);
+ additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>(
+ Inherited ? 1 : 0, ES.getExpr() ? 1 : 0);
+ return new (C, RD, Extra)
+ CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline,
+ isImplicitlyDeclared, ConstexprKind, Inherited);
}
CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
@@ -2488,25 +2595,22 @@ void CXXConversionDecl::anchor() {}
CXXConversionDecl *
CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- return new (C, ID) CXXConversionDecl(C, nullptr, SourceLocation(),
- DeclarationNameInfo(), QualType(),
- nullptr, false, false, false,
- SourceLocation());
+ return new (C, ID) CXXConversionDecl(
+ C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
+ false, ExplicitSpecifier(), CSK_unspecified, SourceLocation());
}
-CXXConversionDecl *
-CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
- SourceLocation StartLoc,
- const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isExplicit,
- bool isConstexpr, SourceLocation EndLocation) {
+CXXConversionDecl *CXXConversionDecl::Create(
+ ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
+ const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
+ bool isInline, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind,
+ SourceLocation EndLocation) {
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, isExplicit, isConstexpr,
- EndLocation);
+ return new (C, RD)
+ CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, ES,
+ ConstexprKind, EndLocation);
}
bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
@@ -2857,6 +2961,12 @@ BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) BindingDecl(nullptr, SourceLocation(), nullptr);
}
+ValueDecl *BindingDecl::getDecomposedDecl() const {
+ ExternalASTSource *Source =
+ Decomp.isOffset() ? getASTContext().getExternalSource() : nullptr;
+ return cast_or_null<ValueDecl>(Decomp.get(Source));
+}
+
VarDecl *BindingDecl::getHoldingVar() const {
Expr *B = getBinding();
if (!B)
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
index 08fbed3615790..8ec1dea84df5f 100644
--- a/lib/AST/DeclFriend.cpp
+++ b/lib/AST/DeclFriend.cpp
@@ -1,9 +1,8 @@
//===- DeclFriend.cpp - C++ Friend Declaration AST Node Implementation ----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp
index f74ef9bbb8391..27dbdaab6f30d 100644
--- a/lib/AST/DeclGroup.cpp
+++ b/lib/AST/DeclGroup.cpp
@@ -1,9 +1,8 @@
//===- DeclGroup.cpp - Classes for representing groups of Decls -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 1ed7fc71b025a..bf748fbab8e96 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -1,9 +1,8 @@
//===- DeclObjC.cpp - ObjC Declaration AST Node Implementation ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -1642,7 +1641,7 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
if (!layout.empty()) {
// Order synthesized ivars by their size.
- std::stable_sort(layout.begin(), layout.end());
+ llvm::stable_sort(layout);
unsigned Ix = 0, EIx = layout.size();
if (!data().IvarList) {
data().IvarList = layout[0].Ivar; Ix++;
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
index b77a67cbf38da..af321280d417a 100644
--- a/lib/AST/DeclOpenMP.cpp
+++ b/lib/AST/DeclOpenMP.cpp
@@ -1,9 +1,8 @@
//===--- DeclOpenMP.cpp - Declaration OpenMP AST Node Implementation ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
/// \file
@@ -54,6 +53,49 @@ void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) {
}
//===----------------------------------------------------------------------===//
+// OMPAllocateDecl Implementation.
+//===----------------------------------------------------------------------===//
+
+void OMPAllocateDecl::anchor() { }
+
+OMPAllocateDecl *OMPAllocateDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, ArrayRef<Expr *> VL,
+ ArrayRef<OMPClause *> CL) {
+ OMPAllocateDecl *D = new (
+ C, DC, additionalSizeToAlloc<Expr *, OMPClause *>(VL.size(), CL.size()))
+ OMPAllocateDecl(OMPAllocate, DC, L);
+ D->NumVars = VL.size();
+ D->setVars(VL);
+ D->NumClauses = CL.size();
+ D->setClauses(CL);
+ return D;
+}
+
+OMPAllocateDecl *OMPAllocateDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+ unsigned NVars,
+ unsigned NClauses) {
+ OMPAllocateDecl *D =
+ new (C, ID, additionalSizeToAlloc<Expr *, OMPClause *>(NVars, NClauses))
+ OMPAllocateDecl(OMPAllocate, nullptr, SourceLocation());
+ D->NumVars = NVars;
+ D->NumClauses = NClauses;
+ return D;
+}
+
+void OMPAllocateDecl::setVars(ArrayRef<Expr *> VL) {
+ assert(VL.size() == NumVars &&
+ "Number of variables is not the same as the preallocated buffer");
+ std::uninitialized_copy(VL.begin(), VL.end(), getTrailingObjects<Expr *>());
+}
+
+void OMPAllocateDecl::setClauses(ArrayRef<OMPClause *> CL) {
+ assert(CL.size() == NumClauses &&
+ "Number of variables is not the same as the preallocated buffer");
+ std::uninitialized_copy(CL.begin(), CL.end(),
+ getTrailingObjects<OMPClause *>());
+}
+
+//===----------------------------------------------------------------------===//
// OMPRequiresDecl Implementation.
//===----------------------------------------------------------------------===//
@@ -124,6 +166,66 @@ OMPDeclareReductionDecl::getPrevDeclInScope() const {
}
//===----------------------------------------------------------------------===//
+// OMPDeclareMapperDecl Implementation.
+//===----------------------------------------------------------------------===//
+
+void OMPDeclareMapperDecl::anchor() {}
+
+OMPDeclareMapperDecl *
+OMPDeclareMapperDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ DeclarationName Name, QualType T,
+ DeclarationName VarName,
+ OMPDeclareMapperDecl *PrevDeclInScope) {
+ return new (C, DC) OMPDeclareMapperDecl(OMPDeclareMapper, DC, L, Name, T,
+ VarName, PrevDeclInScope);
+}
+
+OMPDeclareMapperDecl *OMPDeclareMapperDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID,
+ unsigned N) {
+ auto *D = new (C, ID)
+ OMPDeclareMapperDecl(OMPDeclareMapper, /*DC=*/nullptr, SourceLocation(),
+ DeclarationName(), QualType(), DeclarationName(),
+ /*PrevDeclInScope=*/nullptr);
+ if (N) {
+ auto **ClauseStorage = C.Allocate<OMPClause *>(N);
+ D->Clauses = llvm::makeMutableArrayRef<OMPClause *>(ClauseStorage, N);
+ }
+ return D;
+}
+
+/// Creates an array of clauses to this mapper declaration and intializes
+/// them. The space used to store clause pointers is dynamically allocated,
+/// because we do not know the number of clauses when creating
+/// OMPDeclareMapperDecl
+void OMPDeclareMapperDecl::CreateClauses(ASTContext &C,
+ ArrayRef<OMPClause *> CL) {
+ assert(Clauses.empty() && "Number of clauses should be 0 on initialization");
+ size_t NumClauses = CL.size();
+ if (NumClauses) {
+ auto **ClauseStorage = C.Allocate<OMPClause *>(NumClauses);
+ Clauses = llvm::makeMutableArrayRef<OMPClause *>(ClauseStorage, NumClauses);
+ setClauses(CL);
+ }
+}
+
+void OMPDeclareMapperDecl::setClauses(ArrayRef<OMPClause *> CL) {
+ assert(CL.size() == Clauses.size() &&
+ "Number of clauses is not the same as the preallocated buffer");
+ std::uninitialized_copy(CL.begin(), CL.end(), Clauses.data());
+}
+
+OMPDeclareMapperDecl *OMPDeclareMapperDecl::getPrevDeclInScope() {
+ return cast_or_null<OMPDeclareMapperDecl>(
+ PrevDeclInScope.get(getASTContext().getExternalSource()));
+}
+
+const OMPDeclareMapperDecl *OMPDeclareMapperDecl::getPrevDeclInScope() const {
+ return cast_or_null<OMPDeclareMapperDecl>(
+ PrevDeclInScope.get(getASTContext().getExternalSource()));
+}
+
+//===----------------------------------------------------------------------===//
// OMPCapturedExprDecl Implementation.
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 517851f9eeb19..f5c69944034a5 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -1,9 +1,8 @@
//===--- DeclPrinter.cpp - Printing implementation for Decl ASTs ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -16,6 +15,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@@ -100,11 +100,14 @@ namespace {
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
+ void VisitOMPAllocateDecl(OMPAllocateDecl *D);
void VisitOMPRequiresDecl(OMPRequiresDecl *D);
void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
+ void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D);
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
- void printTemplateParameters(const TemplateParameterList *Params);
+ void printTemplateParameters(const TemplateParameterList *Params,
+ bool OmitTemplateKW = false);
void printTemplateArguments(const TemplateArgumentList &Args,
const TemplateParameterList *Params = nullptr);
void prettyPrintAttributes(Decl *D);
@@ -125,6 +128,18 @@ void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy,
Printer.Visit(const_cast<Decl*>(this));
}
+void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
+ bool OmitTemplateKW) const {
+ print(Out, Context, Context.getPrintingPolicy(), OmitTemplateKW);
+}
+
+void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
+ const PrintingPolicy &Policy,
+ bool OmitTemplateKW) const {
+ DeclPrinter Printer(Out, Policy, Context);
+ Printer.printTemplateParameters(this, OmitTemplateKW);
+}
+
static QualType GetBaseType(QualType T) {
// FIXME: This should be on the Type class!
QualType BaseType = T;
@@ -424,7 +439,8 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
// FIXME: Need to be able to tell the DeclPrinter when
const char *Terminator = nullptr;
if (isa<OMPThreadPrivateDecl>(*D) || isa<OMPDeclareReductionDecl>(*D) ||
- isa<OMPRequiresDecl>(*D))
+ isa<OMPDeclareMapperDecl>(*D) || isa<OMPRequiresDecl>(*D) ||
+ isa<OMPAllocateDecl>(*D))
Terminator = nullptr;
else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->hasBody())
Terminator = nullptr;
@@ -550,6 +566,21 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
}
}
+static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out,
+ PrintingPolicy &Policy,
+ unsigned Indentation) {
+ std::string Proto = "explicit";
+ llvm::raw_string_ostream EOut(Proto);
+ if (ES.getExpr()) {
+ EOut << "(";
+ ES.getExpr()->printPretty(EOut, nullptr, Policy, Indentation);
+ EOut << ")";
+ }
+ EOut << " ";
+ EOut.flush();
+ Out << EOut.str();
+}
+
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (!D->getDescribedFunctionTemplate() &&
!D->isFunctionTemplateSpecialization())
@@ -579,11 +610,12 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isInlineSpecified()) Out << "inline ";
if (D->isVirtualAsWritten()) Out << "virtual ";
if (D->isModulePrivate()) Out << "__module_private__ ";
- if (D->isConstexpr() && !D->isExplicitlyDefaulted()) Out << "constexpr ";
- if ((CDecl && CDecl->isExplicitSpecified()) ||
- (ConversionDecl && ConversionDecl->isExplicitSpecified()) ||
- (GuideDecl && GuideDecl->isExplicitSpecified()))
- Out << "explicit ";
+ if (D->isConstexprSpecified() && !D->isExplicitlyDefaulted())
+ Out << "constexpr ";
+ if (D->isConsteval()) Out << "consteval ";
+ ExplicitSpecifier ExplicitSpec = ExplicitSpecifier::getFromDecl(D);
+ if (ExplicitSpec.isSpecified())
+ printExplicitSpecifier(ExplicitSpec, Out, Policy, Indentation);
}
PrintingPolicy SubPolicy(Policy);
@@ -986,25 +1018,35 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Visit(*D->decls_begin());
}
-void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params) {
+void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params,
+ bool OmitTemplateKW) {
assert(Params);
- Out << "template <";
+ if (!OmitTemplateKW)
+ Out << "template ";
+ Out << '<';
+
+ bool NeedComma = false;
+ for (const Decl *Param : *Params) {
+ if (Param->isImplicit())
+ continue;
- for (unsigned i = 0, e = Params->size(); i != e; ++i) {
- if (i != 0)
+ if (NeedComma)
Out << ", ";
+ else
+ NeedComma = true;
- const Decl *Param = Params->getParam(i);
if (auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
if (TTP->wasDeclaredWithTypename())
- Out << "typename ";
+ Out << "typename";
else
- Out << "class ";
+ Out << "class";
if (TTP->isParameterPack())
- Out << "...";
+ Out << " ...";
+ else if (!TTP->getName().empty())
+ Out << ' ';
Out << *TTP;
@@ -1029,7 +1071,9 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params) {
}
}
- Out << "> ";
+ Out << '>';
+ if (!OmitTemplateKW)
+ Out << ' ';
}
void DeclPrinter::printTemplateArguments(const TemplateArgumentList &Args,
@@ -1079,8 +1123,13 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
if (TTP->isParameterPack())
Out << "...";
Out << D->getName();
- } else {
- Visit(D->getTemplatedDecl());
+ } else if (auto *TD = D->getTemplatedDecl())
+ Visit(TD);
+ else if (const auto *Concept = dyn_cast<ConceptDecl>(D)) {
+ Out << "concept " << Concept->getName() << " = " ;
+ Concept->getConstraintExpr()->printPretty(Out, nullptr, Policy,
+ Indentation);
+ Out << ";";
}
}
@@ -1389,6 +1438,13 @@ void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
/// PrintObjCPropertyDecl - print a property declaration.
///
+/// Print attributes in the following order:
+/// - class
+/// - nonatomic | atomic
+/// - assign | retain | strong | copy | weak | unsafe_unretained
+/// - readwrite | readonly
+/// - getter & setter
+/// - nullability
void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Required)
Out << "@required\n";
@@ -1400,58 +1456,69 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
Out << "@property";
if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) {
bool first = true;
- Out << " (";
- if (PDecl->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_readonly) {
- Out << (first ? ' ' : ',') << "readonly";
+ Out << "(";
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_class) {
+ Out << (first ? "" : ", ") << "class";
first = false;
}
- if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
- Out << (first ? ' ' : ',') << "getter = ";
- PDecl->getGetterName().print(Out);
+ if (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_nonatomic) {
+ Out << (first ? "" : ", ") << "nonatomic";
first = false;
}
- if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
- Out << (first ? ' ' : ',') << "setter = ";
- PDecl->getSetterName().print(Out);
+ if (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_atomic) {
+ Out << (first ? "" : ", ") << "atomic";
first = false;
}
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) {
- Out << (first ? ' ' : ',') << "assign";
- first = false;
- }
-
- if (PDecl->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_readwrite) {
- Out << (first ? ' ' : ',') << "readwrite";
+ Out << (first ? "" : ", ") << "assign";
first = false;
}
-
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) {
- Out << (first ? ' ' : ',') << "retain";
+ Out << (first ? "" : ", ") << "retain";
first = false;
}
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_strong) {
- Out << (first ? ' ' : ',') << "strong";
+ Out << (first ? "" : ", ") << "strong";
first = false;
}
-
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) {
- Out << (first ? ' ' : ',') << "copy";
+ Out << (first ? "" : ", ") << "copy";
+ first = false;
+ }
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) {
+ Out << (first ? "" : ", ") << "weak";
+ first = false;
+ }
+ if (PDecl->getPropertyAttributes()
+ & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) {
+ Out << (first ? "" : ", ") << "unsafe_unretained";
first = false;
}
if (PDecl->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_nonatomic) {
- Out << (first ? ' ' : ',') << "nonatomic";
+ ObjCPropertyDecl::OBJC_PR_readwrite) {
+ Out << (first ? "" : ", ") << "readwrite";
first = false;
}
if (PDecl->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_atomic) {
- Out << (first ? ' ' : ',') << "atomic";
+ ObjCPropertyDecl::OBJC_PR_readonly) {
+ Out << (first ? "" : ", ") << "readonly";
+ first = false;
+ }
+
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
+ Out << (first ? "" : ", ") << "getter = ";
+ PDecl->getGetterName().print(Out);
+ first = false;
+ }
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
+ Out << (first ? "" : ", ") << "setter = ";
+ PDecl->getSetterName().print(Out);
first = false;
}
@@ -1461,25 +1528,24 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
if (*nullability == NullabilityKind::Unspecified &&
(PDecl->getPropertyAttributes() &
ObjCPropertyDecl::OBJC_PR_null_resettable)) {
- Out << (first ? ' ' : ',') << "null_resettable";
+ Out << (first ? "" : ", ") << "null_resettable";
} else {
- Out << (first ? ' ' : ',')
+ Out << (first ? "" : ", ")
<< getNullabilitySpelling(*nullability, true);
}
first = false;
}
}
- if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_class) {
- Out << (first ? ' ' : ',') << "class";
- first = false;
- }
-
(void) first; // Silence dead store warning due to idiomatic code.
- Out << " )";
+ Out << ")";
}
- Out << ' ' << PDecl->getASTContext().getUnqualifiedObjCPointerType(T).
- getAsString(Policy) << ' ' << *PDecl;
+ std::string TypeStr = PDecl->getASTContext().getUnqualifiedObjCPointerType(T).
+ getAsString(Policy);
+ Out << ' ' << TypeStr;
+ if (!StringRef(TypeStr).endswith("*"))
+ Out << ' ';
+ Out << *PDecl;
if (Policy.PolishForDeclaration)
Out << ';';
}
@@ -1546,6 +1612,26 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
}
}
+void DeclPrinter::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
+ Out << "#pragma omp allocate";
+ if (!D->varlist_empty()) {
+ for (OMPAllocateDecl::varlist_iterator I = D->varlist_begin(),
+ E = D->varlist_end();
+ I != E; ++I) {
+ Out << (I == D->varlist_begin() ? '(' : ',');
+ NamedDecl *ND = cast<DeclRefExpr>(*I)->getDecl();
+ ND->printQualifiedName(Out);
+ }
+ Out << ")";
+ }
+ if (!D->clauselist_empty()) {
+ Out << " ";
+ OMPClausePrinter Printer(Out, Policy);
+ for (OMPClause *C : D->clauselists())
+ Printer.Visit(C);
+ }
+}
+
void DeclPrinter::VisitOMPRequiresDecl(OMPRequiresDecl *D) {
Out << "#pragma omp requires ";
if (!D->clauselist_empty()) {
@@ -1559,14 +1645,8 @@ void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
if (!D->isInvalidDecl()) {
Out << "#pragma omp declare reduction (";
if (D->getDeclName().getNameKind() == DeclarationName::CXXOperatorName) {
- static const char *const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
- nullptr,
-#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
- Spelling,
-#include "clang/Basic/OperatorKinds.def"
- };
const char *OpName =
- OperatorNames[D->getDeclName().getCXXOverloadedOperator()];
+ getOperatorSpelling(D->getDeclName().getCXXOverloadedOperator());
assert(OpName && "not an overloaded operator");
Out << OpName;
} else {
@@ -1598,6 +1678,25 @@ void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
}
}
+void DeclPrinter::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
+ if (!D->isInvalidDecl()) {
+ Out << "#pragma omp declare mapper (";
+ D->printName(Out);
+ Out << " : ";
+ D->getType().print(Out, Policy);
+ Out << " ";
+ Out << D->getVarName();
+ Out << ")";
+ if (!D->clauselist_empty()) {
+ OMPClausePrinter Printer(Out, Policy);
+ for (auto *C : D->clauselists()) {
+ Out << " ";
+ Printer.Visit(C);
+ }
+ }
+ }
+}
+
void DeclPrinter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
D->getInit()->printPretty(Out, nullptr, Policy, Indentation);
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 76f29dac1647d..40c39c845db63 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -1,9 +1,8 @@
//===- DeclTemplate.cpp - Template Declaration AST Node Implementation ----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -688,22 +687,20 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
return new (Mem) TemplateArgumentList(Args);
}
-FunctionTemplateSpecializationInfo *
-FunctionTemplateSpecializationInfo::Create(ASTContext &C, FunctionDecl *FD,
- FunctionTemplateDecl *Template,
- TemplateSpecializationKind TSK,
- const TemplateArgumentList *TemplateArgs,
- const TemplateArgumentListInfo *TemplateArgsAsWritten,
- SourceLocation POI) {
+FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
+ ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
+ TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs,
+ const TemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation POI,
+ MemberSpecializationInfo *MSInfo) {
const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
if (TemplateArgsAsWritten)
ArgsAsWritten = ASTTemplateArgumentListInfo::Create(C,
*TemplateArgsAsWritten);
- return new (C) FunctionTemplateSpecializationInfo(FD, Template, TSK,
- TemplateArgs,
- ArgsAsWritten,
- POI);
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<MemberSpecializationInfo *>(MSInfo ? 1 : 0));
+ return new (Mem) FunctionTemplateSpecializationInfo(
+ FD, Template, TSK, TemplateArgs, ArgsAsWritten, POI, MSInfo);
}
//===----------------------------------------------------------------------===//
@@ -825,6 +822,26 @@ ClassTemplateSpecializationDecl::getSourceRange() const {
}
//===----------------------------------------------------------------------===//
+// ConceptDecl Implementation
+//===----------------------------------------------------------------------===//
+ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params,
+ Expr *ConstraintExpr) {
+ AdoptTemplateParameterList(Params, DC);
+ return new (C, DC) ConceptDecl(DC, L, Name, Params, ConstraintExpr);
+}
+
+ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ ConceptDecl *Result = new (C, ID) ConceptDecl(nullptr, SourceLocation(),
+ DeclarationName(),
+ nullptr, nullptr);
+
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
// ClassTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
void ClassTemplatePartialSpecializationDecl::anchor() {}
@@ -936,7 +953,7 @@ ClassScopeFunctionSpecializationDecl *
ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
return new (C, ID) ClassScopeFunctionSpecializationDecl(
- nullptr, SourceLocation(), nullptr, false, TemplateArgumentListInfo());
+ nullptr, SourceLocation(), nullptr, nullptr);
}
//===----------------------------------------------------------------------===//
@@ -957,6 +974,7 @@ VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, DeclarationName Name,
TemplateParameterList *Params,
VarDecl *Decl) {
+ AdoptTemplateParameterList(Params, DC);
return new (C, DC) VarTemplateDecl(C, DC, L, Name, Params, Decl);
}
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index f2c152f918ebf..fe69c71aa3ddf 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -1,9 +1,8 @@
//===- DeclarationName.cpp - Declaration names implementation -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -162,13 +161,7 @@ void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) {
return;
case DeclarationName::CXXOperatorName: {
- static const char *const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
- nullptr,
-#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
- Spelling,
-#include "clang/Basic/OperatorKinds.def"
- };
- const char *OpName = OperatorNames[getCXXOverloadedOperator()];
+ const char *OpName = getOperatorSpelling(getCXXOverloadedOperator());
assert(OpName && "not an overloaded operator");
OS << "operator";
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 7cdd3b2c2a30c..6ef77b8aee684 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1,9 +1,8 @@
//===--- Expr.cpp - Expression AST Node Implementation --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -11,13 +10,14 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Expr.h"
+#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
-#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
@@ -229,6 +229,133 @@ SourceLocation Expr::getExprLoc() const {
// Primary Expressions.
//===----------------------------------------------------------------------===//
+static void AssertResultStorageKind(ConstantExpr::ResultStorageKind Kind) {
+ assert((Kind == ConstantExpr::RSK_APValue ||
+ Kind == ConstantExpr::RSK_Int64 || Kind == ConstantExpr::RSK_None) &&
+ "Invalid StorageKind Value");
+}
+
+ConstantExpr::ResultStorageKind
+ConstantExpr::getStorageKind(const APValue &Value) {
+ switch (Value.getKind()) {
+ case APValue::None:
+ case APValue::Indeterminate:
+ return ConstantExpr::RSK_None;
+ case APValue::Int:
+ if (!Value.getInt().needsCleanup())
+ return ConstantExpr::RSK_Int64;
+ LLVM_FALLTHROUGH;
+ default:
+ return ConstantExpr::RSK_APValue;
+ }
+}
+
+ConstantExpr::ResultStorageKind
+ConstantExpr::getStorageKind(const Type *T, const ASTContext &Context) {
+ if (T->isIntegralOrEnumerationType() && Context.getTypeInfo(T).Width <= 64)
+ return ConstantExpr::RSK_Int64;
+ return ConstantExpr::RSK_APValue;
+}
+
+void ConstantExpr::DefaultInit(ResultStorageKind StorageKind) {
+ ConstantExprBits.ResultKind = StorageKind;
+ ConstantExprBits.APValueKind = APValue::None;
+ ConstantExprBits.HasCleanup = false;
+ if (StorageKind == ConstantExpr::RSK_APValue)
+ ::new (getTrailingObjects<APValue>()) APValue();
+}
+
+ConstantExpr::ConstantExpr(Expr *subexpr, ResultStorageKind StorageKind)
+ : FullExpr(ConstantExprClass, subexpr) {
+ DefaultInit(StorageKind);
+}
+
+ConstantExpr *ConstantExpr::Create(const ASTContext &Context, Expr *E,
+ ResultStorageKind StorageKind) {
+ assert(!isa<ConstantExpr>(E));
+ AssertResultStorageKind(StorageKind);
+ unsigned Size = totalSizeToAlloc<APValue, uint64_t>(
+ StorageKind == ConstantExpr::RSK_APValue,
+ StorageKind == ConstantExpr::RSK_Int64);
+ void *Mem = Context.Allocate(Size, alignof(ConstantExpr));
+ ConstantExpr *Self = new (Mem) ConstantExpr(E, StorageKind);
+ return Self;
+}
+
+ConstantExpr *ConstantExpr::Create(const ASTContext &Context, Expr *E,
+ const APValue &Result) {
+ ResultStorageKind StorageKind = getStorageKind(Result);
+ ConstantExpr *Self = Create(Context, E, StorageKind);
+ Self->SetResult(Result, Context);
+ return Self;
+}
+
+ConstantExpr::ConstantExpr(ResultStorageKind StorageKind, EmptyShell Empty)
+ : FullExpr(ConstantExprClass, Empty) {
+ DefaultInit(StorageKind);
+}
+
+ConstantExpr *ConstantExpr::CreateEmpty(const ASTContext &Context,
+ ResultStorageKind StorageKind,
+ EmptyShell Empty) {
+ AssertResultStorageKind(StorageKind);
+ unsigned Size = totalSizeToAlloc<APValue, uint64_t>(
+ StorageKind == ConstantExpr::RSK_APValue,
+ StorageKind == ConstantExpr::RSK_Int64);
+ void *Mem = Context.Allocate(Size, alignof(ConstantExpr));
+ ConstantExpr *Self = new (Mem) ConstantExpr(StorageKind, Empty);
+ return Self;
+}
+
+void ConstantExpr::MoveIntoResult(APValue &Value, const ASTContext &Context) {
+ assert(getStorageKind(Value) == ConstantExprBits.ResultKind &&
+ "Invalid storage for this value kind");
+ ConstantExprBits.APValueKind = Value.getKind();
+ switch (ConstantExprBits.ResultKind) {
+ case RSK_None:
+ return;
+ case RSK_Int64:
+ Int64Result() = *Value.getInt().getRawData();
+ ConstantExprBits.BitWidth = Value.getInt().getBitWidth();
+ ConstantExprBits.IsUnsigned = Value.getInt().isUnsigned();
+ return;
+ case RSK_APValue:
+ if (!ConstantExprBits.HasCleanup && Value.needsCleanup()) {
+ ConstantExprBits.HasCleanup = true;
+ Context.addDestruction(&APValueResult());
+ }
+ APValueResult() = std::move(Value);
+ return;
+ }
+ llvm_unreachable("Invalid ResultKind Bits");
+}
+
+llvm::APSInt ConstantExpr::getResultAsAPSInt() const {
+ switch (ConstantExprBits.ResultKind) {
+ case ConstantExpr::RSK_APValue:
+ return APValueResult().getInt();
+ case ConstantExpr::RSK_Int64:
+ return llvm::APSInt(llvm::APInt(ConstantExprBits.BitWidth, Int64Result()),
+ ConstantExprBits.IsUnsigned);
+ default:
+ llvm_unreachable("invalid Accessor");
+ }
+}
+
+APValue ConstantExpr::getAPValueResult() const {
+ switch (ConstantExprBits.ResultKind) {
+ case ConstantExpr::RSK_APValue:
+ return APValueResult();
+ case ConstantExpr::RSK_Int64:
+ return APValue(
+ llvm::APSInt(llvm::APInt(ConstantExprBits.BitWidth, Int64Result()),
+ ConstantExprBits.IsUnsigned));
+ case ConstantExpr::RSK_None:
+ return APValue();
+ }
+ llvm_unreachable("invalid ResultKind");
+}
+
/// Compute the type-, value-, and instantiation-dependence of a
/// declaration reference
/// based on the declaration being referenced.
@@ -344,7 +471,8 @@ void DeclRefExpr::computeDependence(const ASTContext &Ctx) {
DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
bool RefersToEnclosingVariableOrCapture, QualType T,
ExprValueKind VK, SourceLocation L,
- const DeclarationNameLoc &LocInfo)
+ const DeclarationNameLoc &LocInfo,
+ NonOdrUseReason NOUR)
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
D(D), DNLoc(LocInfo) {
DeclRefExprBits.HasQualifier = false;
@@ -353,6 +481,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
DeclRefExprBits.HadMultipleCandidates = false;
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
RefersToEnclosingVariableOrCapture;
+ DeclRefExprBits.NonOdrUseReason = NOUR;
DeclRefExprBits.Loc = L;
computeDependence(Ctx);
}
@@ -363,7 +492,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
bool RefersToEnclosingVariableOrCapture,
const DeclarationNameInfo &NameInfo, NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs,
- QualType T, ExprValueKind VK)
+ QualType T, ExprValueKind VK, NonOdrUseReason NOUR)
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
D(D), DNLoc(NameInfo.getInfo()) {
DeclRefExprBits.Loc = NameInfo.getLoc();
@@ -384,6 +513,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
= (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0;
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
RefersToEnclosingVariableOrCapture;
+ DeclRefExprBits.NonOdrUseReason = NOUR;
if (TemplateArgs) {
bool Dependent = false;
bool InstantiationDependent = false;
@@ -405,30 +535,27 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc,
- ValueDecl *D,
+ SourceLocation TemplateKWLoc, ValueDecl *D,
bool RefersToEnclosingVariableOrCapture,
- SourceLocation NameLoc,
- QualType T,
- ExprValueKind VK,
- NamedDecl *FoundD,
- const TemplateArgumentListInfo *TemplateArgs) {
+ SourceLocation NameLoc, QualType T,
+ ExprValueKind VK, NamedDecl *FoundD,
+ const TemplateArgumentListInfo *TemplateArgs,
+ NonOdrUseReason NOUR) {
return Create(Context, QualifierLoc, TemplateKWLoc, D,
RefersToEnclosingVariableOrCapture,
DeclarationNameInfo(D->getDeclName(), NameLoc),
- T, VK, FoundD, TemplateArgs);
+ T, VK, FoundD, TemplateArgs, NOUR);
}
DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc,
- ValueDecl *D,
+ SourceLocation TemplateKWLoc, ValueDecl *D,
bool RefersToEnclosingVariableOrCapture,
const DeclarationNameInfo &NameInfo,
- QualType T,
- ExprValueKind VK,
+ QualType T, ExprValueKind VK,
NamedDecl *FoundD,
- const TemplateArgumentListInfo *TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs,
+ NonOdrUseReason NOUR) {
// Filter out cases where the found Decl is the same as the value refenenced.
if (D == FoundD)
FoundD = nullptr;
@@ -443,8 +570,8 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
void *Mem = Context.Allocate(Size, alignof(DeclRefExpr));
return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D,
- RefersToEnclosingVariableOrCapture,
- NameInfo, FoundD, TemplateArgs, T, VK);
+ RefersToEnclosingVariableOrCapture, NameInfo,
+ FoundD, TemplateArgs, T, VK, NOUR);
}
DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context,
@@ -840,7 +967,7 @@ FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V,
FloatingLiteral::FloatingLiteral(const ASTContext &C, EmptyShell Empty)
: Expr(FloatingLiteralClass, Empty) {
- setRawSemantics(IEEEhalf);
+ setRawSemantics(llvm::APFloatBase::S_IEEEhalf);
FloatingLiteralBits.IsExact = false;
}
@@ -855,41 +982,6 @@ FloatingLiteral::Create(const ASTContext &C, EmptyShell Empty) {
return new (C) FloatingLiteral(C, Empty);
}
-const llvm::fltSemantics &FloatingLiteral::getSemantics() const {
- switch(FloatingLiteralBits.Semantics) {
- case IEEEhalf:
- return llvm::APFloat::IEEEhalf();
- case IEEEsingle:
- return llvm::APFloat::IEEEsingle();
- case IEEEdouble:
- return llvm::APFloat::IEEEdouble();
- case x87DoubleExtended:
- return llvm::APFloat::x87DoubleExtended();
- case IEEEquad:
- return llvm::APFloat::IEEEquad();
- case PPCDoubleDouble:
- return llvm::APFloat::PPCDoubleDouble();
- }
- llvm_unreachable("Unrecognised floating semantics");
-}
-
-void FloatingLiteral::setSemantics(const llvm::fltSemantics &Sem) {
- if (&Sem == &llvm::APFloat::IEEEhalf())
- FloatingLiteralBits.Semantics = IEEEhalf;
- else if (&Sem == &llvm::APFloat::IEEEsingle())
- FloatingLiteralBits.Semantics = IEEEsingle;
- else if (&Sem == &llvm::APFloat::IEEEdouble())
- FloatingLiteralBits.Semantics = IEEEdouble;
- else if (&Sem == &llvm::APFloat::x87DoubleExtended())
- FloatingLiteralBits.Semantics = x87DoubleExtended;
- else if (&Sem == &llvm::APFloat::IEEEquad())
- FloatingLiteralBits.Semantics = IEEEquad;
- else if (&Sem == &llvm::APFloat::PPCDoubleDouble())
- FloatingLiteralBits.Semantics = PPCDoubleDouble;
- else
- llvm_unreachable("Unknown floating semantics");
-}
-
/// getValueAsApproximateDouble - This returns the value as an inaccurate
/// double. Note that this may cause loss of precision, but is useful for
/// debugging dumps, etc.
@@ -1359,6 +1451,8 @@ Decl *Expr::getReferencedDeclOfCallee() {
return DRE->getDecl();
if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE))
return ME->getMemberDecl();
+ if (auto *BE = dyn_cast<BlockExpr>(CEE))
+ return BE->getBlockDecl();
return nullptr;
}
@@ -1536,29 +1630,46 @@ UnaryExprOrTypeTraitExpr::UnaryExprOrTypeTraitExpr(
}
}
+MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
+ ValueDecl *MemberDecl,
+ const DeclarationNameInfo &NameInfo, QualType T,
+ ExprValueKind VK, ExprObjectKind OK,
+ NonOdrUseReason NOUR)
+ : Expr(MemberExprClass, T, VK, OK, Base->isTypeDependent(),
+ Base->isValueDependent(), Base->isInstantiationDependent(),
+ Base->containsUnexpandedParameterPack()),
+ Base(Base), MemberDecl(MemberDecl), MemberDNLoc(NameInfo.getInfo()),
+ MemberLoc(NameInfo.getLoc()) {
+ assert(!NameInfo.getName() ||
+ MemberDecl->getDeclName() == NameInfo.getName());
+ MemberExprBits.IsArrow = IsArrow;
+ MemberExprBits.HasQualifierOrFoundDecl = false;
+ MemberExprBits.HasTemplateKWAndArgsInfo = false;
+ MemberExprBits.HadMultipleCandidates = false;
+ MemberExprBits.NonOdrUseReason = NOUR;
+ MemberExprBits.OperatorLoc = OperatorLoc;
+}
+
MemberExpr *MemberExpr::Create(
- const ASTContext &C, Expr *base, bool isarrow, SourceLocation OperatorLoc,
+ const ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
- ValueDecl *memberdecl, DeclAccessPair founddecl,
- DeclarationNameInfo nameinfo, const TemplateArgumentListInfo *targs,
- QualType ty, ExprValueKind vk, ExprObjectKind ok) {
-
- bool hasQualOrFound = (QualifierLoc ||
- founddecl.getDecl() != memberdecl ||
- founddecl.getAccess() != memberdecl->getAccess());
-
- bool HasTemplateKWAndArgsInfo = targs || TemplateKWLoc.isValid();
+ ValueDecl *MemberDecl, DeclAccessPair FoundDecl,
+ DeclarationNameInfo NameInfo, const TemplateArgumentListInfo *TemplateArgs,
+ QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) {
+ bool HasQualOrFound = QualifierLoc || FoundDecl.getDecl() != MemberDecl ||
+ FoundDecl.getAccess() != MemberDecl->getAccess();
+ bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid();
std::size_t Size =
totalSizeToAlloc<MemberExprNameQualifier, ASTTemplateKWAndArgsInfo,
- TemplateArgumentLoc>(hasQualOrFound ? 1 : 0,
- HasTemplateKWAndArgsInfo ? 1 : 0,
- targs ? targs->size() : 0);
+ TemplateArgumentLoc>(
+ HasQualOrFound ? 1 : 0, HasTemplateKWAndArgsInfo ? 1 : 0,
+ TemplateArgs ? TemplateArgs->size() : 0);
void *Mem = C.Allocate(Size, alignof(MemberExpr));
- MemberExpr *E = new (Mem)
- MemberExpr(base, isarrow, OperatorLoc, memberdecl, nameinfo, ty, vk, ok);
+ MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl,
+ NameInfo, T, VK, OK, NOUR);
- if (hasQualOrFound) {
+ if (HasQualOrFound) {
// FIXME: Wrong. We should be looking at the member declaration we found.
if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) {
E->setValueDependent(true);
@@ -1574,19 +1685,20 @@ MemberExpr *MemberExpr::Create(
MemberExprNameQualifier *NQ =
E->getTrailingObjects<MemberExprNameQualifier>();
NQ->QualifierLoc = QualifierLoc;
- NQ->FoundDecl = founddecl;
+ NQ->FoundDecl = FoundDecl;
}
E->MemberExprBits.HasTemplateKWAndArgsInfo =
- (targs || TemplateKWLoc.isValid());
+ TemplateArgs || TemplateKWLoc.isValid();
- if (targs) {
+ if (TemplateArgs) {
bool Dependent = false;
bool InstantiationDependent = false;
bool ContainsUnexpandedParameterPack = false;
E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
- TemplateKWLoc, *targs, E->getTrailingObjects<TemplateArgumentLoc>(),
- Dependent, InstantiationDependent, ContainsUnexpandedParameterPack);
+ TemplateKWLoc, *TemplateArgs,
+ E->getTrailingObjects<TemplateArgumentLoc>(), Dependent,
+ InstantiationDependent, ContainsUnexpandedParameterPack);
if (InstantiationDependent)
E->setInstantiationDependent(true);
} else if (TemplateKWLoc.isValid()) {
@@ -1597,6 +1709,22 @@ MemberExpr *MemberExpr::Create(
return E;
}
+MemberExpr *MemberExpr::CreateEmpty(const ASTContext &Context,
+ bool HasQualifier, bool HasFoundDecl,
+ bool HasTemplateKWAndArgsInfo,
+ unsigned NumTemplateArgs) {
+ assert((!NumTemplateArgs || HasTemplateKWAndArgsInfo) &&
+ "template args but no template arg info?");
+ bool HasQualOrFound = HasQualifier || HasFoundDecl;
+ std::size_t Size =
+ totalSizeToAlloc<MemberExprNameQualifier, ASTTemplateKWAndArgsInfo,
+ TemplateArgumentLoc>(HasQualOrFound ? 1 : 0,
+ HasTemplateKWAndArgsInfo ? 1 : 0,
+ NumTemplateArgs);
+ void *Mem = Context.Allocate(Size, alignof(MemberExpr));
+ return new (Mem) MemberExpr(EmptyShell());
+}
+
SourceLocation MemberExpr::getBeginLoc() const {
if (isImplicitAccess()) {
if (hasQualifier())
@@ -1677,7 +1805,7 @@ bool CastExpr::CastConsistency() const {
auto Ty = getType();
auto SETy = getSubExpr()->getType();
assert(getValueKindForType(Ty) == Expr::getValueKindForType(SETy));
- if (isRValue()) {
+ if (/*isRValue()*/ !Ty->getPointeeType().isNull()) {
Ty = Ty->getPointeeType();
SETy = SETy->getPointeeType();
}
@@ -1717,6 +1845,8 @@ bool CastExpr::CastConsistency() const {
case CK_ZeroToOCLOpaqueType:
case CK_IntToOCLSampler:
case CK_FixedPointCast:
+ case CK_FixedPointToIntegral:
+ case CK_IntegralToFixedPoint:
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
goto CheckNoBasePath;
@@ -1732,6 +1862,7 @@ bool CastExpr::CastConsistency() const {
case CK_FloatingComplexToBoolean:
case CK_IntegralComplexToBoolean:
case CK_LValueBitCast: // -> bool&
+ case CK_LValueToRValueBitCast:
case CK_UserDefinedConversion: // operator bool()
case CK_BuiltinFnToFnPtr:
case CK_FixedPointToBoolean:
@@ -1847,6 +1978,11 @@ ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
+ // Per C++ [conv.lval]p3, lvalue-to-rvalue conversions on class and
+ // std::nullptr_t have special semantics not captured by CK_LValueToRValue.
+ assert((Kind != CK_LValueToRValue ||
+ !(T->isNullPtrType() || T->getAsCXXRecordDecl())) &&
+ "invalid type for lvalue-to-rvalue conversion");
ImplicitCastExpr *E =
new (Buffer) ImplicitCastExpr(T, Kind, Operand, PathSize, VK);
if (PathSize)
@@ -1989,6 +2125,91 @@ bool BinaryOperator::isNullPointerArithmeticExtension(ASTContext &Ctx,
return true;
}
+
+static QualType getDecayedSourceLocExprType(const ASTContext &Ctx,
+ SourceLocExpr::IdentKind Kind) {
+ switch (Kind) {
+ case SourceLocExpr::File:
+ case SourceLocExpr::Function: {
+ QualType ArrTy = Ctx.getStringLiteralArrayType(Ctx.CharTy, 0);
+ return Ctx.getPointerType(ArrTy->getAsArrayTypeUnsafe()->getElementType());
+ }
+ case SourceLocExpr::Line:
+ case SourceLocExpr::Column:
+ return Ctx.UnsignedIntTy;
+ }
+ llvm_unreachable("unhandled case");
+}
+
+SourceLocExpr::SourceLocExpr(const ASTContext &Ctx, IdentKind Kind,
+ SourceLocation BLoc, SourceLocation RParenLoc,
+ DeclContext *ParentContext)
+ : Expr(SourceLocExprClass, getDecayedSourceLocExprType(Ctx, Kind),
+ VK_RValue, OK_Ordinary, false, false, false, false),
+ BuiltinLoc(BLoc), RParenLoc(RParenLoc), ParentContext(ParentContext) {
+ SourceLocExprBits.Kind = Kind;
+}
+
+StringRef SourceLocExpr::getBuiltinStr() const {
+ switch (getIdentKind()) {
+ case File:
+ return "__builtin_FILE";
+ case Function:
+ return "__builtin_FUNCTION";
+ case Line:
+ return "__builtin_LINE";
+ case Column:
+ return "__builtin_COLUMN";
+ }
+ llvm_unreachable("unexpected IdentKind!");
+}
+
+APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx,
+ const Expr *DefaultExpr) const {
+ SourceLocation Loc;
+ const DeclContext *Context;
+
+ std::tie(Loc,
+ Context) = [&]() -> std::pair<SourceLocation, const DeclContext *> {
+ if (auto *DIE = dyn_cast_or_null<CXXDefaultInitExpr>(DefaultExpr))
+ return {DIE->getUsedLocation(), DIE->getUsedContext()};
+ if (auto *DAE = dyn_cast_or_null<CXXDefaultArgExpr>(DefaultExpr))
+ return {DAE->getUsedLocation(), DAE->getUsedContext()};
+ return {this->getLocation(), this->getParentContext()};
+ }();
+
+ PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc(
+ Ctx.getSourceManager().getExpansionRange(Loc).getEnd());
+
+ auto MakeStringLiteral = [&](StringRef Tmp) {
+ using LValuePathEntry = APValue::LValuePathEntry;
+ StringLiteral *Res = Ctx.getPredefinedStringLiteralFromCache(Tmp);
+ // Decay the string to a pointer to the first character.
+ LValuePathEntry Path[1] = {LValuePathEntry::ArrayIndex(0)};
+ return APValue(Res, CharUnits::Zero(), Path, /*OnePastTheEnd=*/false);
+ };
+
+ switch (getIdentKind()) {
+ case SourceLocExpr::File:
+ return MakeStringLiteral(PLoc.getFilename());
+ case SourceLocExpr::Function: {
+ const Decl *CurDecl = dyn_cast_or_null<Decl>(Context);
+ return MakeStringLiteral(
+ CurDecl ? PredefinedExpr::ComputeName(PredefinedExpr::Function, CurDecl)
+ : std::string(""));
+ }
+ case SourceLocExpr::Line:
+ case SourceLocExpr::Column: {
+ llvm::APSInt IntVal(Ctx.getIntWidth(Ctx.UnsignedIntTy),
+ /*isUnsigned=*/true);
+ IntVal = getIdentKind() == SourceLocExpr::Line ? PLoc.getLine()
+ : PLoc.getColumn();
+ return APValue(IntVal);
+ }
+ }
+ llvm_unreachable("unhandled case");
+}
+
InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc)
: Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
@@ -2082,11 +2303,11 @@ bool InitListExpr::isTransparent() const {
bool InitListExpr::isIdiomaticZeroInitializer(const LangOptions &LangOpts) const {
assert(isSyntacticForm() && "only test syntactic form as zero initializer");
- if (LangOpts.CPlusPlus || getNumInits() != 1) {
+ if (LangOpts.CPlusPlus || getNumInits() != 1 || !getInit(0)) {
return false;
}
- const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(getInit(0));
+ const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(getInit(0)->IgnoreImplicit());
return Lit && Lit->getValue() == 0;
}
@@ -2256,12 +2477,13 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
// If only one of the LHS or RHS is a warning, the operator might
// be being used for control flow. Only warn if both the LHS and
// RHS are warnings.
- const ConditionalOperator *Exp = cast<ConditionalOperator>(this);
- if (!Exp->getRHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx))
- return false;
- if (!Exp->getLHS())
- return true;
- return Exp->getLHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
+ const auto *Exp = cast<ConditionalOperator>(this);
+ return Exp->getLHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx) &&
+ Exp->getRHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
+ }
+ case BinaryConditionalOperatorClass: {
+ const auto *Exp = cast<BinaryConditionalOperator>(this);
+ return Exp->getFalseExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
}
case MemberExprClass:
@@ -2557,205 +2779,197 @@ QualType Expr::findBoundMemberType(const Expr *expr) {
return QualType();
}
-Expr* Expr::IgnoreParens() {
- Expr* E = this;
- while (true) {
- if (ParenExpr* P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
- if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- }
- if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
- }
- if (ChooseExpr* P = dyn_cast<ChooseExpr>(E)) {
- if (!P->isConditionDependent()) {
- E = P->getChosenSubExpr();
- continue;
- }
- }
- if (ConstantExpr *CE = dyn_cast<ConstantExpr>(E)) {
- E = CE->getSubExpr();
- continue;
- }
- return E;
- }
+static Expr *IgnoreImpCastsSingleStep(Expr *E) {
+ if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+ return ICE->getSubExpr();
+
+ if (auto *FE = dyn_cast<FullExpr>(E))
+ return FE->getSubExpr();
+
+ return E;
}
-/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr
-/// or CastExprs or ImplicitCastExprs, returning their operand.
-Expr *Expr::IgnoreParenCasts() {
- Expr *E = this;
- while (true) {
- E = E->IgnoreParens();
- if (CastExpr *P = dyn_cast<CastExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
- if (MaterializeTemporaryExpr *Materialize
- = dyn_cast<MaterializeTemporaryExpr>(E)) {
- E = Materialize->GetTemporaryExpr();
- continue;
- }
- if (SubstNonTypeTemplateParmExpr *NTTP
- = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
- E = NTTP->getReplacement();
- continue;
- }
- if (FullExpr *FE = dyn_cast<FullExpr>(E)) {
- E = FE->getSubExpr();
- continue;
- }
- return E;
- }
+static Expr *IgnoreImpCastsExtraSingleStep(Expr *E) {
+ // FIXME: Skip MaterializeTemporaryExpr and SubstNonTypeTemplateParmExpr in
+ // addition to what IgnoreImpCasts() skips to account for the current
+ // behaviour of IgnoreParenImpCasts().
+ Expr *SubE = IgnoreImpCastsSingleStep(E);
+ if (SubE != E)
+ return SubE;
+
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
+ return MTE->GetTemporaryExpr();
+
+ if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
+ return NTTP->getReplacement();
+
+ return E;
}
-Expr *Expr::IgnoreCasts() {
- Expr *E = this;
- while (true) {
- if (CastExpr *P = dyn_cast<CastExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
- if (MaterializeTemporaryExpr *Materialize
- = dyn_cast<MaterializeTemporaryExpr>(E)) {
- E = Materialize->GetTemporaryExpr();
- continue;
- }
- if (SubstNonTypeTemplateParmExpr *NTTP
- = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
- E = NTTP->getReplacement();
- continue;
- }
- if (FullExpr *FE = dyn_cast<FullExpr>(E)) {
- E = FE->getSubExpr();
- continue;
- }
- return E;
+static Expr *IgnoreCastsSingleStep(Expr *E) {
+ if (auto *CE = dyn_cast<CastExpr>(E))
+ return CE->getSubExpr();
+
+ if (auto *FE = dyn_cast<FullExpr>(E))
+ return FE->getSubExpr();
+
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
+ return MTE->GetTemporaryExpr();
+
+ if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
+ return NTTP->getReplacement();
+
+ return E;
+}
+
+static Expr *IgnoreLValueCastsSingleStep(Expr *E) {
+ // Skip what IgnoreCastsSingleStep skips, except that only
+ // lvalue-to-rvalue casts are skipped.
+ if (auto *CE = dyn_cast<CastExpr>(E))
+ if (CE->getCastKind() != CK_LValueToRValue)
+ return E;
+
+ return IgnoreCastsSingleStep(E);
+}
+
+static Expr *IgnoreBaseCastsSingleStep(Expr *E) {
+ if (auto *CE = dyn_cast<CastExpr>(E))
+ if (CE->getCastKind() == CK_DerivedToBase ||
+ CE->getCastKind() == CK_UncheckedDerivedToBase ||
+ CE->getCastKind() == CK_NoOp)
+ return CE->getSubExpr();
+
+ return E;
+}
+
+static Expr *IgnoreImplicitSingleStep(Expr *E) {
+ Expr *SubE = IgnoreImpCastsSingleStep(E);
+ if (SubE != E)
+ return SubE;
+
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
+ return MTE->GetTemporaryExpr();
+
+ if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
+ return BTE->getSubExpr();
+
+ return E;
+}
+
+static Expr *IgnoreParensSingleStep(Expr *E) {
+ if (auto *PE = dyn_cast<ParenExpr>(E))
+ return PE->getSubExpr();
+
+ if (auto *UO = dyn_cast<UnaryOperator>(E)) {
+ if (UO->getOpcode() == UO_Extension)
+ return UO->getSubExpr();
+ }
+
+ else if (auto *GSE = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!GSE->isResultDependent())
+ return GSE->getResultExpr();
}
+
+ else if (auto *CE = dyn_cast<ChooseExpr>(E)) {
+ if (!CE->isConditionDependent())
+ return CE->getChosenSubExpr();
+ }
+
+ else if (auto *CE = dyn_cast<ConstantExpr>(E))
+ return CE->getSubExpr();
+
+ return E;
}
-/// IgnoreParenLValueCasts - Ignore parentheses and lvalue-to-rvalue
-/// casts. This is intended purely as a temporary workaround for code
-/// that hasn't yet been rewritten to do the right thing about those
-/// casts, and may disappear along with the last internal use.
-Expr *Expr::IgnoreParenLValueCasts() {
- Expr *E = this;
- while (true) {
- E = E->IgnoreParens();
- if (CastExpr *P = dyn_cast<CastExpr>(E)) {
- if (P->getCastKind() == CK_LValueToRValue) {
- E = P->getSubExpr();
- continue;
- }
- } else if (MaterializeTemporaryExpr *Materialize
- = dyn_cast<MaterializeTemporaryExpr>(E)) {
- E = Materialize->GetTemporaryExpr();
- continue;
- } else if (SubstNonTypeTemplateParmExpr *NTTP
- = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
- E = NTTP->getReplacement();
- continue;
- } else if (FullExpr *FE = dyn_cast<FullExpr>(E)) {
- E = FE->getSubExpr();
- continue;
- }
- break;
+static Expr *IgnoreNoopCastsSingleStep(const ASTContext &Ctx, Expr *E) {
+ if (auto *CE = dyn_cast<CastExpr>(E)) {
+ // We ignore integer <-> casts that are of the same width, ptr<->ptr and
+ // ptr<->int casts of the same width. We also ignore all identity casts.
+ Expr *SubExpr = CE->getSubExpr();
+ bool IsIdentityCast =
+ Ctx.hasSameUnqualifiedType(E->getType(), SubExpr->getType());
+ bool IsSameWidthCast =
+ (E->getType()->isPointerType() || E->getType()->isIntegralType(Ctx)) &&
+ (SubExpr->getType()->isPointerType() ||
+ SubExpr->getType()->isIntegralType(Ctx)) &&
+ (Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SubExpr->getType()));
+
+ if (IsIdentityCast || IsSameWidthCast)
+ return SubExpr;
}
+
+ else if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
+ return NTTP->getReplacement();
+
return E;
}
-Expr *Expr::ignoreParenBaseCasts() {
- Expr *E = this;
- while (true) {
- E = E->IgnoreParens();
- if (CastExpr *CE = dyn_cast<CastExpr>(E)) {
- if (CE->getCastKind() == CK_DerivedToBase ||
- CE->getCastKind() == CK_UncheckedDerivedToBase ||
- CE->getCastKind() == CK_NoOp) {
- E = CE->getSubExpr();
- continue;
- }
- }
+static Expr *IgnoreExprNodesImpl(Expr *E) { return E; }
+template <typename FnTy, typename... FnTys>
+static Expr *IgnoreExprNodesImpl(Expr *E, FnTy &&Fn, FnTys &&... Fns) {
+ return IgnoreExprNodesImpl(Fn(E), std::forward<FnTys>(Fns)...);
+}
- return E;
+/// Given an expression E and functions Fn_1,...,Fn_n : Expr * -> Expr *,
+/// Recursively apply each of the functions to E until reaching a fixed point.
+/// Note that a null E is valid; in this case nothing is done.
+template <typename... FnTys>
+static Expr *IgnoreExprNodes(Expr *E, FnTys &&... Fns) {
+ Expr *LastE = nullptr;
+ while (E != LastE) {
+ LastE = E;
+ E = IgnoreExprNodesImpl(E, std::forward<FnTys>(Fns)...);
}
+ return E;
+}
+
+Expr *Expr::IgnoreImpCasts() {
+ return IgnoreExprNodes(this, IgnoreImpCastsSingleStep);
+}
+
+Expr *Expr::IgnoreCasts() {
+ return IgnoreExprNodes(this, IgnoreCastsSingleStep);
+}
+
+Expr *Expr::IgnoreImplicit() {
+ return IgnoreExprNodes(this, IgnoreImplicitSingleStep);
+}
+
+Expr *Expr::IgnoreParens() {
+ return IgnoreExprNodes(this, IgnoreParensSingleStep);
}
Expr *Expr::IgnoreParenImpCasts() {
- Expr *E = this;
- while (true) {
- E = E->IgnoreParens();
- if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
- if (MaterializeTemporaryExpr *Materialize
- = dyn_cast<MaterializeTemporaryExpr>(E)) {
- E = Materialize->GetTemporaryExpr();
- continue;
- }
- if (SubstNonTypeTemplateParmExpr *NTTP
- = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
- E = NTTP->getReplacement();
- continue;
- }
- return E;
- }
+ return IgnoreExprNodes(this, IgnoreParensSingleStep,
+ IgnoreImpCastsExtraSingleStep);
+}
+
+Expr *Expr::IgnoreParenCasts() {
+ return IgnoreExprNodes(this, IgnoreParensSingleStep, IgnoreCastsSingleStep);
}
Expr *Expr::IgnoreConversionOperator() {
- if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(this)) {
+ if (auto *MCE = dyn_cast<CXXMemberCallExpr>(this)) {
if (MCE->getMethodDecl() && isa<CXXConversionDecl>(MCE->getMethodDecl()))
return MCE->getImplicitObjectArgument();
}
return this;
}
-/// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the
-/// value (including ptr->int casts of the same size). Strip off any
-/// ParenExpr or CastExprs, returning their operand.
-Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
- Expr *E = this;
- while (true) {
- E = E->IgnoreParens();
-
- if (CastExpr *P = dyn_cast<CastExpr>(E)) {
- // We ignore integer <-> casts that are of the same width, ptr<->ptr and
- // ptr<->int casts of the same width. We also ignore all identity casts.
- Expr *SE = P->getSubExpr();
-
- if (Ctx.hasSameUnqualifiedType(E->getType(), SE->getType())) {
- E = SE;
- continue;
- }
-
- if ((E->getType()->isPointerType() ||
- E->getType()->isIntegralType(Ctx)) &&
- (SE->getType()->isPointerType() ||
- SE->getType()->isIntegralType(Ctx)) &&
- Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SE->getType())) {
- E = SE;
- continue;
- }
- }
+Expr *Expr::IgnoreParenLValueCasts() {
+ return IgnoreExprNodes(this, IgnoreParensSingleStep,
+ IgnoreLValueCastsSingleStep);
+}
- if (SubstNonTypeTemplateParmExpr *NTTP
- = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
- E = NTTP->getReplacement();
- continue;
- }
+Expr *Expr::ignoreParenBaseCasts() {
+ return IgnoreExprNodes(this, IgnoreParensSingleStep,
+ IgnoreBaseCastsSingleStep);
+}
- return E;
- }
+Expr *Expr::IgnoreParenNoopCasts(const ASTContext &Ctx) {
+ return IgnoreExprNodes(this, IgnoreParensSingleStep, [&Ctx](Expr *E) {
+ return IgnoreNoopCastsSingleStep(Ctx, E);
+ });
}
bool Expr::isDefaultArgument() const {
@@ -2893,6 +3107,9 @@ bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) {
bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
const Expr **Culprit) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
// This function is attempting whether an expression is an initializer
// which can be evaluated at compile-time. It very closely parallels
// ConstExprEmitter in CGExprConstant.cpp; if they don't match, it
@@ -2952,6 +3169,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
}
case InitListExprClass: {
const InitListExpr *ILE = cast<InitListExpr>(this);
+ assert(ILE->isSemanticForm() && "InitListExpr must be in semantic form");
if (ILE->getType()->isArrayType()) {
unsigned numInits = ILE->getNumInits();
for (unsigned i = 0; i < numInits; i++) {
@@ -3160,6 +3378,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case ObjCAvailabilityCheckExprClass:
case CXXUuidofExprClass:
case OpaqueValueExprClass:
+ case SourceLocExprClass:
// These never have a side-effect.
return false;
@@ -3288,7 +3507,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case CXXStaticCastExprClass:
case CXXReinterpretCastExprClass:
case CXXConstCastExprClass:
- case CXXFunctionalCastExprClass: {
+ case CXXFunctionalCastExprClass:
+ case BuiltinBitCastExprClass: {
// While volatile reads are side-effecting in both C and C++, we treat them
// as having possible (not definite) side-effects. This allows idiomatic
// code to behave without warning, such as sizeof(*v) for a volatile-
@@ -3775,55 +3995,95 @@ void ShuffleVectorExpr::setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs) {
memcpy(SubExprs, Exprs.data(), sizeof(Expr *) * Exprs.size());
}
-GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context,
- SourceLocation GenericLoc, Expr *ControllingExpr,
- ArrayRef<TypeSourceInfo*> AssocTypes,
- ArrayRef<Expr*> AssocExprs,
- SourceLocation DefaultLoc,
- SourceLocation RParenLoc,
- bool ContainsUnexpandedParameterPack,
- unsigned ResultIndex)
- : Expr(GenericSelectionExprClass,
- AssocExprs[ResultIndex]->getType(),
- AssocExprs[ResultIndex]->getValueKind(),
- AssocExprs[ResultIndex]->getObjectKind(),
- AssocExprs[ResultIndex]->isTypeDependent(),
- AssocExprs[ResultIndex]->isValueDependent(),
- AssocExprs[ResultIndex]->isInstantiationDependent(),
- ContainsUnexpandedParameterPack),
- AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]),
- SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]),
- NumAssocs(AssocExprs.size()), ResultIndex(ResultIndex),
- GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) {
- SubExprs[CONTROLLING] = ControllingExpr;
- assert(AssocTypes.size() == AssocExprs.size());
- std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes);
- std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR);
-}
-
-GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context,
- SourceLocation GenericLoc, Expr *ControllingExpr,
- ArrayRef<TypeSourceInfo*> AssocTypes,
- ArrayRef<Expr*> AssocExprs,
- SourceLocation DefaultLoc,
- SourceLocation RParenLoc,
- bool ContainsUnexpandedParameterPack)
- : Expr(GenericSelectionExprClass,
- Context.DependentTy,
- VK_RValue,
- OK_Ordinary,
- /*isTypeDependent=*/true,
- /*isValueDependent=*/true,
- /*isInstantiationDependent=*/true,
- ContainsUnexpandedParameterPack),
- AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]),
- SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]),
- NumAssocs(AssocExprs.size()), ResultIndex(-1U), GenericLoc(GenericLoc),
- DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) {
- SubExprs[CONTROLLING] = ControllingExpr;
- assert(AssocTypes.size() == AssocExprs.size());
- std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes);
- std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR);
+GenericSelectionExpr::GenericSelectionExpr(
+ const ASTContext &, SourceLocation GenericLoc, Expr *ControllingExpr,
+ ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs,
+ SourceLocation DefaultLoc, SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack, unsigned ResultIndex)
+ : Expr(GenericSelectionExprClass, AssocExprs[ResultIndex]->getType(),
+ AssocExprs[ResultIndex]->getValueKind(),
+ AssocExprs[ResultIndex]->getObjectKind(),
+ AssocExprs[ResultIndex]->isTypeDependent(),
+ AssocExprs[ResultIndex]->isValueDependent(),
+ AssocExprs[ResultIndex]->isInstantiationDependent(),
+ ContainsUnexpandedParameterPack),
+ NumAssocs(AssocExprs.size()), ResultIndex(ResultIndex),
+ DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) {
+ assert(AssocTypes.size() == AssocExprs.size() &&
+ "Must have the same number of association expressions"
+ " and TypeSourceInfo!");
+ assert(ResultIndex < NumAssocs && "ResultIndex is out-of-bounds!");
+
+ GenericSelectionExprBits.GenericLoc = GenericLoc;
+ getTrailingObjects<Stmt *>()[ControllingIndex] = ControllingExpr;
+ std::copy(AssocExprs.begin(), AssocExprs.end(),
+ getTrailingObjects<Stmt *>() + AssocExprStartIndex);
+ std::copy(AssocTypes.begin(), AssocTypes.end(),
+ getTrailingObjects<TypeSourceInfo *>());
+}
+
+GenericSelectionExpr::GenericSelectionExpr(
+ const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr,
+ ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs,
+ SourceLocation DefaultLoc, SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack)
+ : Expr(GenericSelectionExprClass, Context.DependentTy, VK_RValue,
+ OK_Ordinary,
+ /*isTypeDependent=*/true,
+ /*isValueDependent=*/true,
+ /*isInstantiationDependent=*/true, ContainsUnexpandedParameterPack),
+ NumAssocs(AssocExprs.size()), ResultIndex(ResultDependentIndex),
+ DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) {
+ assert(AssocTypes.size() == AssocExprs.size() &&
+ "Must have the same number of association expressions"
+ " and TypeSourceInfo!");
+
+ GenericSelectionExprBits.GenericLoc = GenericLoc;
+ getTrailingObjects<Stmt *>()[ControllingIndex] = ControllingExpr;
+ std::copy(AssocExprs.begin(), AssocExprs.end(),
+ getTrailingObjects<Stmt *>() + AssocExprStartIndex);
+ std::copy(AssocTypes.begin(), AssocTypes.end(),
+ getTrailingObjects<TypeSourceInfo *>());
+}
+
+GenericSelectionExpr::GenericSelectionExpr(EmptyShell Empty, unsigned NumAssocs)
+ : Expr(GenericSelectionExprClass, Empty), NumAssocs(NumAssocs) {}
+
+GenericSelectionExpr *GenericSelectionExpr::Create(
+ const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr,
+ ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs,
+ SourceLocation DefaultLoc, SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack, unsigned ResultIndex) {
+ unsigned NumAssocs = AssocExprs.size();
+ void *Mem = Context.Allocate(
+ totalSizeToAlloc<Stmt *, TypeSourceInfo *>(1 + NumAssocs, NumAssocs),
+ alignof(GenericSelectionExpr));
+ return new (Mem) GenericSelectionExpr(
+ Context, GenericLoc, ControllingExpr, AssocTypes, AssocExprs, DefaultLoc,
+ RParenLoc, ContainsUnexpandedParameterPack, ResultIndex);
+}
+
+GenericSelectionExpr *GenericSelectionExpr::Create(
+ const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr,
+ ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs,
+ SourceLocation DefaultLoc, SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack) {
+ unsigned NumAssocs = AssocExprs.size();
+ void *Mem = Context.Allocate(
+ totalSizeToAlloc<Stmt *, TypeSourceInfo *>(1 + NumAssocs, NumAssocs),
+ alignof(GenericSelectionExpr));
+ return new (Mem) GenericSelectionExpr(
+ Context, GenericLoc, ControllingExpr, AssocTypes, AssocExprs, DefaultLoc,
+ RParenLoc, ContainsUnexpandedParameterPack);
+}
+
+GenericSelectionExpr *
+GenericSelectionExpr::CreateEmpty(const ASTContext &Context,
+ unsigned NumAssocs) {
+ void *Mem = Context.Allocate(
+ totalSizeToAlloc<Stmt *, TypeSourceInfo *>(1 + NumAssocs, NumAssocs),
+ alignof(GenericSelectionExpr));
+ return new (Mem) GenericSelectionExpr(EmptyShell(), NumAssocs);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 3891f45c7fc2c..b30f785ba8f54 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -1,9 +1,8 @@
//===- ExprCXX.cpp - (C++) Expression AST Node Implementation -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -98,7 +97,8 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
FunctionDecl *OperatorDelete, bool ShouldPassAlignment,
bool UsualArrayDeleteWantsSize,
ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens,
- Expr *ArraySize, InitializationStyle InitializationStyle,
+ Optional<Expr *> ArraySize,
+ InitializationStyle InitializationStyle,
Expr *Initializer, QualType Ty,
TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
SourceRange DirectInitRange)
@@ -113,7 +113,7 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
"Only NoInit can have no initializer!");
CXXNewExprBits.IsGlobalNew = IsGlobalNew;
- CXXNewExprBits.IsArray = ArraySize != nullptr;
+ CXXNewExprBits.IsArray = ArraySize.hasValue();
CXXNewExprBits.ShouldPassAlignment = ShouldPassAlignment;
CXXNewExprBits.UsualArrayDeleteWantsSize = UsualArrayDeleteWantsSize;
CXXNewExprBits.StoredInitializationStyle =
@@ -123,12 +123,14 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
CXXNewExprBits.NumPlacementArgs = PlacementArgs.size();
if (ArraySize) {
- if (ArraySize->isInstantiationDependent())
- ExprBits.InstantiationDependent = true;
- if (ArraySize->containsUnexpandedParameterPack())
- ExprBits.ContainsUnexpandedParameterPack = true;
+ if (Expr *SizeExpr = *ArraySize) {
+ if (SizeExpr->isInstantiationDependent())
+ ExprBits.InstantiationDependent = true;
+ if (SizeExpr->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+ }
- getTrailingObjects<Stmt *>()[arraySizeOffset()] = ArraySize;
+ getTrailingObjects<Stmt *>()[arraySizeOffset()] = *ArraySize;
}
if (Initializer) {
@@ -180,11 +182,11 @@ CXXNewExpr::Create(const ASTContext &Ctx, bool IsGlobalNew,
FunctionDecl *OperatorNew, FunctionDecl *OperatorDelete,
bool ShouldPassAlignment, bool UsualArrayDeleteWantsSize,
ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens,
- Expr *ArraySize, InitializationStyle InitializationStyle,
- Expr *Initializer, QualType Ty,
- TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
- SourceRange DirectInitRange) {
- bool IsArray = ArraySize != nullptr;
+ Optional<Expr *> ArraySize,
+ InitializationStyle InitializationStyle, Expr *Initializer,
+ QualType Ty, TypeSourceInfo *AllocatedTypeInfo,
+ SourceRange Range, SourceRange DirectInitRange) {
+ bool IsArray = ArraySize.hasValue();
bool HasInit = Initializer != nullptr;
unsigned NumPlacementArgs = PlacementArgs.size();
bool IsParenTypeId = TypeIdParens.isValid();
@@ -905,13 +907,14 @@ const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const {
}
CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &Ctx, SourceLocation Loc,
- FieldDecl *Field, QualType Ty)
+ FieldDecl *Field, QualType Ty,
+ DeclContext *UsedContext)
: Expr(CXXDefaultInitExprClass, Ty.getNonLValueExprType(Ctx),
Ty->isLValueReferenceType() ? VK_LValue : Ty->isRValueReferenceType()
? VK_XValue
: VK_RValue,
/*FIXME*/ OK_Ordinary, false, false, false, false),
- Field(Field) {
+ Field(Field), UsedContext(UsedContext) {
CXXDefaultInitExprBits.Loc = Loc;
assert(Field->hasInClassInitializer());
}
@@ -1205,7 +1208,11 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const {
TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
CXXRecordDecl *Record = getLambdaClass();
return Record->getGenericLambdaTemplateParameterList();
+}
+ArrayRef<NamedDecl *> LambdaExpr::getExplicitTemplateParameters() const {
+ const CXXRecordDecl *Record = getLambdaClass();
+ return Record->getLambdaExplicitTemplateParameters();
}
CompoundStmt *LambdaExpr::getBody() const {
@@ -1534,30 +1541,30 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const {
return TemplateArgument(llvm::makeArrayRef(Arguments, NumArguments));
}
-FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
+FunctionParmPackExpr::FunctionParmPackExpr(QualType T, VarDecl *ParamPack,
SourceLocation NameLoc,
unsigned NumParams,
- ParmVarDecl *const *Params)
+ VarDecl *const *Params)
: Expr(FunctionParmPackExprClass, T, VK_LValue, OK_Ordinary, true, true,
true, true),
ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) {
if (Params)
std::uninitialized_copy(Params, Params + NumParams,
- getTrailingObjects<ParmVarDecl *>());
+ getTrailingObjects<VarDecl *>());
}
FunctionParmPackExpr *
FunctionParmPackExpr::Create(const ASTContext &Context, QualType T,
- ParmVarDecl *ParamPack, SourceLocation NameLoc,
- ArrayRef<ParmVarDecl *> Params) {
- return new (Context.Allocate(totalSizeToAlloc<ParmVarDecl *>(Params.size())))
+ VarDecl *ParamPack, SourceLocation NameLoc,
+ ArrayRef<VarDecl *> Params) {
+ return new (Context.Allocate(totalSizeToAlloc<VarDecl *>(Params.size())))
FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data());
}
FunctionParmPackExpr *
FunctionParmPackExpr::CreateEmpty(const ASTContext &Context,
unsigned NumParams) {
- return new (Context.Allocate(totalSizeToAlloc<ParmVarDecl *>(NumParams)))
+ return new (Context.Allocate(totalSizeToAlloc<VarDecl *>(NumParams)))
FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr);
}
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index e1d6a1c9edcc8..c61ee703aca8e 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -1,9 +1,8 @@
//===- ExprClassification.cpp - Expression AST Node Implementation --------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -192,6 +191,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ArrayInitIndexExprClass:
case Expr::NoInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
+ case Expr::SourceLocExprClass:
return Cl::CL_PRValue;
case Expr::ConstantExprClass:
@@ -343,6 +343,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass:
case Expr::ObjCBridgedCastExprClass:
+ case Expr::BuiltinBitCastExprClass:
// Only in C++ can casts be interesting at all.
if (!Lang.CPlusPlus) return Cl::CL_PRValue;
return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten());
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index da093ff22c123..f01b42e7ff761 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1,9 +1,8 @@
//===--- ExprConstant.cpp - Expression Constant Evaluator -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -38,13 +37,18 @@
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTLambda.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/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/FixedPoint.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallBitVector.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
@@ -53,8 +57,10 @@
#define DEBUG_TYPE "exprconstant"
using namespace clang;
+using llvm::APInt;
using llvm::APSInt;
using llvm::APFloat;
+using llvm::Optional;
static bool IsGlobalLValue(APValue::LValueBase B);
@@ -63,6 +69,9 @@ namespace {
struct CallStackFrame;
struct EvalInfo;
+ using SourceLocExprScopeGuard =
+ CurrentSourceLocExprScope::SourceLocExprScopeGuard;
+
static QualType getType(APValue::LValueBase B) {
if (!B) return QualType();
if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
@@ -82,6 +91,9 @@ namespace {
return D->getType();
}
+ if (B.is<TypeInfoLValue>())
+ return B.getTypeInfoType();
+
const Expr *Base = B.get<const Expr*>();
// For a materialized temporary, the type of the temporary we materialized
@@ -103,28 +115,19 @@ namespace {
}
/// Get an LValue path entry, which is known to not be an array index, as a
- /// field or base class.
- static
- APValue::BaseOrMemberType getAsBaseOrMember(APValue::LValuePathEntry E) {
- APValue::BaseOrMemberType Value;
- Value.setFromOpaqueValue(E.BaseOrMember);
- return Value;
- }
-
- /// Get an LValue path entry, which is known to not be an array index, as a
/// field declaration.
static const FieldDecl *getAsField(APValue::LValuePathEntry E) {
- return dyn_cast<FieldDecl>(getAsBaseOrMember(E).getPointer());
+ return dyn_cast_or_null<FieldDecl>(E.getAsBaseOrMember().getPointer());
}
/// Get an LValue path entry, which is known to not be an array index, as a
/// base class declaration.
static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {
- return dyn_cast<CXXRecordDecl>(getAsBaseOrMember(E).getPointer());
+ return dyn_cast_or_null<CXXRecordDecl>(E.getAsBaseOrMember().getPointer());
}
/// Determine whether this LValue path entry for a base class names a virtual
/// base class.
static bool isVirtualBaseClass(APValue::LValuePathEntry E) {
- return getAsBaseOrMember(E).getInt();
+ return E.getAsBaseOrMember().getInt();
}
/// Given a CallExpr, try to get the alloc_size attribute. May return null.
@@ -222,7 +225,7 @@ namespace {
// The order of this enum is important for diagnostics.
enum CheckSubobjectKind {
CSK_Base, CSK_Derived, CSK_Field, CSK_ArrayToPointer, CSK_ArrayIndex,
- CSK_This, CSK_Real, CSK_Imag
+ CSK_Real, CSK_Imag
};
/// A path from a glvalue to a subobject of that glvalue.
@@ -291,6 +294,27 @@ namespace {
}
}
+ void truncate(ASTContext &Ctx, APValue::LValueBase Base,
+ unsigned NewLength) {
+ if (Invalid)
+ return;
+
+ assert(Base && "cannot truncate path for null pointer");
+ assert(NewLength <= Entries.size() && "not a truncation");
+
+ if (NewLength == Entries.size())
+ return;
+ Entries.resize(NewLength);
+
+ bool IsArray = false;
+ bool FirstIsUnsizedArray = false;
+ MostDerivedPathLength = findMostDerivedSubobject(
+ Ctx, Base, Entries, MostDerivedArraySize, MostDerivedType, IsArray,
+ FirstIsUnsizedArray);
+ MostDerivedIsArrayElement = IsArray;
+ FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
+ }
+
void setInvalid() {
Invalid = true;
Entries.clear();
@@ -316,7 +340,8 @@ namespace {
if (IsOnePastTheEnd)
return true;
if (!isMostDerivedAnUnsizedArray() && MostDerivedIsArrayElement &&
- Entries[MostDerivedPathLength - 1].ArrayIndex == MostDerivedArraySize)
+ Entries[MostDerivedPathLength - 1].getAsArrayIndex() ==
+ MostDerivedArraySize)
return true;
return false;
}
@@ -333,8 +358,8 @@ namespace {
// an array of length one with the type of the object as its element type.
bool IsArray = MostDerivedPathLength == Entries.size() &&
MostDerivedIsArrayElement;
- uint64_t ArrayIndex =
- IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd;
+ uint64_t ArrayIndex = IsArray ? Entries.back().getAsArrayIndex()
+ : (uint64_t)IsOnePastTheEnd;
uint64_t ArraySize =
IsArray ? getMostDerivedArraySize() : (uint64_t)1;
return {ArrayIndex, ArraySize - ArrayIndex};
@@ -360,9 +385,7 @@ namespace {
/// Update this designator to refer to the first element within this array.
void addArrayUnchecked(const ConstantArrayType *CAT) {
- PathEntry Entry;
- Entry.ArrayIndex = 0;
- Entries.push_back(Entry);
+ Entries.push_back(PathEntry::ArrayIndex(0));
// This is a most-derived object.
MostDerivedType = CAT->getElementType();
@@ -373,9 +396,7 @@ namespace {
/// Update this designator to refer to the first element within the array of
/// elements of type T. This is an array of unknown size.
void addUnsizedArrayUnchecked(QualType ElemTy) {
- PathEntry Entry;
- Entry.ArrayIndex = 0;
- Entries.push_back(Entry);
+ Entries.push_back(PathEntry::ArrayIndex(0));
MostDerivedType = ElemTy;
MostDerivedIsArrayElement = true;
@@ -388,10 +409,7 @@ namespace {
/// Update this designator to refer to the given base or member of this
/// object.
void addDeclUnchecked(const Decl *D, bool Virtual = false) {
- PathEntry Entry;
- APValue::BaseOrMemberType Value(D, Virtual);
- Entry.BaseOrMember = Value.getOpaqueValue();
- Entries.push_back(Entry);
+ Entries.push_back(APValue::BaseOrMemberType(D, Virtual));
// If this isn't a base class, it's a new most-derived object.
if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
@@ -403,9 +421,7 @@ namespace {
}
/// Update this designator to refer to the given complex component.
void addComplexUnchecked(QualType EltTy, bool Imag) {
- PathEntry Entry;
- Entry.ArrayIndex = Imag;
- Entries.push_back(Entry);
+ Entries.push_back(PathEntry::ArrayIndex(Imag));
// This is technically a most-derived object, though in practice this
// is unlikely to matter.
@@ -426,7 +442,8 @@ namespace {
// Can't verify -- trust that the user is doing the right thing (or if
// not, trust that the caller will catch the bad behavior).
// FIXME: Should we reject if this overflows, at least?
- Entries.back().ArrayIndex += TruncatedN;
+ Entries.back() = PathEntry::ArrayIndex(
+ Entries.back().getAsArrayIndex() + TruncatedN);
return;
}
@@ -435,8 +452,8 @@ namespace {
// an array of length one with the type of the object as its element type.
bool IsArray = MostDerivedPathLength == Entries.size() &&
MostDerivedIsArrayElement;
- uint64_t ArrayIndex =
- IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd;
+ uint64_t ArrayIndex = IsArray ? Entries.back().getAsArrayIndex()
+ : (uint64_t)IsOnePastTheEnd;
uint64_t ArraySize =
IsArray ? getMostDerivedArraySize() : (uint64_t)1;
@@ -456,7 +473,7 @@ namespace {
"bounds check succeeded for out-of-bounds index");
if (IsArray)
- Entries.back().ArrayIndex = ArrayIndex;
+ Entries.back() = PathEntry::ArrayIndex(ArrayIndex);
else
IsOnePastTheEnd = (ArrayIndex != 0);
}
@@ -479,6 +496,10 @@ namespace {
/// parameters' function scope indices.
APValue *Arguments;
+ /// Source location information about the default argument or default
+ /// initializer expression we're evaluating, if any.
+ CurrentSourceLocExprScope CurSourceLocExprScope;
+
// Note that we intentionally use std::map here so that references to
// values are stable.
typedef std::pair<const void *, unsigned> MapKeyTy;
@@ -613,6 +634,15 @@ namespace {
}
return *this;
}
+
+ OptionalDiagnostic &operator<<(const APFixedPoint &FX) {
+ if (Diag) {
+ SmallVector<char, 32> Buffer;
+ FX.toString(Buffer);
+ *Diag << StringRef(Buffer.data(), Buffer.size());
+ }
+ return *this;
+ }
};
/// A cleanup, and a flag indicating whether it is lifetime-extended.
@@ -629,6 +659,40 @@ namespace {
}
};
+ /// A reference to an object whose construction we are currently evaluating.
+ struct ObjectUnderConstruction {
+ APValue::LValueBase Base;
+ ArrayRef<APValue::LValuePathEntry> Path;
+ friend bool operator==(const ObjectUnderConstruction &LHS,
+ const ObjectUnderConstruction &RHS) {
+ return LHS.Base == RHS.Base && LHS.Path == RHS.Path;
+ }
+ friend llvm::hash_code hash_value(const ObjectUnderConstruction &Obj) {
+ return llvm::hash_combine(Obj.Base, Obj.Path);
+ }
+ };
+ enum class ConstructionPhase { None, Bases, AfterBases };
+}
+
+namespace llvm {
+template<> struct DenseMapInfo<ObjectUnderConstruction> {
+ using Base = DenseMapInfo<APValue::LValueBase>;
+ static ObjectUnderConstruction getEmptyKey() {
+ return {Base::getEmptyKey(), {}}; }
+ static ObjectUnderConstruction getTombstoneKey() {
+ return {Base::getTombstoneKey(), {}};
+ }
+ static unsigned getHashValue(const ObjectUnderConstruction &Object) {
+ return hash_value(Object);
+ }
+ static bool isEqual(const ObjectUnderConstruction &LHS,
+ const ObjectUnderConstruction &RHS) {
+ return LHS == RHS;
+ }
+};
+}
+
+namespace {
/// 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
@@ -679,34 +743,41 @@ namespace {
/// declaration whose initializer is being evaluated, if any.
APValue *EvaluatingDeclValue;
- /// EvaluatingObject - Pair of the AST node that an lvalue represents and
- /// the call index that that lvalue was allocated in.
- typedef std::pair<APValue::LValueBase, std::pair<unsigned, unsigned>>
- EvaluatingObject;
-
- /// EvaluatingConstructors - Set of objects that are currently being
- /// constructed.
- llvm::DenseSet<EvaluatingObject> EvaluatingConstructors;
+ /// Set of objects that are currently being constructed.
+ llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase>
+ ObjectsUnderConstruction;
struct EvaluatingConstructorRAII {
EvalInfo &EI;
- EvaluatingObject Object;
+ ObjectUnderConstruction Object;
bool DidInsert;
- EvaluatingConstructorRAII(EvalInfo &EI, EvaluatingObject Object)
+ EvaluatingConstructorRAII(EvalInfo &EI, ObjectUnderConstruction Object,
+ bool HasBases)
: EI(EI), Object(Object) {
- DidInsert = EI.EvaluatingConstructors.insert(Object).second;
+ DidInsert =
+ EI.ObjectsUnderConstruction
+ .insert({Object, HasBases ? ConstructionPhase::Bases
+ : ConstructionPhase::AfterBases})
+ .second;
+ }
+ void finishedConstructingBases() {
+ EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterBases;
}
~EvaluatingConstructorRAII() {
- if (DidInsert) EI.EvaluatingConstructors.erase(Object);
+ if (DidInsert) EI.ObjectsUnderConstruction.erase(Object);
}
};
- bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex,
- unsigned Version) {
- return EvaluatingConstructors.count(
- EvaluatingObject(Decl, {CallIndex, Version}));
+ ConstructionPhase
+ isEvaluatingConstructor(APValue::LValueBase Base,
+ ArrayRef<APValue::LValuePathEntry> Path) {
+ return ObjectsUnderConstruction.lookup({Base, Path});
}
+ /// If we're currently speculatively evaluating, the outermost call stack
+ /// depth at which we can mutate state, otherwise 0.
+ unsigned SpeculativeEvaluationDepth = 0;
+
/// The current array initialization index, if we're performing array
/// initialization.
uint64_t ArrayInitIndex = -1;
@@ -719,9 +790,6 @@ namespace {
/// fold (not just why it's not strictly a constant expression)?
bool HasFoldFailureDiagnostic;
- /// Whether or not we're currently speculatively evaluating.
- bool IsSpeculativelyEvaluating;
-
/// Whether or not we're in a context where the front end requires a
/// constant value.
bool InConstantContext;
@@ -786,13 +854,12 @@ namespace {
BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
EvaluatingDecl((const ValueDecl *)nullptr),
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false), IsSpeculativelyEvaluating(false),
+ HasFoldFailureDiagnostic(false),
InConstantContext(false), EvalMode(Mode) {}
void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
EvaluatingDecl = Base;
EvaluatingDeclValue = &Value;
- EvaluatingConstructors.insert({Base, {0, 0}});
}
const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
@@ -814,14 +881,20 @@ namespace {
return false;
}
- CallStackFrame *getCallFrame(unsigned CallIndex) {
- assert(CallIndex && "no call index in getCallFrame");
+ std::pair<CallStackFrame *, unsigned>
+ getCallFrameAndDepth(unsigned CallIndex) {
+ assert(CallIndex && "no call index in getCallFrameAndDepth");
// We will eventually hit BottomFrame, which has Index 1, so Frame can't
// be null in this loop.
+ unsigned Depth = CallStackDepth;
CallStackFrame *Frame = CurrentCall;
- while (Frame->Index > CallIndex)
+ while (Frame->Index > CallIndex) {
Frame = Frame->Caller;
- return (Frame->Index == CallIndex) ? Frame : nullptr;
+ --Depth;
+ }
+ if (Frame->Index == CallIndex)
+ return {Frame, Depth};
+ return {nullptr, 0};
}
bool nextStep(const Stmt *S) {
@@ -1102,12 +1175,12 @@ namespace {
class SpeculativeEvaluationRAII {
EvalInfo *Info = nullptr;
Expr::EvalStatus OldStatus;
- bool OldIsSpeculativelyEvaluating;
+ unsigned OldSpeculativeEvaluationDepth;
void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) {
Info = Other.Info;
OldStatus = Other.OldStatus;
- OldIsSpeculativelyEvaluating = Other.OldIsSpeculativelyEvaluating;
+ OldSpeculativeEvaluationDepth = Other.OldSpeculativeEvaluationDepth;
Other.Info = nullptr;
}
@@ -1116,7 +1189,7 @@ namespace {
return;
Info->EvalStatus = OldStatus;
- Info->IsSpeculativelyEvaluating = OldIsSpeculativelyEvaluating;
+ Info->SpeculativeEvaluationDepth = OldSpeculativeEvaluationDepth;
}
public:
@@ -1125,9 +1198,9 @@ namespace {
SpeculativeEvaluationRAII(
EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
: Info(&Info), OldStatus(Info.EvalStatus),
- OldIsSpeculativelyEvaluating(Info.IsSpeculativelyEvaluating) {
+ OldSpeculativeEvaluationDepth(Info.SpeculativeEvaluationDepth) {
Info.EvalStatus.Diag = NewDiag;
- Info.IsSpeculativelyEvaluating = true;
+ Info.SpeculativeEvaluationDepth = Info.CallStackDepth + 1;
}
SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete;
@@ -1243,7 +1316,7 @@ APValue &CallStackFrame::createTemporary(const void *Key,
bool IsLifetimeExtended) {
unsigned Version = Info.CurrentCall->getTempVersion();
APValue &Result = Temporaries[MapKeyTy(Key, Version)];
- assert(Result.isUninit() && "temporary created multiple times");
+ assert(Result.isAbsent() && "temporary created multiple times");
Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended));
return Result;
}
@@ -1290,14 +1363,40 @@ void EvalInfo::addCallStack(unsigned Limit) {
}
}
-/// Kinds of access we can perform on an object, for diagnostics.
+/// 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_Decrement,
+ AK_MemberCall,
+ AK_DynamicCast,
+ AK_TypeId,
};
+static bool isModification(AccessKinds AK) {
+ switch (AK) {
+ case AK_Read:
+ case AK_MemberCall:
+ case AK_DynamicCast:
+ case AK_TypeId:
+ return false;
+ case AK_Assign:
+ case AK_Increment:
+ case AK_Decrement:
+ return true;
+ }
+ llvm_unreachable("unknown access kind");
+}
+
+/// Is this an access per the C++ definition?
+static bool isFormalAccess(AccessKinds AK) {
+ return AK == AK_Read || isModification(AK);
+}
+
namespace {
struct ComplexValue {
private:
@@ -1613,6 +1712,14 @@ static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result,
EvalInfo &Info);
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result);
+/// Evaluate an integer or fixed point expression into an APResult.
+static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result,
+ EvalInfo &Info);
+
+/// Evaluate only a fixed point expression into an APResult.
+static bool EvaluateFixedPoint(const Expr *E, APFixedPoint &Result,
+ EvalInfo &Info);
+
//===----------------------------------------------------------------------===//
// Misc utilities
//===----------------------------------------------------------------------===//
@@ -1706,6 +1813,9 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
return isa<FunctionDecl>(D);
}
+ if (B.is<TypeInfoLValue>())
+ return true;
+
const Expr *E = B.get<const Expr*>();
switch (E->getStmtClass()) {
default:
@@ -1723,9 +1833,10 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
case Expr::PredefinedExprClass:
case Expr::ObjCStringLiteralClass:
case Expr::ObjCEncodeExprClass:
- case Expr::CXXTypeidExprClass:
case Expr::CXXUuidofExprClass:
return true;
+ case Expr::ObjCBoxedExprClass:
+ return cast<ObjCBoxedExpr>(E)->isExpressibleAsConstantInitializer();
case Expr::CallExprClass:
return IsStringLiteralCall(cast<CallExpr>(E));
// For GCC compatibility, &&label has static storage duration.
@@ -1799,9 +1910,9 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
if (VD)
Info.Note(VD->getLocation(), diag::note_declared_at);
- else
- Info.Note(Base.get<const Expr*>()->getExprLoc(),
- diag::note_constexpr_temporary_here);
+ else if (const Expr *E = Base.dyn_cast<const Expr*>())
+ Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here);
+ // We have no information to show for a typeid(T) object.
}
/// Check that this reference or pointer core constant expression is a valid
@@ -1938,10 +2049,13 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
static bool
CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
const APValue &Value,
- Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen) {
- if (Value.isUninit()) {
+ Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen,
+ SourceLocation SubobjectLoc = SourceLocation()) {
+ if (!Value.hasValue()) {
Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
<< true << Type;
+ if (SubobjectLoc.isValid())
+ Info.Note(SubobjectLoc, diag::note_constexpr_subobject_declared_here);
return false;
}
@@ -1957,18 +2071,20 @@ CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
QualType EltTy = Type->castAsArrayTypeUnsafe()->getElementType();
for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) {
if (!CheckConstantExpression(Info, DiagLoc, EltTy,
- Value.getArrayInitializedElt(I), Usage))
+ Value.getArrayInitializedElt(I), Usage,
+ SubobjectLoc))
return false;
}
if (!Value.hasArrayFiller())
return true;
return CheckConstantExpression(Info, DiagLoc, EltTy, Value.getArrayFiller(),
- Usage);
+ Usage, SubobjectLoc);
}
if (Value.isUnion() && Value.getUnionField()) {
return CheckConstantExpression(Info, DiagLoc,
Value.getUnionField()->getType(),
- Value.getUnionValue(), Usage);
+ Value.getUnionValue(), Usage,
+ Value.getUnionField()->getLocation());
}
if (Value.isStruct()) {
RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
@@ -1976,7 +2092,8 @@ CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
unsigned BaseIndex = 0;
for (const CXXBaseSpecifier &BS : CD->bases()) {
if (!CheckConstantExpression(Info, DiagLoc, BS.getType(),
- Value.getStructBase(BaseIndex), Usage))
+ Value.getStructBase(BaseIndex), Usage,
+ BS.getBeginLoc()))
return false;
++BaseIndex;
}
@@ -1987,7 +2104,7 @@ CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
Value.getStructField(I->getFieldIndex()),
- Usage))
+ Usage, I->getLocation()))
return false;
}
}
@@ -2022,11 +2139,15 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
static bool HandleConversionToBool(const APValue &Val, bool &Result) {
switch (Val.getKind()) {
- case APValue::Uninitialized:
+ case APValue::None:
+ case APValue::Indeterminate:
return false;
case APValue::Int:
Result = Val.getInt().getBoolValue();
return true;
+ case APValue::FixedPoint:
+ Result = Val.getFixedPoint().getBoolValue();
+ return true;
case APValue::Float:
Result = !Val.getFloat().isZero();
return true;
@@ -2091,10 +2212,8 @@ static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E,
APFloat &Result) {
APFloat Value = Result;
bool ignored;
- if (Result.convert(Info.Ctx.getFloatTypeSemantics(DestType),
- APFloat::rmNearestTiesToEven, &ignored)
- & APFloat::opOverflow)
- return HandleOverflow(Info, E, Value, DestType);
+ Result.convert(Info.Ctx.getFloatTypeSemantics(DestType),
+ APFloat::rmNearestTiesToEven, &ignored);
return true;
}
@@ -2115,10 +2234,8 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
QualType SrcType, const APSInt &Value,
QualType DestType, APFloat &Result) {
Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
- if (Result.convertFromAPInt(Value, Value.isSigned(),
- APFloat::rmNearestTiesToEven)
- & APFloat::opOverflow)
- return HandleOverflow(Info, E, Value, DestType);
+ Result.convertFromAPInt(Value, Value.isSigned(),
+ APFloat::rmNearestTiesToEven);
return true;
}
@@ -2270,9 +2387,11 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
if (SA != RHS) {
Info.CCEDiag(E, diag::note_constexpr_large_shift)
<< RHS << E->getType() << LHS.getBitWidth();
- } else if (LHS.isSigned()) {
+ } else if (LHS.isSigned() && !Info.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 (LHS.isNegative())
Info.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS;
else if (LHS.countLeadingZeros() < SA)
@@ -2334,11 +2453,19 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E,
LHS.subtract(RHS, APFloat::rmNearestTiesToEven);
break;
case BO_Div:
+ // [expr.mul]p4:
+ // If the second operand of / or % is zero the behavior is undefined.
+ if (RHS.isZero())
+ Info.CCEDiag(E, diag::note_expr_divide_by_zero);
LHS.divide(RHS, APFloat::rmNearestTiesToEven);
break;
}
- if (LHS.isInfinity() || LHS.isNaN()) {
+ // [expr.pre]p4:
+ // If during the evaluation of an expression, the result is not
+ // mathematically defined [...], the behavior is undefined.
+ // FIXME: C++ rules require us to not conform to IEEE 754 here.
+ if (LHS.isNaN()) {
Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
return Info.noteUndefinedBehavior();
}
@@ -2428,6 +2555,21 @@ static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E,
return true;
}
+/// Cast an lvalue referring to a derived class to a known base subobject.
+static bool CastToBaseClass(EvalInfo &Info, const Expr *E, LValue &Result,
+ const CXXRecordDecl *DerivedRD,
+ const CXXRecordDecl *BaseRD) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/false);
+ if (!DerivedRD->isDerivedFrom(BaseRD, Paths))
+ llvm_unreachable("Class must be derived from the passed in base class!");
+
+ for (CXXBasePathElement &Elem : Paths.front())
+ if (!HandleLValueBase(Info, E, Result, Elem.Class, Elem.Base))
+ return false;
+ return true;
+}
+
/// Update LVal to refer to the given field, which must be a member of the type
/// currently described by LVal.
static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
@@ -2522,10 +2664,6 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
return true;
}
-static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
- QualType Type, const LValue &LVal,
- APValue &RVal);
-
/// Try to evaluate the initializer for a variable declaration.
///
/// \param Info Information about the ongoing evaluation.
@@ -2643,6 +2781,9 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
/// Extract the value of a character from a string literal.
static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
uint64_t Index) {
+ assert(!isa<SourceLocExpr>(Lit) &&
+ "SourceLocExpr should have already been converted to a StringLiteral");
+
// FIXME: Support MakeStringConstant
if (const auto *ObjCEnc = dyn_cast<ObjCEncodeExpr>(Lit)) {
std::string Str;
@@ -2668,9 +2809,11 @@ static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
}
// Expand a string literal into an array of characters.
-static void expandStringLiteral(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 StringLiteral *S = cast<StringLiteral>(Lit);
const ConstantArrayType *CAT =
Info.Ctx.getAsConstantArrayType(S->getType());
assert(CAT && "string literal isn't an array");
@@ -2769,28 +2912,73 @@ static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
return false;
}
+static bool lifetimeStartedInEvaluation(EvalInfo &Info,
+ APValue::LValueBase Base) {
+ // A temporary we created.
+ if (Base.getCallIndex())
+ return true;
+
+ auto *Evaluating = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>();
+ 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;
+
+ // 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;
+
+ return false;
+}
+
namespace {
/// A handle to a complete object (an object that is not a subobject of
/// another object).
struct CompleteObject {
+ /// The identity of the object.
+ APValue::LValueBase Base;
/// The value of the complete object.
APValue *Value;
/// The type of the complete object.
QualType Type;
- bool LifetimeStartedInEvaluation;
CompleteObject() : Value(nullptr) {}
- CompleteObject(APValue *Value, QualType Type,
- bool LifetimeStartedInEvaluation)
- : Value(Value), Type(Type),
- LifetimeStartedInEvaluation(LifetimeStartedInEvaluation) {
- assert(Value && "missing value for complete object");
+ CompleteObject(APValue::LValueBase Base, APValue *Value, QualType Type)
+ : Base(Base), Value(Value), Type(Type) {}
+
+ bool mayReadMutableMembers(EvalInfo &Info) 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);
}
- explicit operator bool() const { return Value; }
+ explicit operator bool() const { return !Type.isNull(); }
};
} // end anonymous namespace
+static QualType getSubobjectType(QualType ObjType, QualType SubobjType,
+ bool IsMutable = false) {
+ // C++ [basic.type.qualifier]p1:
+ // - A const object is an object of type const T or a non-mutable subobject
+ // of a const object.
+ if (ObjType.isConstQualified() && !IsMutable)
+ SubobjType.addConst();
+ // - A volatile object is an object of type const T or a subobject of a
+ // volatile object.
+ if (ObjType.isVolatileQualified())
+ SubobjType.addVolatile();
+ return SubobjType;
+}
+
/// Find the designated sub-object of an rvalue.
template<typename SubobjectHandler>
typename SubobjectHandler::result_type
@@ -2813,31 +3001,78 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
APValue *O = Obj.Value;
QualType ObjType = Obj.Type;
const FieldDecl *LastField = nullptr;
- const bool MayReadMutableMembers =
- Obj.LifetimeStartedInEvaluation && Info.getLangOpts().CPlusPlus14;
+ const FieldDecl *VolatileField = nullptr;
// Walk the designator's path to find the subobject.
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
- if (O->isUninit()) {
+ // Reading an indeterminate value is undefined, but assigning over one is OK.
+ if (O->isAbsent() || (O->isIndeterminate() && handler.AccessKind != AK_Assign)) {
if (!Info.checkingPotentialConstantExpression())
- Info.FFDiag(E, diag::note_constexpr_access_uninit) << handler.AccessKind;
+ Info.FFDiag(E, diag::note_constexpr_access_uninit)
+ << handler.AccessKind << O->isIndeterminate();
return handler.failed();
}
- if (I == N) {
+ // C++ [class.ctor]p5:
+ // const and volatile semantics are not applied on an object under
+ // construction.
+ if ((ObjType.isConstQualified() || ObjType.isVolatileQualified()) &&
+ ObjType->isRecordType() &&
+ Info.isEvaluatingConstructor(
+ Obj.Base, llvm::makeArrayRef(Sub.Entries.begin(),
+ Sub.Entries.begin() + I)) !=
+ ConstructionPhase::None) {
+ ObjType = Info.Ctx.getCanonicalType(ObjType);
+ ObjType.removeLocalConst();
+ ObjType.removeLocalVolatile();
+ }
+
+ // If this is our last pass, check that the final object type is OK.
+ if (I == N || (I == N - 1 && ObjType->isAnyComplexType())) {
+ // Accesses to volatile objects are prohibited.
+ if (ObjType.isVolatileQualified() && isFormalAccess(handler.AccessKind)) {
+ if (Info.getLangOpts().CPlusPlus) {
+ int DiagKind;
+ SourceLocation Loc;
+ const NamedDecl *Decl = nullptr;
+ if (VolatileField) {
+ DiagKind = 2;
+ Loc = VolatileField->getLocation();
+ Decl = VolatileField;
+ } else if (auto *VD = Obj.Base.dyn_cast<const ValueDecl*>()) {
+ DiagKind = 1;
+ Loc = VD->getLocation();
+ Decl = VD;
+ } else {
+ DiagKind = 0;
+ if (auto *E = Obj.Base.dyn_cast<const Expr *>())
+ Loc = E->getExprLoc();
+ }
+ Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1)
+ << handler.AccessKind << DiagKind << Decl;
+ Info.Note(Loc, diag::note_constexpr_volatile_here) << DiagKind;
+ } else {
+ Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
+ }
+ return handler.failed();
+ }
+
// If we are reading an object of class type, there may still be more
// 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 &&
- !MayReadMutableMembers && diagnoseUnreadableFields(Info, E, ObjType))
+ !Obj.mayReadMutableMembers(Info) &&
+ diagnoseUnreadableFields(Info, E, ObjType))
return handler.failed();
+ }
+ if (I == N) {
if (!handler.found(*O, ObjType))
return false;
// If we modified a bit-field, truncate it to the right width.
- if (handler.AccessKind != AK_Read &&
+ if (isModification(handler.AccessKind) &&
LastField && LastField->isBitField() &&
!truncateBitfieldValue(Info, E, *O, LastField))
return false;
@@ -2850,7 +3085,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// Next subobject is an array element.
const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType);
assert(CAT && "vla in literal type?");
- uint64_t Index = Sub.Entries[I].ArrayIndex;
+ uint64_t Index = Sub.Entries[I].getAsArrayIndex();
if (CAT->getSize().ule(Index)) {
// Note, it should not be possible to form a pointer with a valid
// designator which points more than one past the end of the array.
@@ -2864,18 +3099,6 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
ObjType = CAT->getElementType();
- // An array object is represented as either an Array APValue or as an
- // LValue which refers to a string literal.
- if (O->isLValue()) {
- assert(I == N - 1 && "extracting subobject of character?");
- assert(!O->hasLValuePath() || O->getLValuePath().empty());
- if (handler.AccessKind != AK_Read)
- expandStringLiteral(Info, O->getLValueBase().get<const Expr *>(),
- *O);
- else
- return handler.foundString(*O, ObjType, Index);
- }
-
if (O->getArrayInitializedElts() > Index)
O = &O->getArrayInitializedElt(Index);
else if (handler.AccessKind != AK_Read) {
@@ -2885,7 +3108,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
O = &O->getArrayFiller();
} else if (ObjType->isAnyComplexType()) {
// Next subobject is a complex number.
- uint64_t Index = Sub.Entries[I].ArrayIndex;
+ uint64_t Index = Sub.Entries[I].getAsArrayIndex();
if (Index > 1) {
if (Info.getLangOpts().CPlusPlus11)
Info.FFDiag(E, diag::note_constexpr_access_past_end)
@@ -2895,10 +3118,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
return handler.failed();
}
- bool WasConstQualified = ObjType.isConstQualified();
- ObjType = ObjType->castAs<ComplexType>()->getElementType();
- if (WasConstQualified)
- ObjType.addConst();
+ ObjType = getSubobjectType(
+ ObjType, ObjType->castAs<ComplexType>()->getElementType());
assert(I == N - 1 && "extracting subobject of scalar?");
if (O->isComplexInt()) {
@@ -2910,11 +3131,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
: O->getComplexFloatReal(), ObjType);
}
} else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
- // 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 (Field->isMutable() && handler.AccessKind == AK_Read &&
- !MayReadMutableMembers) {
+ !Obj.mayReadMutableMembers(Info)) {
Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1)
<< Field;
Info.Note(Field->getLocation(), diag::note_declared_at);
@@ -2935,34 +3153,17 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
} else
O = &O->getStructField(Field->getFieldIndex());
- bool WasConstQualified = ObjType.isConstQualified();
- ObjType = Field->getType();
- if (WasConstQualified && !Field->isMutable())
- ObjType.addConst();
-
- if (ObjType.isVolatileQualified()) {
- if (Info.getLangOpts().CPlusPlus) {
- // FIXME: Include a description of the path to the volatile subobject.
- Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1)
- << handler.AccessKind << 2 << Field;
- Info.Note(Field->getLocation(), diag::note_declared_at);
- } else {
- Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
- }
- return handler.failed();
- }
-
+ ObjType = getSubobjectType(ObjType, Field->getType(), Field->isMutable());
LastField = Field;
+ if (Field->getType().isVolatileQualified())
+ VolatileField = Field;
} else {
// Next subobject is a base class.
const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl();
const CXXRecordDecl *Base = getAsBaseClass(Sub.Entries[I]);
O = &O->getStructBase(getBaseIndex(Derived, Base));
- bool WasConstQualified = ObjType.isConstQualified();
- ObjType = Info.Ctx.getRecordType(Base);
- if (WasConstQualified)
- ObjType.addConst();
+ ObjType = getSubobjectType(ObjType, Info.Ctx.getRecordType(Base));
}
}
}
@@ -2988,11 +3189,6 @@ struct ExtractSubobjectHandler {
Result = APValue(Value);
return true;
}
- bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) {
- Result = APValue(extractStringLiteralCharacter(
- Info, Subobj.getLValueBase().get<const Expr *>(), Character));
- return true;
- }
};
} // end anonymous namespace
@@ -3050,9 +3246,6 @@ struct ModifySubobjectHandler {
Value = NewVal.getFloat();
return true;
}
- bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) {
- llvm_unreachable("shouldn't encounter string elements with ExpandArrays");
- }
};
} // end anonymous namespace
@@ -3078,7 +3271,7 @@ static unsigned FindDesignatorMismatch(QualType ObjType,
if (!ObjType.isNull() &&
(ObjType->isArrayType() || ObjType->isAnyComplexType())) {
// Next subobject is an array element.
- if (A.Entries[I].ArrayIndex != B.Entries[I].ArrayIndex) {
+ if (A.Entries[I].getAsArrayIndex() != B.Entries[I].getAsArrayIndex()) {
WasArrayIndex = true;
return I;
}
@@ -3087,7 +3280,8 @@ static unsigned FindDesignatorMismatch(QualType ObjType,
else
ObjType = ObjType->castAsArrayTypeUnsafe()->getElementType();
} else {
- if (A.Entries[I].BaseOrMember != B.Entries[I].BaseOrMember) {
+ if (A.Entries[I].getAsBaseOrMember() !=
+ B.Entries[I].getAsBaseOrMember()) {
WasArrayIndex = false;
return I;
}
@@ -3128,14 +3322,21 @@ static bool AreElementsOfSameArray(QualType ObjType,
static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
AccessKinds AK, const LValue &LVal,
QualType LValType) {
+ if (LVal.InvalidBase) {
+ Info.FFDiag(E);
+ return CompleteObject();
+ }
+
if (!LVal.Base) {
Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
return CompleteObject();
}
CallStackFrame *Frame = nullptr;
+ unsigned Depth = 0;
if (LVal.getLValueCallIndex()) {
- Frame = Info.getCallFrame(LVal.getLValueCallIndex());
+ std::tie(Frame, Depth) =
+ Info.getCallFrameAndDepth(LVal.getLValueCallIndex());
if (!Frame) {
Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1)
<< AK << LVal.Base.is<const ValueDecl*>();
@@ -3144,11 +3345,13 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
}
+ bool IsAccess = isFormalAccess(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 (LValType.isVolatileQualified()) {
+ if (IsAccess && LValType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus)
Info.FFDiag(E, diag::note_constexpr_access_volatile_type)
<< AK << LValType;
@@ -3160,7 +3363,6 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// Compute value storage location and type of base object.
APValue *BaseVal = nullptr;
QualType BaseType = getType(LVal.Base);
- bool LifetimeStartedInEvaluation = Frame;
if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) {
// In C++98, const, non-volatile integers initialized with ICEs are ICEs.
@@ -3180,37 +3382,29 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
return CompleteObject();
}
- // Accesses of volatile-qualified objects are not allowed.
- if (BaseType.isVolatileQualified()) {
- if (Info.getLangOpts().CPlusPlus) {
- Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1)
- << AK << 1 << VD;
- Info.Note(VD->getLocation(), diag::note_declared_at);
- } else {
- Info.FFDiag(E);
- }
- return CompleteObject();
- }
-
// Unless we're looking at a local variable or argument in a constexpr call,
// the variable we're reading must be const.
if (!Frame) {
if (Info.getLangOpts().CPlusPlus14 &&
- VD == Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()) {
+ declaresSameEntity(
+ VD, Info.EvaluatingDecl.dyn_cast<const ValueDecl *>())) {
// 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.
- } else if (AK != AK_Read) {
- // All the remaining cases only permit reading.
+ } else if (isModification(AK)) {
+ // All the remaining cases do not permit modification of the object.
Info.FFDiag(E, diag::note_constexpr_modify_global);
return CompleteObject();
} else if (VD->isConstexpr()) {
// OK, we can read this variable.
} else if (BaseType->isIntegralOrEnumerationType()) {
- // In OpenCL if a variable is in constant address space it is a const value.
+ // In OpenCL if a variable is in constant address space it is a const
+ // value.
if (!(BaseType.isConstQualified() ||
(Info.getLangOpts().OpenCL &&
BaseType.getAddressSpace() == LangAS::opencl_constant))) {
+ if (!IsAccess)
+ return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
if (Info.getLangOpts().CPlusPlus) {
Info.FFDiag(E, diag::note_constexpr_ltor_non_const_int, 1) << VD;
Info.Note(VD->getLocation(), diag::note_declared_at);
@@ -3219,6 +3413,8 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
return CompleteObject();
}
+ } else if (!IsAccess) {
+ return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
} else if (BaseType->isFloatingType() && BaseType.isConstQualified()) {
// We support folding of const floating-point types, in order to make
// static const data members of such types (supported as an extension)
@@ -3255,7 +3451,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (!Frame) {
if (const MaterializeTemporaryExpr *MTE =
- dyn_cast<MaterializeTemporaryExpr>(Base)) {
+ dyn_cast_or_null<MaterializeTemporaryExpr>(Base)) {
assert(MTE->getStorageDuration() == SD_Static &&
"should have a frame for a non-global materialized temporary");
@@ -3278,6 +3474,8 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (!(BaseType.isConstQualified() &&
BaseType->isIntegralOrEnumerationType()) &&
!(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) {
+ if (!IsAccess)
+ return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
Info.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here);
return CompleteObject();
@@ -3285,38 +3483,22 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
assert(BaseVal && "got reference to unevaluated temporary");
- LifetimeStartedInEvaluation = true;
} else {
- Info.FFDiag(E);
+ if (!IsAccess)
+ return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
+ APValue Val;
+ LVal.moveInto(Val);
+ Info.FFDiag(E, diag::note_constexpr_access_unreadable_object)
+ << AK
+ << Val.getAsString(Info.Ctx,
+ Info.Ctx.getLValueReferenceType(LValType));
+ NoteLValueLocation(Info, LVal.Base);
return CompleteObject();
}
} else {
BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
assert(BaseVal && "missing value for temporary");
}
-
- // Volatile temporary objects cannot be accessed in constant expressions.
- if (BaseType.isVolatileQualified()) {
- if (Info.getLangOpts().CPlusPlus) {
- Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1)
- << AK << 0;
- Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here);
- } else {
- Info.FFDiag(E);
- }
- return CompleteObject();
- }
- }
-
- // During the construction of an object, it is not yet 'const'.
- // FIXME: This doesn't do quite the right thing for const subobjects of the
- // object under construction.
- if (Info.isEvaluatingConstructor(LVal.getLValueBase(),
- LVal.getLValueCallIndex(),
- LVal.getLValueVersion())) {
- BaseType = Info.Ctx.getCanonicalType(BaseType);
- BaseType.removeLocalConst();
- LifetimeStartedInEvaluation = true;
}
// In C++14, we can't safely access any mutable state when we might be
@@ -3326,10 +3508,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// to be read here (but take care with 'mutable' fields).
if ((Frame && Info.getLangOpts().CPlusPlus14 &&
Info.EvalStatus.HasSideEffects) ||
- (AK != AK_Read && Info.IsSpeculativelyEvaluating))
+ (isModification(AK) && Depth < Info.SpeculativeEvaluationDepth))
return CompleteObject();
- return CompleteObject(BaseVal, BaseType, LifetimeStartedInEvaluation);
+ return CompleteObject(LVal.getLValueBase(), BaseVal, BaseType);
}
/// Perform an lvalue-to-rvalue conversion on the given glvalue. This
@@ -3351,6 +3533,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
// Check for special cases where there is no existing APValue to look at.
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
+
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
@@ -3363,15 +3546,30 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
APValue Lit;
if (!Evaluate(Lit, Info, CLE->getInitializer()))
return false;
- CompleteObject LitObj(&Lit, Base->getType(), false);
+ CompleteObject LitObj(LVal.Base, &Lit, Base->getType());
return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal);
} else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) {
- // We represent a string literal array as an lvalue pointing at the
- // corresponding expression, rather than building an array of chars.
- // FIXME: Support ObjCEncodeExpr, MakeStringConstant
- APValue Str(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0);
- CompleteObject StrObj(&Str, Base->getType(), false);
- return extractSubobject(Info, Conv, StrObj, LVal.Designator, RVal);
+ // Special-case character extraction so we don't have to construct an
+ // APValue for the whole string.
+ assert(LVal.Designator.Entries.size() <= 1 &&
+ "Can only read characters from string literals");
+ if (LVal.Designator.Entries.empty()) {
+ // Fail for now for LValue to RValue conversion of an array.
+ // (This shouldn't show up in C/C++, but it could be triggered by a
+ // weird EvaluateAsRValue call from a tool.)
+ Info.FFDiag(Conv);
+ return false;
+ }
+ if (LVal.Designator.isOnePastTheEnd()) {
+ if (Info.getLangOpts().CPlusPlus11)
+ Info.FFDiag(Conv, diag::note_constexpr_access_past_end) << AK_Read;
+ else
+ Info.FFDiag(Conv);
+ return false;
+ }
+ uint64_t CharIndex = LVal.Designator.Entries[0].getAsArrayIndex();
+ RVal = APValue(extractStringLiteralCharacter(Info, Base, CharIndex));
+ return true;
}
}
@@ -3497,9 +3695,6 @@ struct CompoundAssignSubobjectHandler {
LVal.moveInto(Subobj);
return true;
}
- bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) {
- llvm_unreachable("shouldn't encounter string elements here");
- }
};
} // end anonymous namespace
@@ -3648,9 +3843,6 @@ struct IncDecSubobjectHandler {
LVal.moveInto(Subobj);
return true;
}
- bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) {
- llvm_unreachable("shouldn't encounter string elements here");
- }
};
} // end anonymous namespace
@@ -4359,9 +4551,20 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
return false;
}
+ // DR1872: An instantiated virtual constexpr function can't be called in a
+ // constant expression (prior to C++20). We can still constant-fold such a
+ // call.
+ if (!Info.Ctx.getLangOpts().CPlusPlus2a && isa<CXXMethodDecl>(Declaration) &&
+ cast<CXXMethodDecl>(Declaration)->isVirtual())
+ Info.CCEDiag(CallLoc, diag::note_constexpr_virtual_call);
+
+ if (Definition && Definition->isInvalidDecl()) {
+ Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
+
// Can we evaluate this function call?
- if (Definition && Definition->isConstexpr() &&
- !Definition->isInvalidDecl() && Body)
+ if (Definition && Definition->isConstexpr() && Body)
return true;
if (Info.getLangOpts().CPlusPlus11) {
@@ -4392,6 +4595,487 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
return false;
}
+namespace {
+struct CheckDynamicTypeHandler {
+ AccessKinds AccessKind;
+ typedef bool result_type;
+ bool failed() { return false; }
+ bool found(APValue &Subobj, QualType SubobjType) { return true; }
+ bool found(APSInt &Value, QualType SubobjType) { return true; }
+ bool found(APFloat &Value, QualType SubobjType) { return true; }
+};
+} // end anonymous namespace
+
+/// Check that we can access the notional vptr of an object / determine its
+/// dynamic type.
+static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This,
+ AccessKinds AK, bool Polymorphic) {
+ if (This.Designator.Invalid)
+ return false;
+
+ CompleteObject Obj = findCompleteObject(Info, E, AK, This, QualType());
+
+ if (!Obj)
+ return false;
+
+ if (!Obj.Value) {
+ // The object is not usable in constant expressions, so we can't inspect
+ // its value to see if it's in-lifetime or what the active union members
+ // are. We can still check for a one-past-the-end lvalue.
+ if (This.Designator.isOnePastTheEnd() ||
+ This.Designator.isMostDerivedAnUnsizedArray()) {
+ Info.FFDiag(E, This.Designator.isOnePastTheEnd()
+ ? diag::note_constexpr_access_past_end
+ : diag::note_constexpr_access_unsized_array)
+ << AK;
+ return false;
+ } else if (Polymorphic) {
+ // Conservatively refuse to perform a polymorphic operation if we would
+ // not be able to read a notional 'vptr' value.
+ APValue Val;
+ This.moveInto(Val);
+ QualType StarThisType =
+ Info.Ctx.getLValueReferenceType(This.Designator.getType(Info.Ctx));
+ Info.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
+ << AK << Val.getAsString(Info.Ctx, StarThisType);
+ return false;
+ }
+ return true;
+ }
+
+ CheckDynamicTypeHandler Handler{AK};
+ return Obj && findSubobject(Info, E, Obj, This.Designator, Handler);
+}
+
+/// 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);
+}
+
+struct DynamicType {
+ /// The dynamic class type of the object.
+ const CXXRecordDecl *Type;
+ /// The corresponding path length in the lvalue.
+ unsigned PathLength;
+};
+
+static const CXXRecordDecl *getBaseClassType(SubobjectDesignator &Designator,
+ unsigned PathLength) {
+ assert(PathLength >= Designator.MostDerivedPathLength && PathLength <=
+ Designator.Entries.size() && "invalid path length");
+ return (PathLength == Designator.MostDerivedPathLength)
+ ? Designator.MostDerivedType->getAsCXXRecordDecl()
+ : getAsBaseClass(Designator.Entries[PathLength - 1]);
+}
+
+/// Determine the dynamic type of an object.
+static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E,
+ LValue &This, AccessKinds AK) {
+ // If we don't have an lvalue denoting an object of class type, there is no
+ // meaningful dynamic type. (We consider objects of non-class type to have no
+ // dynamic type.)
+ if (!checkDynamicType(Info, E, This, AK, true))
+ return None;
+
+ // Refuse to compute a dynamic type in the presence of virtual bases. This
+ // shouldn't happen other than in constant-folding situations, since literal
+ // types can't have virtual bases.
+ //
+ // Note that consumers of DynamicType assume that the type has no virtual
+ // bases, and will need modifications if this restriction is relaxed.
+ const CXXRecordDecl *Class =
+ This.Designator.MostDerivedType->getAsCXXRecordDecl();
+ if (!Class || Class->getNumVBases()) {
+ Info.FFDiag(E);
+ return None;
+ }
+
+ // FIXME: For very deep class hierarchies, it might be beneficial to use a
+ // binary search here instead. But the overwhelmingly common case is that
+ // we're not in the middle of a constructor, so it probably doesn't matter
+ // in practice.
+ 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))) {
+ case ConstructionPhase::Bases:
+ // We're constructing 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.
+ return DynamicType{getBaseClassType(This.Designator, PathLength),
+ PathLength};
+ }
+ }
+
+ // CWG issue 1517: we're constructing a base class of the object described by
+ // 'This', so that object has not yet begun its period of construction and
+ // any polymorphic operation on it results in undefined behavior.
+ Info.FFDiag(E);
+ return None;
+}
+
+/// Perform virtual dispatch.
+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);
+ if (!DynType)
+ return nullptr;
+
+ // Find the final overrider. It must be declared in one of the classes on the
+ // path from the dynamic type to the static type.
+ // FIXME: If we ever allow literal types to have virtual base classes, that
+ // won't be true.
+ const CXXMethodDecl *Callee = Found;
+ unsigned PathLength = DynType->PathLength;
+ for (/**/; PathLength <= This.Designator.Entries.size(); ++PathLength) {
+ const CXXRecordDecl *Class = getBaseClassType(This.Designator, PathLength);
+ const CXXMethodDecl *Overrider =
+ Found->getCorrespondingMethodDeclaredInClass(Class, false);
+ if (Overrider) {
+ Callee = Overrider;
+ break;
+ }
+ }
+
+ // C++2a [class.abstract]p6:
+ // the effect of making a virtual call to a pure virtual function [...] is
+ // undefined
+ if (Callee->isPure()) {
+ Info.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << Callee;
+ Info.Note(Callee->getLocation(), diag::note_declared_at);
+ return nullptr;
+ }
+
+ // If necessary, walk the rest of the path to determine the sequence of
+ // covariant adjustment steps to apply.
+ if (!Info.Ctx.hasSameUnqualifiedType(Callee->getReturnType(),
+ Found->getReturnType())) {
+ CovariantAdjustmentPath.push_back(Callee->getReturnType());
+ for (unsigned CovariantPathLength = PathLength + 1;
+ CovariantPathLength != This.Designator.Entries.size();
+ ++CovariantPathLength) {
+ const CXXRecordDecl *NextClass =
+ getBaseClassType(This.Designator, CovariantPathLength);
+ const CXXMethodDecl *Next =
+ Found->getCorrespondingMethodDeclaredInClass(NextClass, false);
+ if (Next && !Info.Ctx.hasSameUnqualifiedType(
+ Next->getReturnType(), CovariantAdjustmentPath.back()))
+ CovariantAdjustmentPath.push_back(Next->getReturnType());
+ }
+ if (!Info.Ctx.hasSameUnqualifiedType(Found->getReturnType(),
+ CovariantAdjustmentPath.back()))
+ CovariantAdjustmentPath.push_back(Found->getReturnType());
+ }
+
+ // Perform 'this' adjustment.
+ if (!CastToDerivedClass(Info, E, This, Callee->getParent(), PathLength))
+ return nullptr;
+
+ return Callee;
+}
+
+/// Perform the adjustment from a value returned by a virtual function to
+/// a value of the statically expected type, which may be a pointer or
+/// reference to a base class of the returned type.
+static bool HandleCovariantReturnAdjustment(EvalInfo &Info, const Expr *E,
+ APValue &Result,
+ ArrayRef<QualType> Path) {
+ assert(Result.isLValue() &&
+ "unexpected kind of APValue for covariant return");
+ if (Result.isNullPointer())
+ return true;
+
+ LValue LVal;
+ LVal.setFrom(Info.Ctx, Result);
+
+ const CXXRecordDecl *OldClass = Path[0]->getPointeeCXXRecordDecl();
+ for (unsigned I = 1; I != Path.size(); ++I) {
+ const CXXRecordDecl *NewClass = Path[I]->getPointeeCXXRecordDecl();
+ assert(OldClass && NewClass && "unexpected kind of covariant return");
+ if (OldClass != NewClass &&
+ !CastToBaseClass(Info, E, LVal, OldClass, NewClass))
+ return false;
+ OldClass = NewClass;
+ }
+
+ LVal.moveInto(Result);
+ return true;
+}
+
+/// Determine whether \p Base, which is known to be a direct base class of
+/// \p Derived, is a public base class.
+static bool isBaseClassPublic(const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Base) {
+ for (const CXXBaseSpecifier &BaseSpec : Derived->bases()) {
+ auto *BaseClass = BaseSpec.getType()->getAsCXXRecordDecl();
+ if (BaseClass && declaresSameEntity(BaseClass, Base))
+ return BaseSpec.getAccessSpecifier() == AS_public;
+ }
+ llvm_unreachable("Base is not a direct base of Derived");
+}
+
+/// Apply the given dynamic cast operation on the provided lvalue.
+///
+/// This implements the hard case of dynamic_cast, requiring a "runtime check"
+/// to find a suitable target subobject.
+static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E,
+ LValue &Ptr) {
+ // We can't do anything with a non-symbolic pointer value.
+ SubobjectDesignator &D = Ptr.Designator;
+ if (D.Invalid)
+ return false;
+
+ // C++ [expr.dynamic.cast]p6:
+ // If v is a null pointer value, the result is a null pointer value.
+ if (Ptr.isNullPointer() && !E->isGLValue())
+ return true;
+
+ // For all the other cases, we need the pointer to point to an object within
+ // its lifetime / period of construction / destruction, and we need to know
+ // its dynamic type.
+ Optional<DynamicType> DynType =
+ ComputeDynamicType(Info, E, Ptr, AK_DynamicCast);
+ if (!DynType)
+ return false;
+
+ // C++ [expr.dynamic.cast]p7:
+ // If T is "pointer to cv void", then the result is a pointer to the most
+ // derived object
+ if (E->getType()->isVoidPointerType())
+ return CastToDerivedClass(Info, E, Ptr, DynType->Type, DynType->PathLength);
+
+ const CXXRecordDecl *C = E->getTypeAsWritten()->getPointeeCXXRecordDecl();
+ assert(C && "dynamic_cast target is not void pointer nor class");
+ CanQualType CQT = Info.Ctx.getCanonicalType(Info.Ctx.getRecordType(C));
+
+ auto RuntimeCheckFailed = [&] (CXXBasePaths *Paths) {
+ // C++ [expr.dynamic.cast]p9:
+ 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);
+ return true;
+ }
+
+ // A failed cast to reference type throws [...] std::bad_cast.
+ unsigned DiagKind;
+ if (!Paths && (declaresSameEntity(DynType->Type, C) ||
+ DynType->Type->isDerivedFrom(C)))
+ DiagKind = 0;
+ else if (!Paths || Paths->begin() == Paths->end())
+ DiagKind = 1;
+ else if (Paths->isAmbiguous(CQT))
+ DiagKind = 2;
+ else {
+ assert(Paths->front().Access != AS_public && "why did the cast fail?");
+ DiagKind = 3;
+ }
+ Info.FFDiag(E, diag::note_constexpr_dynamic_cast_to_reference_failed)
+ << DiagKind << Ptr.Designator.getType(Info.Ctx)
+ << Info.Ctx.getRecordType(DynType->Type)
+ << E->getType().getUnqualifiedType();
+ return false;
+ };
+
+ // Runtime check, phase 1:
+ // Walk from the base subobject towards the derived object looking for the
+ // target type.
+ for (int PathLength = Ptr.Designator.Entries.size();
+ PathLength >= (int)DynType->PathLength; --PathLength) {
+ const CXXRecordDecl *Class = getBaseClassType(Ptr.Designator, PathLength);
+ if (declaresSameEntity(Class, C))
+ return CastToDerivedClass(Info, E, Ptr, Class, PathLength);
+ // We can only walk across public inheritance edges.
+ if (PathLength > (int)DynType->PathLength &&
+ !isBaseClassPublic(getBaseClassType(Ptr.Designator, PathLength - 1),
+ Class))
+ return RuntimeCheckFailed(nullptr);
+ }
+
+ // Runtime check, phase 2:
+ // Search the dynamic type for an unambiguous public base of type C.
+ CXXBasePaths Paths(/*FindAmbiguities=*/true,
+ /*RecordPaths=*/true, /*DetectVirtual=*/false);
+ if (DynType->Type->isDerivedFrom(C, Paths) && !Paths.isAmbiguous(CQT) &&
+ Paths.front().Access == AS_public) {
+ // Downcast to the dynamic type...
+ if (!CastToDerivedClass(Info, E, Ptr, DynType->Type, DynType->PathLength))
+ return false;
+ // ... then upcast to the chosen base class subobject.
+ for (CXXBasePathElement &Elem : Paths.front())
+ if (!HandleLValueBase(Info, E, Ptr, Elem.Class, Elem.Base))
+ return false;
+ return true;
+ }
+
+ // Otherwise, the runtime check fails.
+ return RuntimeCheckFailed(&Paths);
+}
+
+namespace {
+struct StartLifetimeOfUnionMemberHandler {
+ const FieldDecl *Field;
+
+ 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) {
+ // We are supposed to perform no initialization but begin the lifetime of
+ // the object. We interpret that as meaning to do what default
+ // initialization of the object would do if all constructors involved were
+ // trivial:
+ // * All base, non-variant member, and array element subobjects' lifetimes
+ // begin
+ // * No variant members' lifetimes begin
+ // * All scalar subobjects whose lifetimes begin have indeterminate values
+ assert(SubobjType->isUnionType());
+ if (!declaresSameEntity(Subobj.getUnionField(), Field))
+ Subobj.setUnion(Field, getDefaultInitValue(Field->getType()));
+ return true;
+ }
+ bool found(APSInt &Value, QualType SubobjType) {
+ llvm_unreachable("wrong value kind for union object");
+ }
+ bool found(APFloat &Value, QualType SubobjType) {
+ llvm_unreachable("wrong value kind for union object");
+ }
+};
+} // end anonymous namespace
+
+const AccessKinds StartLifetimeOfUnionMemberHandler::AccessKind;
+
+/// Handle a builtin simple-assignment or a call to a trivial assignment
+/// operator whose left-hand side might involve a union member access. If it
+/// does, implicitly start the lifetime of any accessed union elements per
+/// C++20 [class.union]5.
+static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,
+ const LValue &LHS) {
+ if (LHS.InvalidBase || LHS.Designator.Invalid)
+ return false;
+
+ llvm::SmallVector<std::pair<unsigned, const FieldDecl*>, 4> UnionPathLengths;
+ // C++ [class.union]p5:
+ // define the set S(E) of subexpressions of E as follows:
+ unsigned PathLength = LHS.Designator.Entries.size();
+ for (const Expr *E = LHSExpr; E != nullptr;) {
+ // -- 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)
+ break;
+
+ // ... and also contains A.B if B names a union member
+ if (FD->getParent()->isUnion())
+ UnionPathLengths.push_back({PathLength - 1, FD});
+
+ E = ME->getBase();
+ --PathLength;
+ assert(declaresSameEntity(FD,
+ LHS.Designator.Entries[PathLength]
+ .getAsBaseOrMember().getPointer()));
+
+ // -- If E is of the form A[B] and is interpreted as a built-in array
+ // subscripting operator, S(E) is [S(the array operand, if any)].
+ } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
+ // Step over an ArrayToPointerDecay implicit cast.
+ auto *Base = ASE->getBase()->IgnoreImplicit();
+ if (!Base->getType()->isArrayType())
+ break;
+
+ E = Base;
+ --PathLength;
+
+ } else if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ // Step over a derived-to-base conversion.
+ E = ICE->getSubExpr();
+ if (ICE->getCastKind() == CK_NoOp)
+ continue;
+ if (ICE->getCastKind() != CK_DerivedToBase &&
+ ICE->getCastKind() != CK_UncheckedDerivedToBase)
+ break;
+ // Walk path backwards as we walk up from the base to the derived class.
+ for (const CXXBaseSpecifier *Elt : llvm::reverse(ICE->path())) {
+ --PathLength;
+ (void)Elt;
+ assert(declaresSameEntity(Elt->getType()->getAsCXXRecordDecl(),
+ LHS.Designator.Entries[PathLength]
+ .getAsBaseOrMember().getPointer()));
+ }
+
+ // -- Otherwise, S(E) is empty.
+ } else {
+ break;
+ }
+ }
+
+ // Common case: no unions' lifetimes are started.
+ if (UnionPathLengths.empty())
+ return true;
+
+ // if modification of X [would access an inactive union member], an object
+ // of the type of X is implicitly created
+ CompleteObject Obj =
+ findCompleteObject(Info, LHSExpr, AK_Assign, LHS, LHSExpr->getType());
+ if (!Obj)
+ return false;
+ for (std::pair<unsigned, const FieldDecl *> LengthAndField :
+ llvm::reverse(UnionPathLengths)) {
+ // Form a designator for the union object.
+ SubobjectDesignator D = LHS.Designator;
+ D.truncate(Info.Ctx, LHS.Base, LengthAndField.first);
+
+ StartLifetimeOfUnionMemberHandler StartLifetime{LengthAndField.second};
+ if (!findSubobject(Info, LHSExpr, Obj, D, StartLifetime))
+ return false;
+ }
+
+ return true;
+}
+
/// Determine if a class has any fields that might need to be copied by a
/// trivial copy or move operation.
static bool hasFields(const CXXRecordDecl *RD) {
@@ -4413,9 +5097,25 @@ typedef SmallVector<APValue, 8> ArgVector;
}
/// EvaluateArgs - Evaluate the arguments to a function call.
-static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
- EvalInfo &Info) {
+static bool EvaluateArgs(ArrayRef<const Expr *> Args, ArgVector &ArgValues,
+ EvalInfo &Info, const FunctionDecl *Callee) {
bool Success = true;
+ llvm::SmallBitVector ForbiddenNullArgs;
+ if (Callee->hasAttr<NonNullAttr>()) {
+ ForbiddenNullArgs.resize(Args.size());
+ for (const auto *Attr : Callee->specific_attrs<NonNullAttr>()) {
+ if (!Attr->args_size()) {
+ ForbiddenNullArgs.set();
+ break;
+ } else
+ for (auto Idx : Attr->args()) {
+ unsigned ASTIdx = Idx.getASTIndex();
+ if (ASTIdx >= Args.size())
+ continue;
+ ForbiddenNullArgs[ASTIdx] = 1;
+ }
+ }
+ }
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) {
@@ -4424,6 +5124,13 @@ static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
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);
+ if (!Info.noteFailure())
+ return false;
+ Success = false;
}
}
return Success;
@@ -4436,7 +5143,7 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
EvalInfo &Info, APValue &Result,
const LValue *ResultSlot) {
ArgVector ArgValues(Args.size());
- if (!EvaluateArgs(Args, ArgValues, Info))
+ if (!EvaluateArgs(Args, ArgValues, Info, Callee))
return false;
if (!Info.CheckCallLimit(CallLoc))
@@ -4462,6 +5169,9 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
RHS, RHSValue))
return false;
+ if (Info.getLangOpts().CPlusPlus2a && MD->isTrivial() &&
+ !HandleUnionActiveMemberChange(Info, Args[0], *This))
+ return false;
if (!handleAssignment(Info, Args[0], *This, MD->getThisType(),
RHSValue))
return false;
@@ -4505,8 +5215,9 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
}
EvalInfo::EvaluatingConstructorRAII EvalObj(
- Info, {This.getLValueBase(),
- {This.getLValueCallIndex(), This.getLValueVersion()}});
+ Info,
+ ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries},
+ RD->getNumBases());
CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues);
// FIXME: Creating an APValue just to hold a nonexistent return value is
@@ -4544,7 +5255,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
}
// Reserve space for the struct members.
- if (!RD->isUnion() && Result.isUninit())
+ if (!RD->isUnion() && !Result.hasValue())
Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
std::distance(RD->field_begin(), RD->field_end()));
@@ -4601,7 +5312,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
// subobject other than the first.
// FIXME: In this case, the values of the other subobjects are
// specified, since zero-initialization sets all padding bits to zero.
- if (Value->isUninit() ||
+ if (!Value->hasValue() ||
(Value->isUnion() && Value->getUnionField() != FD)) {
if (CD->isUnion())
*Value = APValue(FD);
@@ -4640,6 +5351,11 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
return false;
Success = false;
}
+
+ // This is the point at which the dynamic type of the object becomes this
+ // class type.
+ if (I->isBaseInitializer() && BasesSeen == RD->getNumBases())
+ EvalObj.finishedConstructingBases();
}
return Success &&
@@ -4651,7 +5367,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
const CXXConstructorDecl *Definition,
EvalInfo &Info, APValue &Result) {
ArgVector ArgValues(Args.size());
- if (!EvaluateArgs(Args, ArgValues, Info))
+ if (!EvaluateArgs(Args, ArgValues, Info, Definition))
return false;
return HandleConstructorCall(E, This, ArgValues.data(), Definition,
@@ -4663,6 +5379,491 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
//===----------------------------------------------------------------------===//
namespace {
+class BitCastBuffer {
+ // FIXME: We're going to need bit-level granularity when we support
+ // bit-fields.
+ // FIXME: Its possible under the C++ standard for 'char' to not be 8 bits, but
+ // we don't support a host or target where that is the case. Still, we should
+ // use a more generic type in case we ever do.
+ SmallVector<Optional<unsigned char>, 32> Bytes;
+
+ static_assert(std::numeric_limits<unsigned char>::digits >= 8,
+ "Need at least 8 bit unsigned char");
+
+ bool TargetIsLittleEndian;
+
+public:
+ BitCastBuffer(CharUnits Width, bool TargetIsLittleEndian)
+ : Bytes(Width.getQuantity()),
+ TargetIsLittleEndian(TargetIsLittleEndian) {}
+
+ LLVM_NODISCARD
+ bool readObject(CharUnits Offset, CharUnits Width,
+ SmallVectorImpl<unsigned char> &Output) const {
+ for (CharUnits I = Offset, E = Offset + Width; I != E; ++I) {
+ // If a byte of an integer is uninitialized, then the whole integer is
+ // uninitalized.
+ if (!Bytes[I.getQuantity()])
+ return false;
+ Output.push_back(*Bytes[I.getQuantity()]);
+ }
+ if (llvm::sys::IsLittleEndianHost != TargetIsLittleEndian)
+ std::reverse(Output.begin(), Output.end());
+ return true;
+ }
+
+ void writeObject(CharUnits Offset, SmallVectorImpl<unsigned char> &Input) {
+ if (llvm::sys::IsLittleEndianHost != TargetIsLittleEndian)
+ std::reverse(Input.begin(), Input.end());
+
+ size_t Index = 0;
+ for (unsigned char Byte : Input) {
+ assert(!Bytes[Offset.getQuantity() + Index] && "overwriting a byte?");
+ Bytes[Offset.getQuantity() + Index] = Byte;
+ ++Index;
+ }
+ }
+
+ size_t size() { return Bytes.size(); }
+};
+
+/// Traverse an APValue to produce an BitCastBuffer, emulating how the current
+/// target would represent the value at runtime.
+class APValueToBufferConverter {
+ EvalInfo &Info;
+ BitCastBuffer Buffer;
+ const CastExpr *BCE;
+
+ APValueToBufferConverter(EvalInfo &Info, CharUnits ObjectWidth,
+ const CastExpr *BCE)
+ : Info(Info),
+ Buffer(ObjectWidth, Info.Ctx.getTargetInfo().isLittleEndian()),
+ BCE(BCE) {}
+
+ bool visit(const APValue &Val, QualType Ty) {
+ return visit(Val, Ty, CharUnits::fromQuantity(0));
+ }
+
+ // Write out Val with type Ty into Buffer starting at Offset.
+ bool visit(const APValue &Val, QualType Ty, CharUnits Offset) {
+ assert((size_t)Offset.getQuantity() <= Buffer.size());
+
+ // As a special case, nullptr_t has an indeterminate value.
+ if (Ty->isNullPtrType())
+ return true;
+
+ // Dig through Src to find the byte at SrcOffset.
+ switch (Val.getKind()) {
+ case APValue::Indeterminate:
+ case APValue::None:
+ return true;
+
+ case APValue::Int:
+ return visitInt(Val.getInt(), Ty, Offset);
+ case APValue::Float:
+ return visitFloat(Val.getFloat(), Ty, Offset);
+ case APValue::Array:
+ return visitArray(Val, Ty, Offset);
+ case APValue::Struct:
+ return visitRecord(Val, Ty, Offset);
+
+ case APValue::ComplexInt:
+ case APValue::ComplexFloat:
+ case APValue::Vector:
+ case APValue::FixedPoint:
+ // FIXME: We should support these.
+
+ case APValue::Union:
+ case APValue::MemberPointer:
+ case APValue::AddrLabelDiff: {
+ Info.FFDiag(BCE->getBeginLoc(),
+ diag::note_constexpr_bit_cast_unsupported_type)
+ << Ty;
+ return false;
+ }
+
+ case APValue::LValue:
+ llvm_unreachable("LValue subobject in bit_cast?");
+ }
+ llvm_unreachable("Unhandled APValue::ValueKind");
+ }
+
+ bool visitRecord(const APValue &Val, QualType Ty, CharUnits Offset) {
+ const RecordDecl *RD = Ty->getAsRecordDecl();
+ const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+
+ // Visit the base classes.
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (size_t I = 0, E = CXXRD->getNumBases(); I != E; ++I) {
+ const CXXBaseSpecifier &BS = CXXRD->bases_begin()[I];
+ CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl();
+
+ if (!visitRecord(Val.getStructBase(I), BS.getType(),
+ Layout.getBaseClassOffset(BaseDecl) + Offset))
+ return false;
+ }
+ }
+
+ // Visit the fields.
+ unsigned FieldIdx = 0;
+ for (FieldDecl *FD : RD->fields()) {
+ if (FD->isBitField()) {
+ Info.FFDiag(BCE->getBeginLoc(),
+ diag::note_constexpr_bit_cast_unsupported_bitfield);
+ return false;
+ }
+
+ uint64_t FieldOffsetBits = Layout.getFieldOffset(FieldIdx);
+
+ assert(FieldOffsetBits % Info.Ctx.getCharWidth() == 0 &&
+ "only bit-fields can have sub-char alignment");
+ CharUnits FieldOffset =
+ Info.Ctx.toCharUnitsFromBits(FieldOffsetBits) + Offset;
+ QualType FieldTy = FD->getType();
+ if (!visit(Val.getStructField(FieldIdx), FieldTy, FieldOffset))
+ return false;
+ ++FieldIdx;
+ }
+
+ return true;
+ }
+
+ bool visitArray(const APValue &Val, QualType Ty, CharUnits Offset) {
+ const auto *CAT =
+ dyn_cast_or_null<ConstantArrayType>(Ty->getAsArrayTypeUnsafe());
+ if (!CAT)
+ return false;
+
+ CharUnits ElemWidth = Info.Ctx.getTypeSizeInChars(CAT->getElementType());
+ unsigned NumInitializedElts = Val.getArrayInitializedElts();
+ unsigned ArraySize = Val.getArraySize();
+ // First, initialize the initialized elements.
+ for (unsigned I = 0; I != NumInitializedElts; ++I) {
+ const APValue &SubObj = Val.getArrayInitializedElt(I);
+ if (!visit(SubObj, CAT->getElementType(), Offset + I * ElemWidth))
+ return false;
+ }
+
+ // Next, initialize the rest of the array using the filler.
+ if (Val.hasArrayFiller()) {
+ const APValue &Filler = Val.getArrayFiller();
+ for (unsigned I = NumInitializedElts; I != ArraySize; ++I) {
+ if (!visit(Filler, CAT->getElementType(), Offset + I * ElemWidth))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool visitInt(const APSInt &Val, QualType Ty, CharUnits Offset) {
+ CharUnits Width = Info.Ctx.getTypeSizeInChars(Ty);
+ SmallVector<unsigned char, 8> Bytes(Width.getQuantity());
+ llvm::StoreIntToMemory(Val, &*Bytes.begin(), Width.getQuantity());
+ Buffer.writeObject(Offset, Bytes);
+ return true;
+ }
+
+ bool visitFloat(const APFloat &Val, QualType Ty, CharUnits Offset) {
+ APSInt AsInt(Val.bitcastToAPInt());
+ return visitInt(AsInt, Ty, Offset);
+ }
+
+public:
+ static Optional<BitCastBuffer> convert(EvalInfo &Info, const APValue &Src,
+ const CastExpr *BCE) {
+ CharUnits DstSize = Info.Ctx.getTypeSizeInChars(BCE->getType());
+ APValueToBufferConverter Converter(Info, DstSize, BCE);
+ if (!Converter.visit(Src, BCE->getSubExpr()->getType()))
+ return None;
+ return Converter.Buffer;
+ }
+};
+
+/// Write an BitCastBuffer into an APValue.
+class BufferToAPValueConverter {
+ EvalInfo &Info;
+ const BitCastBuffer &Buffer;
+ const CastExpr *BCE;
+
+ BufferToAPValueConverter(EvalInfo &Info, const BitCastBuffer &Buffer,
+ const CastExpr *BCE)
+ : Info(Info), Buffer(Buffer), BCE(BCE) {}
+
+ // Emit an unsupported bit_cast type error. Sema refuses to build a bit_cast
+ // with an invalid type, so anything left is a deficiency on our part (FIXME).
+ // Ideally this will be unreachable.
+ llvm::NoneType unsupportedType(QualType Ty) {
+ Info.FFDiag(BCE->getBeginLoc(),
+ diag::note_constexpr_bit_cast_unsupported_type)
+ << Ty;
+ return None;
+ }
+
+ Optional<APValue> visit(const BuiltinType *T, CharUnits Offset,
+ const EnumType *EnumSugar = nullptr) {
+ if (T->isNullPtrType()) {
+ uint64_t NullValue = Info.Ctx.getTargetNullPointerValue(QualType(T, 0));
+ return APValue((Expr *)nullptr,
+ /*Offset=*/CharUnits::fromQuantity(NullValue),
+ APValue::NoLValuePath{}, /*IsNullPtr=*/true);
+ }
+
+ CharUnits SizeOf = Info.Ctx.getTypeSizeInChars(T);
+ SmallVector<uint8_t, 8> Bytes;
+ if (!Buffer.readObject(Offset, SizeOf, Bytes)) {
+ // If this is std::byte or unsigned char, then its okay to store an
+ // indeterminate value.
+ bool IsStdByte = EnumSugar && EnumSugar->isStdByteType();
+ bool IsUChar =
+ !EnumSugar && (T->isSpecificBuiltinType(BuiltinType::UChar) ||
+ T->isSpecificBuiltinType(BuiltinType::Char_U));
+ if (!IsStdByte && !IsUChar) {
+ QualType DisplayType(EnumSugar ? (const Type *)EnumSugar : T, 0);
+ Info.FFDiag(BCE->getExprLoc(),
+ diag::note_constexpr_bit_cast_indet_dest)
+ << DisplayType << Info.Ctx.getLangOpts().CharIsSigned;
+ return None;
+ }
+
+ return APValue::IndeterminateValue();
+ }
+
+ APSInt Val(SizeOf.getQuantity() * Info.Ctx.getCharWidth(), true);
+ llvm::LoadIntFromMemory(Val, &*Bytes.begin(), Bytes.size());
+
+ if (T->isIntegralOrEnumerationType()) {
+ Val.setIsSigned(T->isSignedIntegerOrEnumerationType());
+ return APValue(Val);
+ }
+
+ if (T->isRealFloatingType()) {
+ const llvm::fltSemantics &Semantics =
+ Info.Ctx.getFloatTypeSemantics(QualType(T, 0));
+ return APValue(APFloat(Semantics, Val));
+ }
+
+ return unsupportedType(QualType(T, 0));
+ }
+
+ Optional<APValue> visit(const RecordType *RTy, CharUnits Offset) {
+ const RecordDecl *RD = RTy->getAsRecordDecl();
+ const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+
+ unsigned NumBases = 0;
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+ NumBases = CXXRD->getNumBases();
+
+ APValue ResultVal(APValue::UninitStruct(), NumBases,
+ std::distance(RD->field_begin(), RD->field_end()));
+
+ // Visit the base classes.
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (size_t I = 0, E = CXXRD->getNumBases(); I != E; ++I) {
+ const CXXBaseSpecifier &BS = CXXRD->bases_begin()[I];
+ CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl();
+ if (BaseDecl->isEmpty() ||
+ Info.Ctx.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero())
+ continue;
+
+ Optional<APValue> SubObj = visitType(
+ BS.getType(), Layout.getBaseClassOffset(BaseDecl) + Offset);
+ if (!SubObj)
+ return None;
+ ResultVal.getStructBase(I) = *SubObj;
+ }
+ }
+
+ // Visit the fields.
+ unsigned FieldIdx = 0;
+ for (FieldDecl *FD : RD->fields()) {
+ // FIXME: We don't currently support bit-fields. A lot of the logic for
+ // this is in CodeGen, so we need to factor it around.
+ if (FD->isBitField()) {
+ Info.FFDiag(BCE->getBeginLoc(),
+ diag::note_constexpr_bit_cast_unsupported_bitfield);
+ return None;
+ }
+
+ uint64_t FieldOffsetBits = Layout.getFieldOffset(FieldIdx);
+ assert(FieldOffsetBits % Info.Ctx.getCharWidth() == 0);
+
+ CharUnits FieldOffset =
+ CharUnits::fromQuantity(FieldOffsetBits / Info.Ctx.getCharWidth()) +
+ Offset;
+ QualType FieldTy = FD->getType();
+ Optional<APValue> SubObj = visitType(FieldTy, FieldOffset);
+ if (!SubObj)
+ return None;
+ ResultVal.getStructField(FieldIdx) = *SubObj;
+ ++FieldIdx;
+ }
+
+ return ResultVal;
+ }
+
+ Optional<APValue> visit(const EnumType *Ty, CharUnits Offset) {
+ 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?");
+ // Recurse into the underlying type. Treat std::byte transparently as
+ // unsigned char.
+ return visit(AsBuiltin, Offset, /*EnumTy=*/Ty);
+ }
+
+ Optional<APValue> visit(const ConstantArrayType *Ty, CharUnits Offset) {
+ size_t Size = Ty->getSize().getLimitedValue();
+ CharUnits ElementWidth = Info.Ctx.getTypeSizeInChars(Ty->getElementType());
+
+ APValue ArrayValue(APValue::UninitArray(), Size, Size);
+ for (size_t I = 0; I != Size; ++I) {
+ Optional<APValue> ElementValue =
+ visitType(Ty->getElementType(), Offset + I * ElementWidth);
+ if (!ElementValue)
+ return None;
+ ArrayValue.getArrayInitializedElt(I) = std::move(*ElementValue);
+ }
+
+ return ArrayValue;
+ }
+
+ Optional<APValue> visit(const Type *Ty, CharUnits Offset) {
+ return unsupportedType(QualType(Ty, 0));
+ }
+
+ Optional<APValue> visitType(QualType Ty, CharUnits Offset) {
+ QualType Can = Ty.getCanonicalType();
+
+ switch (Can->getTypeClass()) {
+#define TYPE(Class, Base) \
+ case Type::Class: \
+ return visit(cast<Class##Type>(Can.getTypePtr()), Offset);
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base) \
+ case Type::Class: \
+ llvm_unreachable("non-canonical type should be impossible!");
+#define DEPENDENT_TYPE(Class, Base) \
+ case Type::Class: \
+ llvm_unreachable( \
+ "dependent types aren't supported in the constant evaluator!");
+#define NON_CANONICAL_UNLESS_DEPENDENT(Class, Base) \
+ case Type::Class: \
+ llvm_unreachable("either dependent or not canonical!");
+#include "clang/AST/TypeNodes.def"
+ }
+ llvm_unreachable("Unhandled Type::TypeClass");
+ }
+
+public:
+ // Pull out a full value of type DstType.
+ static Optional<APValue> convert(EvalInfo &Info, BitCastBuffer &Buffer,
+ const CastExpr *BCE) {
+ BufferToAPValueConverter Converter(Info, Buffer, BCE);
+ return Converter.visitType(BCE->getType(), CharUnits::fromQuantity(0));
+ }
+};
+
+static bool checkBitCastConstexprEligibilityType(SourceLocation Loc,
+ QualType Ty, EvalInfo *Info,
+ const ASTContext &Ctx,
+ bool CheckingDest) {
+ Ty = Ty.getCanonicalType();
+
+ auto diag = [&](int Reason) {
+ if (Info)
+ Info->FFDiag(Loc, diag::note_constexpr_bit_cast_invalid_type)
+ << CheckingDest << (Reason == 4) << Reason;
+ return false;
+ };
+ auto note = [&](int Construct, QualType NoteTy, SourceLocation NoteLoc) {
+ if (Info)
+ Info->Note(NoteLoc, diag::note_constexpr_bit_cast_invalid_subtype)
+ << NoteTy << Construct << Ty;
+ return false;
+ };
+
+ if (Ty->isUnionType())
+ return diag(0);
+ if (Ty->isPointerType())
+ return diag(1);
+ if (Ty->isMemberPointerType())
+ return diag(2);
+ if (Ty.isVolatileQualified())
+ return diag(3);
+
+ if (RecordDecl *Record = Ty->getAsRecordDecl()) {
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(Record)) {
+ for (CXXBaseSpecifier &BS : CXXRD->bases())
+ if (!checkBitCastConstexprEligibilityType(Loc, BS.getType(), Info, Ctx,
+ CheckingDest))
+ return note(1, BS.getType(), BS.getBeginLoc());
+ }
+ for (FieldDecl *FD : Record->fields()) {
+ if (FD->getType()->isReferenceType())
+ return diag(4);
+ if (!checkBitCastConstexprEligibilityType(Loc, FD->getType(), Info, Ctx,
+ CheckingDest))
+ return note(0, FD->getType(), FD->getBeginLoc());
+ }
+ }
+
+ if (Ty->isArrayType() &&
+ !checkBitCastConstexprEligibilityType(Loc, Ctx.getBaseElementType(Ty),
+ Info, Ctx, CheckingDest))
+ return false;
+
+ return true;
+}
+
+static bool checkBitCastConstexprEligibility(EvalInfo *Info,
+ const ASTContext &Ctx,
+ const CastExpr *BCE) {
+ bool DestOK = checkBitCastConstexprEligibilityType(
+ BCE->getBeginLoc(), BCE->getType(), Info, Ctx, true);
+ bool SourceOK = DestOK && checkBitCastConstexprEligibilityType(
+ BCE->getBeginLoc(),
+ BCE->getSubExpr()->getType(), Info, Ctx, false);
+ return SourceOK;
+}
+
+static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
+ APValue &SourceValue,
+ const CastExpr *BCE) {
+ assert(CHAR_BIT == 8 && Info.Ctx.getTargetInfo().getCharWidth() == 8 &&
+ "no host or target supports non 8-bit chars");
+ assert(SourceValue.isLValue() &&
+ "LValueToRValueBitcast requires an lvalue operand!");
+
+ if (!checkBitCastConstexprEligibility(&Info, Info.Ctx, BCE))
+ return false;
+
+ LValue SourceLValue;
+ APValue SourceRValue;
+ SourceLValue.setFrom(Info.Ctx, SourceValue);
+ if (!handleLValueToRValueConversion(Info, BCE,
+ BCE->getSubExpr()->getType().withConst(),
+ SourceLValue, SourceRValue))
+ return false;
+
+ // Read out SourceValue into a char buffer.
+ Optional<BitCastBuffer> Buffer =
+ APValueToBufferConverter::convert(Info, SourceRValue, BCE);
+ if (!Buffer)
+ return false;
+
+ // Write out the buffer into a new APValue.
+ Optional<APValue> MaybeDestValue =
+ BufferToAPValueConverter::convert(Info, *Buffer, BCE);
+ if (!MaybeDestValue)
+ return false;
+
+ DestValue = std::move(*MaybeDestValue);
+ return true;
+}
+
template <class Derived>
class ExprEvaluatorBase
: public ConstStmtVisitor<Derived, bool> {
@@ -4771,6 +5972,7 @@ public:
{ return StmtVisitorTy::Visit(E->getReplacement()); }
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
TempVersionRAII RAII(*Info.CurrentCall);
+ SourceLocExprScopeGuard Guard(E, Info.CurrentCall->CurSourceLocExprScope);
return StmtVisitorTy::Visit(E->getExpr());
}
bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
@@ -4778,8 +5980,10 @@ public:
// The initializer may not have been parsed yet, or might be erroneous.
if (!E->getExpr())
return Error(E);
+ SourceLocExprScopeGuard Guard(E, Info.CurrentCall->CurSourceLocExprScope);
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)
@@ -4790,7 +5994,11 @@ public:
return static_cast<Derived*>(this)->VisitCastExpr(E);
}
bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
- CCEDiag(E, diag::note_constexpr_invalid_cast) << 1;
+ if (!Info.Ctx.getLangOpts().CPlusPlus2a)
+ CCEDiag(E, diag::note_constexpr_invalid_cast) << 1;
+ return static_cast<Derived*>(this)->VisitCastExpr(E);
+ }
+ bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E) {
return static_cast<Derived*>(this)->VisitCastExpr(E);
}
@@ -4884,25 +6092,26 @@ public:
// Extract function decl and 'this' pointer from the callee.
if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) {
- const ValueDecl *Member = nullptr;
+ const CXXMethodDecl *Member = nullptr;
if (const MemberExpr *ME = dyn_cast<MemberExpr>(Callee)) {
// Explicit bound member calls, such as x.f() or p->g();
if (!EvaluateObjectArgument(Info, ME->getBase(), ThisVal))
return false;
- Member = ME->getMemberDecl();
+ Member = dyn_cast<CXXMethodDecl>(ME->getMemberDecl());
+ if (!Member)
+ return Error(Callee);
This = &ThisVal;
HasQualifier = ME->hasQualifier();
} else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(Callee)) {
// Indirect bound member calls ('.*' or '->*').
- Member = HandleMemberPointerAccess(Info, BE, ThisVal, false);
- if (!Member) return false;
+ Member = dyn_cast_or_null<CXXMethodDecl>(
+ HandleMemberPointerAccess(Info, BE, ThisVal, false));
+ if (!Member)
+ return Error(Callee);
This = &ThisVal;
} else
return Error(Callee);
-
- FD = dyn_cast<FunctionDecl>(Member);
- if (!FD)
- return Error(Callee);
+ FD = Member;
} else if (CalleeType->isFunctionPointerType()) {
LValue Call;
if (!EvaluatePointer(Callee, Call, Info))
@@ -4969,19 +6178,24 @@ public:
} else
FD = LambdaCallOp;
}
-
-
} else
return Error(E);
- if (This && !This->checkSubobject(Info, E, CSK_This))
- return false;
-
- // DR1358 allows virtual constexpr functions in some cases. Don't allow
- // calls to such functions in constant expressions.
- if (This && !HasQualifier &&
- isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isVirtual())
- return Error(E, diag::note_constexpr_virtual_call);
+ SmallVector<QualType, 4> CovariantAdjustmentPath;
+ if (This) {
+ auto *NamedMember = dyn_cast<CXXMethodDecl>(FD);
+ if (NamedMember && NamedMember->isVirtual() && !HasQualifier) {
+ // Perform virtual dispatch, if necessary.
+ FD = HandleVirtualDispatch(Info, E, *This, NamedMember,
+ CovariantAdjustmentPath);
+ if (!FD)
+ return false;
+ } else {
+ // Check that the 'this' pointer points to an object of the right type.
+ if (!checkNonVirtualMemberCallThisPointer(Info, E, *This))
+ return false;
+ }
+ }
const FunctionDecl *Definition = nullptr;
Stmt *Body = FD->getBody(Definition);
@@ -4991,6 +6205,11 @@ public:
Result, ResultSlot))
return false;
+ if (!CovariantAdjustmentPath.empty() &&
+ !HandleCovariantReturnAdjustment(Info, E, Result,
+ CovariantAdjustmentPath))
+ return false;
+
return true;
}
@@ -5016,6 +6235,8 @@ public:
/// A member expression where the object is a prvalue is itself a prvalue.
bool VisitMemberExpr(const MemberExpr *E) {
+ assert(!Info.Ctx.getLangOpts().CPlusPlus11 &&
+ "missing temporary materialization conversion");
assert(!E->isArrow() && "missing call to bound member function?");
APValue Val;
@@ -5030,7 +6251,10 @@ public:
assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() ==
FD->getParent()->getCanonicalDecl() && "record / field mismatch");
- CompleteObject Obj(&Val, BaseTy, true);
+ // Note: there is no lvalue base here. But this case should only ever
+ // happen in C or in C++98, where we cannot be evaluating a constexpr
+ // constructor, which is the only case the base matters.
+ CompleteObject Obj(APValue::LValueBase(), &Val, BaseTy);
SubobjectDesignator Designator(BaseTy);
Designator.addDeclUnchecked(FD);
@@ -5069,6 +6293,14 @@ public:
return false;
return DerivedSuccess(RVal, E);
}
+ case CK_LValueToRValueBitCast: {
+ APValue DestValue, SourceValue;
+ if (!Evaluate(SourceValue, Info, E->getSubExpr()))
+ return false;
+ if (!handleLValueToRValueBitCast(Info, DestValue, SourceValue, E))
+ return false;
+ return DerivedSuccess(DestValue, E);
+ }
}
return Error(E);
@@ -5274,13 +6506,13 @@ public:
// - Literals
// * CompoundLiteralExpr in C (and in global scope in C++)
// * StringLiteral
-// * CXXTypeidExpr
// * PredefinedExpr
// * ObjCStringLiteralExpr
// * ObjCEncodeExpr
// * AddrLabelExpr
// * BlockExpr
// * CallExpr for a MakeStringConstant builtin
+// - typeid(T) expressions, as TypeInfoLValues
// - Locals and temporaries
// * MaterializeTemporaryExpr
// * Any Expr, with a CallIndex indicating the function in which the temporary
@@ -5338,6 +6570,11 @@ public:
if (!Visit(E->getSubExpr()))
return false;
return HandleBaseToDerivedCast(Info, E, Result);
+
+ case CK_Dynamic:
+ if (!Visit(E->getSubExpr()))
+ return false;
+ return HandleDynamicCast(Info, cast<ExplicitCastExpr>(E), Result);
}
}
};
@@ -5427,7 +6664,9 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
APValue *V;
if (!evaluateVarDeclInit(Info, E, VD, Frame, V, nullptr))
return false;
- if (V->isUninit()) {
+ if (!V->hasValue()) {
+ // FIXME: Is it possible for V to be indeterminate here? If so, we should
+ // adjust the diagnostic to say that.
if (!Info.checkingPotentialConstantExpression())
Info.FFDiag(E, diag::note_constexpr_use_uninit_reference);
return false;
@@ -5510,13 +6749,33 @@ LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
}
bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
- if (!E->isPotentiallyEvaluated())
- return Success(E);
+ TypeInfoLValue TypeInfo;
- Info.FFDiag(E, diag::note_constexpr_typeid_polymorphic)
- << E->getExprOperand()->getType()
- << E->getExprOperand()->getSourceRange();
- return false;
+ if (!E->isPotentiallyEvaluated()) {
+ if (E->isTypeOperand())
+ TypeInfo = TypeInfoLValue(E->getTypeOperand(Info.Ctx).getTypePtr());
+ else
+ TypeInfo = TypeInfoLValue(E->getExprOperand()->getType().getTypePtr());
+ } else {
+ if (!Info.Ctx.getLangOpts().CPlusPlus2a) {
+ Info.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)
+ << E->getExprOperand()->getType()
+ << E->getExprOperand()->getSourceRange();
+ }
+
+ if (!Visit(E->getExprOperand()))
+ return false;
+
+ Optional<DynamicType> DynType =
+ ComputeDynamicType(Info, E, Result, AK_TypeId);
+ if (!DynType)
+ return false;
+
+ TypeInfo =
+ TypeInfoLValue(Info.Ctx.getRecordType(DynType->Type).getTypePtr());
+ }
+
+ return Success(APValue::LValueBase::getTypeInfo(TypeInfo, E->getType()));
}
bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
@@ -5634,6 +6893,10 @@ bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {
if (!Evaluate(NewVal, this->Info, E->getRHS()))
return false;
+ if (Info.getLangOpts().CPlusPlus2a &&
+ !HandleUnionActiveMemberChange(Info, E->getLHS(), Result))
+ return false;
+
return handleAssignment(this->Info, E, Result, E->getLHS()->getType(),
NewVal);
}
@@ -5783,6 +7046,8 @@ public:
bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
{ return Success(E); }
bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
+ if (E->isExpressibleAsConstantInitializer())
+ return Success(E);
if (Info.noteFailure())
EvaluateIgnoredValue(Info, E->getSubExpr());
return Error(E);
@@ -5832,6 +7097,14 @@ public:
return true;
}
+ bool VisitSourceLocExpr(const SourceLocExpr *E) {
+ assert(E->isStringType() && "SourceLocExpr isn't a pointer type?");
+ APValue LValResult = E->EvaluateInContext(
+ Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getDefaultExpr());
+ Result.setFrom(Info.Ctx, LValResult);
+ return true;
+ }
+
// FIXME: Missing: @protocol, @selector
};
} // end anonymous namespace
@@ -5877,7 +7150,6 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
default:
break;
-
case CK_BitCast:
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
@@ -5920,6 +7192,11 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
return true;
return HandleBaseToDerivedCast(Info, E, Result);
+ case CK_Dynamic:
+ if (!Visit(E->getSubExpr()))
+ return false;
+ return HandleDynamicCast(Info, cast<ExplicitCastExpr>(E), Result);
+
case CK_NullToPointer:
VisitIgnoredValue(E->getSubExpr());
return ZeroInitialization(E);
@@ -6092,9 +7369,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
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 = GetAlignOfExpr(
- Info, OffsetResult.Base.get<const Expr *>(), UETT_AlignOf);
+ BaseAlignment = GetAlignOfType(
+ Info, OffsetResult.Base.getTypeInfoType(), UETT_AlignOf);
}
if (BaseAlignment < Align) {
@@ -6622,6 +7901,12 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+ auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
+
+ EvalInfo::EvaluatingConstructorRAII EvalObj(
+ Info,
+ ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries},
+ CXXRD && CXXRD->getNumBases());
if (RD->isUnion()) {
const FieldDecl *Field = E->getInitializedFieldInUnion();
@@ -6648,15 +7933,14 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr);
}
- auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
- if (Result.isUninit())
+ if (!Result.hasValue())
Result = APValue(APValue::UninitStruct(), CXXRD ? CXXRD->getNumBases() : 0,
std::distance(RD->field_begin(), RD->field_end()));
unsigned ElementNo = 0;
bool Success = true;
// Initialize base classes.
- if (CXXRD) {
+ if (CXXRD && CXXRD->getNumBases()) {
for (const auto &Base : CXXRD->bases()) {
assert(ElementNo < E->getNumInits() && "missing init for base class");
const Expr *Init = E->getInit(ElementNo);
@@ -6673,6 +7957,8 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
}
++ElementNo;
}
+
+ EvalObj.finishedConstructingBases();
}
// Initialize members.
@@ -6724,7 +8010,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
bool ZeroInit = E->requiresZeroInitialization();
if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
// If we've already performed zero-initialization, we're already done.
- if (!Result.isUninit())
+ if (Result.hasValue())
return true;
// We can get here in two different ways:
@@ -7130,8 +8416,7 @@ namespace {
: ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
bool Success(const APValue &V, const Expr *E) {
- assert((V.isArray() || V.isLValue()) &&
- "expected array or string literal");
+ assert(V.isArray() && "expected array");
Result = V;
return true;
}
@@ -7162,6 +8447,10 @@ namespace {
bool VisitCXXConstructExpr(const CXXConstructExpr *E,
const LValue &Subobject,
APValue *Value, QualType Type);
+ bool VisitStringLiteral(const StringLiteral *E) {
+ expandStringLiteral(Info, E, Result);
+ return true;
+ }
};
} // end anonymous namespace
@@ -7194,14 +8483,8 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *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()) {
- LValue LV;
- if (!EvaluateLValue(E->getInit(0), LV, Info))
- return false;
- APValue Val;
- LV.moveInto(Val);
- return Success(Val, E);
- }
+ if (E->isStringLiteralInit())
+ return Visit(E->getInit(0));
bool Success = true;
@@ -7227,7 +8510,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
// If the array was previously zero-initialized, preserve the
// zero-initialized values.
- if (!Filler.isUninit()) {
+ if (Filler.hasValue()) {
for (unsigned I = 0, E = Result.getArrayInitializedElts(); I != E; ++I)
Result.getArrayInitializedElt(I) = Filler;
if (Result.hasArrayFiller())
@@ -7296,7 +8579,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
const LValue &Subobject,
APValue *Value,
QualType Type) {
- bool HadZeroInit = !Value->isUninit();
+ bool HadZeroInit = Value->hasValue();
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) {
unsigned N = CAT->getSize().getZExtValue();
@@ -7391,7 +8674,7 @@ public:
}
bool Success(const APValue &V, const Expr *E) {
- if (V.isLValue() || V.isAddrLabelDiff()) {
+ if (V.isLValue() || V.isAddrLabelDiff() || V.isIndeterminate()) {
Result = V;
return true;
}
@@ -7478,7 +8761,7 @@ public:
bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
-
+ bool VisitSourceLocExpr(const SourceLocExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
};
@@ -7490,53 +8773,27 @@ class FixedPointExprEvaluator
FixedPointExprEvaluator(EvalInfo &info, APValue &result)
: ExprEvaluatorBaseTy(info), Result(result) {}
- bool Success(const llvm::APSInt &SI, const Expr *E, APValue &Result) {
- assert(E->getType()->isFixedPointType() && "Invalid evaluation result.");
- assert(SI.isSigned() == E->getType()->isSignedFixedPointType() &&
- "Invalid evaluation result.");
- assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
- "Invalid evaluation result.");
- Result = APValue(SI);
- return true;
- }
- bool Success(const llvm::APSInt &SI, const Expr *E) {
- return Success(SI, E, Result);
- }
-
- bool Success(const llvm::APInt &I, const Expr *E, APValue &Result) {
- assert(E->getType()->isFixedPointType() && "Invalid evaluation result.");
- assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
- "Invalid evaluation result.");
- Result = APValue(APSInt(I));
- Result.getInt().setIsUnsigned(E->getType()->isUnsignedFixedPointType());
- return true;
- }
bool Success(const llvm::APInt &I, const Expr *E) {
- return Success(I, E, Result);
+ return Success(
+ APFixedPoint(I, Info.Ctx.getFixedPointSemantics(E->getType())), E);
}
- bool Success(uint64_t Value, const Expr *E, APValue &Result) {
- assert(E->getType()->isFixedPointType() && "Invalid evaluation result.");
- Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType()));
- return true;
- }
bool Success(uint64_t Value, const Expr *E) {
- return Success(Value, E, Result);
- }
-
- bool Success(CharUnits Size, const Expr *E) {
- return Success(Size.getQuantity(), E);
+ return Success(
+ APFixedPoint(Value, Info.Ctx.getFixedPointSemantics(E->getType())), E);
}
bool Success(const APValue &V, const Expr *E) {
- if (V.isLValue() || V.isAddrLabelDiff()) {
- Result = V;
- return true;
- }
- return Success(V.getInt(), E);
+ return Success(V.getFixedPoint(), E);
}
- bool ZeroInitialization(const Expr *E) { return Success(0, E); }
+ bool Success(const APFixedPoint &V, const Expr *E) {
+ assert(E->getType()->isFixedPointType() && "Invalid evaluation result.");
+ assert(V.getWidth() == Info.Ctx.getIntWidth(E->getType()) &&
+ "Invalid evaluation result.");
+ Result = APValue(V);
+ return true;
+ }
//===--------------------------------------------------------------------===//
// Visitor Methods
@@ -7546,7 +8803,9 @@ class FixedPointExprEvaluator
return Success(E->getValue(), E);
}
+ bool VisitCastExpr(const CastExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
+ bool VisitBinaryOperator(const BinaryOperator *E);
};
} // end anonymous namespace
@@ -7578,6 +8837,42 @@ static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info) {
return true;
}
+bool IntExprEvaluator::VisitSourceLocExpr(const SourceLocExpr *E) {
+ APValue Evaluated = E->EvaluateInContext(
+ Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getDefaultExpr());
+ return Success(Evaluated, E);
+}
+
+static bool EvaluateFixedPoint(const Expr *E, APFixedPoint &Result,
+ EvalInfo &Info) {
+ if (E->getType()->isFixedPointType()) {
+ APValue Val;
+ if (!FixedPointExprEvaluator(Info, Val).Visit(E))
+ return false;
+ if (!Val.isFixedPoint())
+ return false;
+
+ Result = Val.getFixedPoint();
+ return true;
+ }
+ return false;
+}
+
+static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result,
+ EvalInfo &Info) {
+ if (E->getType()->isIntegerType()) {
+ auto FXSema = Info.Ctx.getFixedPointSemantics(E->getType());
+ APSInt Val;
+ if (!EvaluateInteger(E, Val, Info))
+ return false;
+ Result = APFixedPoint(Val, FXSema);
+ return true;
+ } else if (E->getType()->isFixedPointType()) {
+ return EvaluateFixedPoint(E, Result, Info);
+ }
+ return false;
+}
+
/// Check whether the given declaration can be directly converted to an integral
/// rvalue. If not, no diagnostic is produced; there are other things we can
/// try.
@@ -7783,19 +9078,41 @@ EvaluateBuiltinClassifyType(const CallExpr *E, const LangOptions &LangOpts) {
}
/// EvaluateBuiltinConstantPForLValue - Determine the result of
-/// __builtin_constant_p when applied to the given lvalue.
+/// __builtin_constant_p when applied to the given pointer.
///
-/// An lvalue is only "constant" if it is a pointer or reference to the first
-/// character of a string literal.
-template<typename LValue>
-static bool EvaluateBuiltinConstantPForLValue(const LValue &LV) {
- const Expr *E = LV.getLValueBase().template dyn_cast<const Expr*>();
- return E && isa<StringLiteral>(E) && LV.getLValueOffset().isZero();
+/// A pointer is only "constant" if it is null (or a pointer cast to integer)
+/// or it points to the first character of a string literal.
+static bool EvaluateBuiltinConstantPForLValue(const APValue &LV) {
+ APValue::LValueBase Base = LV.getLValueBase();
+ if (Base.isNull()) {
+ // A null base is acceptable.
+ return true;
+ } else if (const Expr *E = Base.dyn_cast<const Expr *>()) {
+ if (!isa<StringLiteral>(E))
+ return false;
+ return LV.getLValueOffset().isZero();
+ } else if (Base.is<TypeInfoLValue>()) {
+ // Surprisingly, GCC considers __builtin_constant_p(&typeid(int)) to
+ // evaluate to true.
+ return true;
+ } else {
+ // Any other base is not constant enough for GCC.
+ return false;
+ }
}
/// EvaluateBuiltinConstantP - Evaluate __builtin_constant_p as similarly to
/// GCC as we can manage.
-static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) {
+static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) {
+ // This evaluation is not permitted to have side-effects, so evaluate it in
+ // a speculative evaluation context.
+ SpeculativeEvaluationRAII SpeculativeEval(Info);
+
+ // Constant-folding is always enabled for the operand of __builtin_constant_p
+ // (even when the enclosing evaluation context otherwise requires a strict
+ // language-specific constant expression).
+ FoldConstant Fold(Info, true);
+
QualType ArgType = Arg->getType();
// __builtin_constant_p always has one operand. The rules which gcc follows
@@ -7803,34 +9120,30 @@ static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) {
//
// - If the operand is of integral, floating, complex or enumeration type,
// and can be folded to a known value of that type, it returns 1.
- // - If the operand and can be folded to a pointer to the first character
- // of a string literal (or such a pointer cast to an integral type), it
- // returns 1.
+ // - If the operand can be folded to a pointer to the first character
+ // of a string literal (or such a pointer cast to an integral type)
+ // or to a null pointer or an integer cast to a pointer, it returns 1.
//
// Otherwise, it returns 0.
//
// FIXME: GCC also intends to return 1 for literals of aggregate types, but
- // its support for this does not currently work.
- if (ArgType->isIntegralOrEnumerationType()) {
- Expr::EvalResult Result;
- if (!Arg->EvaluateAsRValue(Result, Ctx) || Result.HasSideEffects)
+ // its support for this did not work prior to GCC 9 and is not yet well
+ // understood.
+ if (ArgType->isIntegralOrEnumerationType() || ArgType->isFloatingType() ||
+ ArgType->isAnyComplexType() || ArgType->isPointerType() ||
+ ArgType->isNullPtrType()) {
+ APValue V;
+ if (!::EvaluateAsRValue(Info, Arg, V)) {
+ Fold.keepDiagnostics();
return false;
+ }
- APValue &V = Result.Val;
- if (V.getKind() == APValue::Int)
- return true;
+ // For a pointer (possibly cast to integer), there are special rules.
if (V.getKind() == APValue::LValue)
return EvaluateBuiltinConstantPForLValue(V);
- } else if (ArgType->isFloatingType() || ArgType->isAnyComplexType()) {
- return Arg->isEvaluatable(Ctx);
- } else if (ArgType->isPointerType() || Arg->isGLValue()) {
- LValue LV;
- Expr::EvalStatus Status;
- EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold);
- if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, Info)
- : EvaluatePointer(Arg, LV, Info)) &&
- !Status.HasSideEffects)
- return EvaluateBuiltinConstantPForLValue(LV);
+
+ // Otherwise, any constant value is good enough.
+ return V.hasValue();
}
// Anything else isn't considered to be sufficiently constant.
@@ -7846,6 +9159,8 @@ static QualType getObjectType(APValue::LValueBase B) {
} else if (const Expr *E = B.get<const Expr*>()) {
if (isa<CompoundLiteralExpr>(E))
return E->getType();
+ } else if (B.is<TypeInfoLValue>()) {
+ return B.getTypeInfoType();
}
return QualType();
@@ -7940,13 +9255,13 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
if (I + 1 == E)
return true;
const auto *CAT = cast<ConstantArrayType>(Ctx.getAsArrayType(BaseType));
- uint64_t Index = Entry.ArrayIndex;
+ uint64_t Index = Entry.getAsArrayIndex();
if (Index + 1 != CAT->getSize())
return false;
BaseType = CAT->getElementType();
} else if (BaseType->isAnyComplexType()) {
const auto *CT = BaseType->castAs<ComplexType>();
- uint64_t Index = Entry.ArrayIndex;
+ uint64_t Index = Entry.getAsArrayIndex();
if (Index != 1)
return false;
BaseType = CT->getElementType();
@@ -8088,7 +9403,7 @@ static bool determineEndOffset(EvalInfo &Info, SourceLocation ExprLoc,
if (Designator.MostDerivedIsArrayElement &&
Designator.Entries.size() == Designator.MostDerivedPathLength) {
uint64_t ArraySize = Designator.getMostDerivedArraySize();
- uint64_t ArrayIndex = Designator.Entries.back().ArrayIndex;
+ uint64_t ArrayIndex = Designator.Entries.back().getAsArrayIndex();
ElemsRemaining = ArraySize <= ArrayIndex ? 0 : ArraySize - ArrayIndex;
} else {
ElemsRemaining = Designator.isOnePastTheEnd() ? 0 : 1;
@@ -8148,6 +9463,8 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type,
bool IntExprEvaluator::VisitConstantExpr(const ConstantExpr *E) {
llvm::SaveAndRestore<bool> InConstantContext(Info.InConstantContext, true);
+ if (E->getResultAPValueKind() != APValue::None)
+ return Success(E->getAPValueResult(), E);
return ExprEvaluatorBaseTy::VisitConstantExpr(E);
}
@@ -8164,6 +9481,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
default:
return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ case Builtin::BI__builtin_dynamic_object_size:
case Builtin::BI__builtin_object_size: {
// The type was checked when we built the expression.
unsigned Type =
@@ -8239,20 +9557,22 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
}
case Builtin::BI__builtin_constant_p: {
- auto Arg = E->getArg(0);
- if (EvaluateBuiltinConstantP(Info.Ctx, Arg))
+ const Expr *Arg = E->getArg(0);
+ if (EvaluateBuiltinConstantP(Info, Arg))
return Success(true, E);
- auto ArgTy = Arg->IgnoreImplicit()->getType();
- if (!Info.InConstantContext && !Arg->HasSideEffects(Info.Ctx) &&
- !ArgTy->isAggregateType() && !ArgTy->isPointerType()) {
- // We can delay calculation of __builtin_constant_p until after
- // inlining. Note: This diagnostic won't be shown to the user.
- Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
- return false;
+ if (Info.InConstantContext || Arg->HasSideEffects(Info.Ctx)) {
+ // Outside a constant context, eagerly evaluate to false in the presence
+ // of side-effects in order to avoid -Wunsequenced false-positives in
+ // a branch on __builtin_constant_p(expr).
+ return Success(false, E);
}
- return Success(false, E);
+ Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
+ return false;
}
+ case Builtin::BI__builtin_is_constant_evaluated:
+ return Success(Info.InConstantContext, E);
+
case Builtin::BI__builtin_ctz:
case Builtin::BI__builtin_ctzl:
case Builtin::BI__builtin_ctzll:
@@ -8411,6 +9731,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BIstrncmp:
case Builtin::BIwcsncmp:
case Builtin::BImemcmp:
+ case Builtin::BIbcmp:
case Builtin::BIwmemcmp:
// A call to strlen is not a constant expression.
if (Info.getLangOpts().CPlusPlus11)
@@ -8425,6 +9746,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_strncmp:
case Builtin::BI__builtin_wcsncmp:
case Builtin::BI__builtin_memcmp:
+ case Builtin::BI__builtin_bcmp:
case Builtin::BI__builtin_wmemcmp: {
LValue String1, String2;
if (!EvaluatePointer(E->getArg(0), String1, Info) ||
@@ -8455,7 +9777,9 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
QualType CharTy2 = String2.Designator.getType(Info.Ctx);
bool IsRawByte = BuiltinOp == Builtin::BImemcmp ||
- BuiltinOp == Builtin::BI__builtin_memcmp;
+ BuiltinOp == Builtin::BIbcmp ||
+ BuiltinOp == Builtin::BI__builtin_memcmp ||
+ BuiltinOp == Builtin::BI__builtin_bcmp;
assert(IsRawByte ||
(Info.Ctx.hasSameUnqualifiedType(
@@ -8523,10 +9847,12 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return Success(0, E);
}
- bool StopAtNull = (BuiltinOp != Builtin::BImemcmp &&
- BuiltinOp != Builtin::BIwmemcmp &&
- BuiltinOp != Builtin::BI__builtin_memcmp &&
- BuiltinOp != Builtin::BI__builtin_wmemcmp);
+ bool StopAtNull =
+ (BuiltinOp != Builtin::BImemcmp && BuiltinOp != Builtin::BIbcmp &&
+ BuiltinOp != Builtin::BIwmemcmp &&
+ BuiltinOp != Builtin::BI__builtin_memcmp &&
+ BuiltinOp != Builtin::BI__builtin_bcmp &&
+ BuiltinOp != Builtin::BI__builtin_wmemcmp);
bool IsWide = BuiltinOp == Builtin::BIwcscmp ||
BuiltinOp == Builtin::BIwcsncmp ||
BuiltinOp == Builtin::BIwmemcmp ||
@@ -8654,10 +9980,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (IsSigned && !AllSigned)
++MaxBits;
- LHS = APSInt(IsSigned ? LHS.sextOrSelf(MaxBits) : LHS.zextOrSelf(MaxBits),
- !IsSigned);
- RHS = APSInt(IsSigned ? RHS.sextOrSelf(MaxBits) : RHS.zextOrSelf(MaxBits),
- !IsSigned);
+ LHS = APSInt(LHS.extOrTrunc(MaxBits), !IsSigned);
+ RHS = APSInt(RHS.extOrTrunc(MaxBits), !IsSigned);
Result = APSInt(MaxBits, !IsSigned);
}
@@ -9123,6 +10447,22 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
return Success(CCR::Equal, E);
}
+ if (LHSTy->isFixedPointType() || RHSTy->isFixedPointType()) {
+ APFixedPoint LHSFX(Info.Ctx.getFixedPointSemantics(LHSTy));
+ APFixedPoint RHSFX(Info.Ctx.getFixedPointSemantics(RHSTy));
+
+ bool LHSOK = EvaluateFixedPointOrInteger(E->getLHS(), LHSFX, Info);
+ if (!LHSOK && !Info.noteFailure())
+ return false;
+ if (!EvaluateFixedPointOrInteger(E->getRHS(), RHSFX, Info) || !LHSOK)
+ return false;
+ if (LHSFX < RHSFX)
+ return Success(CCR::Less, E);
+ if (LHSFX > RHSFX)
+ return Success(CCR::Greater, E);
+ return Success(CCR::Equal, E);
+ }
+
if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) {
ComplexValue LHS, RHS;
bool LHSOK;
@@ -9739,6 +11079,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_AddressSpaceConversion:
case CK_IntToOCLSampler:
case CK_FixedPointCast:
+ case CK_IntegralToFixedPoint:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -9755,6 +11096,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_LValueToRValue:
case CK_AtomicToNonAtomic:
case CK_NoOp:
+ case CK_LValueToRValueBitCast:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_MemberPointerToBoolean:
@@ -9773,12 +11115,25 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return Success(IntResult, E);
}
+ case CK_FixedPointToIntegral: {
+ APFixedPoint Src(Info.Ctx.getFixedPointSemantics(SrcType));
+ if (!EvaluateFixedPoint(SubExpr, Src, Info))
+ return false;
+ bool Overflowed;
+ llvm::APSInt Result = Src.convertToInt(
+ Info.Ctx.getIntWidth(DestType),
+ DestType->isSignedIntegerOrEnumerationType(), &Overflowed);
+ if (Overflowed && !HandleOverflow(Info, E, Result, DestType))
+ return false;
+ return Success(Result, E);
+ }
+
case CK_FixedPointToBoolean: {
// Unsigned padding does not affect this.
APValue Val;
if (!Evaluate(Val, Info, SubExpr))
return false;
- return Success(Val.getInt().getBoolValue(), E);
+ return Success(Val.getFixedPoint().getBoolValue(), E);
}
case CK_IntegralCast: {
@@ -9821,13 +11176,12 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return true;
}
- uint64_t V;
- if (LV.isNullPointer())
- V = Info.Ctx.getTargetNullPointerValue(SrcType);
- else
- V = LV.getLValueOffset().getQuantity();
+ APSInt AsInt;
+ APValue V;
+ LV.moveInto(V);
+ if (!V.toIntegralConstant(AsInt, SrcType, Info.Ctx))
+ llvm_unreachable("Can't cast this!");
- APSInt AsInt = Info.Ctx.MakeIntValue(V, SrcType);
return Success(HandleIntToIntCast(Info, E, DestType, SrcType, AsInt), E);
}
@@ -9898,16 +11252,13 @@ bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
return Visit(E->getSubExpr());
case UO_Minus: {
if (!Visit(E->getSubExpr())) return false;
- if (!Result.isInt()) return Error(E);
- const APSInt &Value = Result.getInt();
- if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow()) {
- SmallString<64> S;
- FixedPointValueToString(S, Value,
- Info.Ctx.getTypeInfo(E->getType()).Width);
- Info.CCEDiag(E, diag::note_constexpr_overflow) << S << E->getType();
- if (Info.noteUndefinedBehavior()) return false;
- }
- return Success(-Value, E);
+ if (!Result.isFixedPoint())
+ return Error(E);
+ bool Overflowed;
+ APFixedPoint Negated = Result.getFixedPoint().negate(&Overflowed);
+ if (Overflowed && !HandleOverflow(Info, E, Negated, E->getType()))
+ return false;
+ return Success(Negated, E);
}
case UO_LNot: {
bool bres;
@@ -9918,6 +11269,75 @@ bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
}
}
+bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
+ const Expr *SubExpr = E->getSubExpr();
+ QualType DestType = E->getType();
+ assert(DestType->isFixedPointType() &&
+ "Expected destination type to be a fixed point type");
+ auto DestFXSema = Info.Ctx.getFixedPointSemantics(DestType);
+
+ switch (E->getCastKind()) {
+ case CK_FixedPointCast: {
+ APFixedPoint Src(Info.Ctx.getFixedPointSemantics(SubExpr->getType()));
+ if (!EvaluateFixedPoint(SubExpr, Src, Info))
+ return false;
+ bool Overflowed;
+ APFixedPoint Result = Src.convert(DestFXSema, &Overflowed);
+ if (Overflowed && !HandleOverflow(Info, E, Result, DestType))
+ return false;
+ return Success(Result, E);
+ }
+ case CK_IntegralToFixedPoint: {
+ APSInt Src;
+ if (!EvaluateInteger(SubExpr, Src, Info))
+ return false;
+
+ bool Overflowed;
+ APFixedPoint IntResult = APFixedPoint::getFromIntValue(
+ Src, Info.Ctx.getFixedPointSemantics(DestType), &Overflowed);
+
+ if (Overflowed && !HandleOverflow(Info, E, IntResult, DestType))
+ return false;
+
+ return Success(IntResult, E);
+ }
+ case CK_NoOp:
+ case CK_LValueToRValue:
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
+ default:
+ return Error(E);
+ }
+}
+
+bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+ const Expr *LHS = E->getLHS();
+ const Expr *RHS = E->getRHS();
+ FixedPointSemantics ResultFXSema =
+ Info.Ctx.getFixedPointSemantics(E->getType());
+
+ APFixedPoint LHSFX(Info.Ctx.getFixedPointSemantics(LHS->getType()));
+ if (!EvaluateFixedPointOrInteger(LHS, LHSFX, Info))
+ return false;
+ APFixedPoint RHSFX(Info.Ctx.getFixedPointSemantics(RHS->getType()));
+ if (!EvaluateFixedPointOrInteger(RHS, RHSFX, Info))
+ return false;
+
+ switch (E->getOpcode()) {
+ case BO_Add: {
+ bool AddOverflow, ConversionOverflow;
+ APFixedPoint Result = LHSFX.add(RHSFX, &AddOverflow)
+ .convert(ResultFXSema, &ConversionOverflow);
+ if ((AddOverflow || ConversionOverflow) &&
+ !HandleOverflow(Info, E, Result, E->getType()))
+ return false;
+ return Success(Result, E);
+ }
+ default:
+ return false;
+ }
+ llvm_unreachable("Should've exited before this");
+}
+
//===----------------------------------------------------------------------===//
// Float Evaluation
//===----------------------------------------------------------------------===//
@@ -10282,11 +11702,14 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntToOCLSampler:
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
+ case CK_FixedPointToIntegral:
+ case CK_IntegralToFixedPoint:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
case CK_AtomicToNonAtomic:
case CK_NoOp:
+ case CK_LValueToRValueBitCast:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_Dependent:
@@ -10929,6 +12352,23 @@ static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult,
return true;
}
+static bool EvaluateAsFixedPoint(const Expr *E, Expr::EvalResult &ExprResult,
+ const ASTContext &Ctx,
+ Expr::SideEffectsKind AllowSideEffects,
+ EvalInfo &Info) {
+ if (!E->getType()->isFixedPointType())
+ return false;
+
+ if (!::EvaluateAsRValue(E, ExprResult, Ctx, Info))
+ return false;
+
+ if (!ExprResult.Val.isFixedPoint() ||
+ hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
+ return false;
+
+ return true;
+}
+
/// EvaluateAsRValue - Return true if this is a constant which we can fold using
/// any crazy technique (that has nothing to do with language standards) that
/// we want to. If this function returns true, it returns the folded constant
@@ -10936,31 +12376,54 @@ static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult,
/// will be applied to the result.
bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx,
bool InConstantContext) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
Info.InConstantContext = InConstantContext;
return ::EvaluateAsRValue(this, Result, Ctx, Info);
}
-bool Expr::EvaluateAsBooleanCondition(bool &Result,
- const ASTContext &Ctx) const {
+bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx,
+ bool InConstantContext) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
EvalResult Scratch;
- return EvaluateAsRValue(Scratch, Ctx) &&
+ return EvaluateAsRValue(Scratch, Ctx, InConstantContext) &&
HandleConversionToBool(Scratch.Val, Result);
}
bool Expr::EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx,
- SideEffectsKind AllowSideEffects) const {
+ SideEffectsKind AllowSideEffects,
+ bool InConstantContext) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
+ Info.InConstantContext = InConstantContext;
return ::EvaluateAsInt(this, Result, Ctx, AllowSideEffects, Info);
}
+bool Expr::EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx,
+ SideEffectsKind AllowSideEffects,
+ bool InConstantContext) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+ EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
+ Info.InConstantContext = InConstantContext;
+ return ::EvaluateAsFixedPoint(this, Result, Ctx, AllowSideEffects, Info);
+}
+
bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
- SideEffectsKind AllowSideEffects) const {
+ SideEffectsKind AllowSideEffects,
+ bool InConstantContext) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
if (!getType()->isRealFloatingType())
return false;
EvalResult ExprResult;
- if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() ||
+ if (!EvaluateAsRValue(ExprResult, Ctx, InConstantContext) ||
+ !ExprResult.Val.isFloat() ||
hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
return false;
@@ -10968,9 +12431,13 @@ bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
return true;
}
-bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
- EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
+bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
+ bool InConstantContext) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+ EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
+ Info.InConstantContext = InConstantContext;
LValue LV;
if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects ||
!CheckLValueConstantExpression(Info, getExprLoc(),
@@ -10984,8 +12451,13 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage,
const ASTContext &Ctx) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression;
EvalInfo Info(Ctx, Result, EM);
+ Info.InConstantContext = true;
+
if (!::Evaluate(Result.Val, Info, this))
return false;
@@ -10996,6 +12468,9 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage,
bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
const VarDecl *VD,
SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
// FIXME: Evaluating initializers for large array and record types can cause
// performance problems. Only do so in C++11 for now.
if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
@@ -11038,6 +12513,9 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
/// constant folded, but discard the result.
bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
EvalResult Result;
return EvaluateAsRValue(Result, Ctx, /* in constant context */ true) &&
!hasUnacceptableSideEffect(Result, SEK);
@@ -11045,6 +12523,9 @@ bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const {
APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
SmallVectorImpl<PartialDiagnosticAt> *Diag) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
EvalResult EVResult;
EVResult.Diag = Diag;
EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
@@ -11060,6 +12541,9 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
APSInt Expr::EvaluateKnownConstIntCheckOverflow(
const ASTContext &Ctx, SmallVectorImpl<PartialDiagnosticAt> *Diag) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
EvalResult EVResult;
EVResult.Diag = Diag;
EvalInfo Info(Ctx, EVResult, EvalInfo::EM_EvaluateForOverflow);
@@ -11074,6 +12558,9 @@ APSInt Expr::EvaluateKnownConstIntCheckOverflow(
}
void Expr::EvaluateForOverflow(const ASTContext &Ctx) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
bool IsConst;
EvalResult EVResult;
if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) {
@@ -11244,7 +12731,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::SizeOfPackExprClass:
case Expr::GNUNullExprClass:
- // GCC considers the GNU __null value to be an integral constant expression.
+ case Expr::SourceLocExprClass:
return NoDiag();
case Expr::SubstNonTypeTemplateParmExprClass:
@@ -11525,6 +13012,11 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::ChooseExprClass: {
return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(), Ctx);
}
+ case Expr::BuiltinBitCastExprClass: {
+ if (!checkBitCastConstexprEligibility(nullptr, Ctx, cast<CastExpr>(E)))
+ return ICEDiag(IK_NotICE, E->getBeginLoc());
+ return CheckICE(cast<CastExpr>(E)->getSubExpr(), Ctx);
+ }
}
llvm_unreachable("Invalid StmtClass!");
@@ -11555,6 +13047,9 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
SourceLocation *Loc) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc);
@@ -11568,6 +13063,9 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, const ASTContext &Ctx,
SourceLocation *Loc, bool isEvaluated) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc);
@@ -11591,11 +13089,17 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, const ASTContext &Ctx,
}
bool Expr::isCXX98IntegralConstantExpr(const ASTContext &Ctx) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
return CheckICE(this, Ctx).Kind == IK_ICE;
}
bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
SourceLocation *Loc) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
// We support this checking in C++98 mode in order to diagnose compatibility
// issues.
assert(Ctx.getLangOpts().CPlusPlus);
@@ -11624,8 +13128,12 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
const FunctionDecl *Callee,
ArrayRef<const Expr*> Args,
const Expr *This) const {
+ assert(!isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
Expr::EvalStatus Status;
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpressionUnevaluated);
+ Info.InConstantContext = true;
LValue ThisVal;
const LValue *ThisPtr = nullptr;
@@ -11704,16 +13212,20 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
const FunctionDecl *FD,
SmallVectorImpl<
PartialDiagnosticAt> &Diags) {
+ assert(!E->isValueDependent() &&
+ "Expression evaluator can't be called on a dependent expression.");
+
Expr::EvalStatus Status;
Status.Diag = &Diags;
EvalInfo Info(FD->getASTContext(), Status,
EvalInfo::EM_PotentialConstantExpressionUnevaluated);
+ Info.InConstantContext = true;
// Fabricate a call stack frame to give the arguments a plausible cover story.
ArrayRef<const Expr*> Args;
ArgVector ArgValues(0);
- bool Success = EvaluateArgs(Args, ArgValues, Info);
+ bool Success = EvaluateArgs(Args, ArgValues, Info, FD);
(void)Success;
assert(Success &&
"Failed to set up arguments for potential constant evaluation");
diff --git a/lib/AST/ExprObjC.cpp b/lib/AST/ExprObjC.cpp
index e1a23f5985892..53d0e873f8c9e 100644
--- a/lib/AST/ExprObjC.cpp
+++ b/lib/AST/ExprObjC.cpp
@@ -1,9 +1,8 @@
//===- ExprObjC.cpp - (ObjC) Expression AST Node Implementation -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -293,6 +292,32 @@ void ObjCMessageExpr::getSelectorLocs(
SelLocs.push_back(getSelectorLoc(i));
}
+
+QualType ObjCMessageExpr::getCallReturnType(ASTContext &Ctx) const {
+ if (const ObjCMethodDecl *MD = getMethodDecl()) {
+ QualType QT = MD->getReturnType();
+ if (QT == Ctx.getObjCInstanceType()) {
+ // instancetype corresponds to expression types.
+ return getType();
+ }
+ return QT;
+ }
+
+ // Expression type might be different from an expected call return type,
+ // as expression type would never be a reference even if call returns a
+ // reference. Reconstruct the original expression type.
+ QualType QT = getType();
+ switch (getValueKind()) {
+ case VK_LValue:
+ return Ctx.getLValueReferenceType(QT);
+ case VK_XValue:
+ return Ctx.getRValueReferenceType(QT);
+ case VK_RValue:
+ return QT;
+ }
+ llvm_unreachable("Unsupported ExprValueKind");
+}
+
SourceRange ObjCMessageExpr::getReceiverRange() const {
switch (getReceiverKind()) {
case Instance:
@@ -352,6 +377,11 @@ Stmt::child_range ObjCMessageExpr::children() {
reinterpret_cast<Stmt **>(getArgs() + getNumArgs()));
}
+Stmt::const_child_range ObjCMessageExpr::children() const {
+ auto Children = const_cast<ObjCMessageExpr *>(this)->children();
+ return const_child_range(Children.begin(), Children.end());
+}
+
StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
switch (getBridgeKind()) {
case OBC_Bridge:
diff --git a/lib/AST/ExternalASTMerger.cpp b/lib/AST/ExternalASTMerger.cpp
index 12e6bfc041a48..61e657da7c919 100644
--- a/lib/AST/ExternalASTMerger.cpp
+++ b/lib/AST/ExternalASTMerger.cpp
@@ -1,9 +1,8 @@
//===- ExternalASTMerger.cpp - Merging External AST Interface ---*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -57,7 +56,12 @@ LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,
}
auto *ND = cast<NamedDecl>(DC);
DeclarationName Name = ND->getDeclName();
- Source<DeclarationName> SourceName = ReverseImporter.Import(Name);
+ auto SourceNameOrErr = ReverseImporter.Import(Name);
+ if (!SourceNameOrErr) {
+ llvm::consumeError(SourceNameOrErr.takeError());
+ return nullptr;
+ }
+ Source<DeclarationName> SourceName = *SourceNameOrErr;
DeclContext::lookup_result SearchResult =
SourceParentDC.get()->lookup(SourceName.get());
size_t SearchResultSize = SearchResult.size();
@@ -111,7 +115,7 @@ public:
/// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin
/// map is kept up to date. Also set the appropriate flags.
- Decl *Imported(Decl *From, Decl *To) override {
+ void Imported(Decl *From, Decl *To) override {
if (auto *ToDC = dyn_cast<DeclContext>(To)) {
const bool LoggingEnabled = Parent.LoggingEnabled();
if (LoggingEnabled)
@@ -154,7 +158,6 @@ public:
ToContainer->getPrimaryContext()->setMustBuildLookupTable();
assert(Parent.CanComplete(ToContainer));
}
- return To;
}
ASTImporter &GetReverse() { return Reverse; }
};
@@ -230,7 +233,7 @@ void ExternalASTMerger::CompleteType(TagDecl *Tag) {
if (!SourceTag->getDefinition())
return false;
Forward.MapImported(SourceTag, Tag);
- if (llvm::Error Err = Forward.ImportDefinition_New(SourceTag))
+ if (llvm::Error Err = Forward.ImportDefinition(SourceTag))
llvm::consumeError(std::move(Err));
Tag->setCompleteDefinition(SourceTag->isCompleteDefinition());
return true;
@@ -250,7 +253,7 @@ void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) {
if (!SourceInterface->getDefinition())
return false;
Forward.MapImported(SourceInterface, Interface);
- if (llvm::Error Err = Forward.ImportDefinition_New(SourceInterface))
+ if (llvm::Error Err = Forward.ImportDefinition(SourceInterface))
llvm::consumeError(std::move(Err));
return true;
});
@@ -356,9 +359,13 @@ void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) {
template <typename DeclTy>
static bool importSpecializations(DeclTy *D, ASTImporter *Importer) {
- for (auto *Spec : D->specializations())
- if (!Importer->Import(Spec))
+ for (auto *Spec : D->specializations()) {
+ auto ImportedSpecOrError = Importer->Import(Spec);
+ if (!ImportedSpecOrError) {
+ llvm::consumeError(ImportedSpecOrError.takeError());
return true;
+ }
+ }
return false;
}
@@ -385,15 +392,21 @@ bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
Candidates.push_back(C);
};
- ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,
- Source<const DeclContext *> SourceDC) -> bool {
- DeclarationName FromName = Reverse.Import(Name);
- DeclContextLookupResult Result = SourceDC.get()->lookup(FromName);
- for (NamedDecl *FromD : Result) {
- FilterFoundDecl(std::make_pair(FromD, &Forward));
- }
- return false;
- });
+ ForEachMatchingDC(DC,
+ [&](ASTImporter &Forward, ASTImporter &Reverse,
+ Source<const DeclContext *> SourceDC) -> bool {
+ auto FromNameOrErr = Reverse.Import(Name);
+ if (!FromNameOrErr) {
+ llvm::consumeError(FromNameOrErr.takeError());
+ return false;
+ }
+ DeclContextLookupResult Result =
+ SourceDC.get()->lookup(*FromNameOrErr);
+ for (NamedDecl *FromD : Result) {
+ FilterFoundDecl(std::make_pair(FromD, &Forward));
+ }
+ return false;
+ });
if (Candidates.empty())
return false;
@@ -402,7 +415,10 @@ bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
for (const Candidate &C : Candidates) {
Decl *LookupRes = C.first.get();
ASTImporter *Importer = C.second;
- NamedDecl *ND = cast_or_null<NamedDecl>(Importer->Import(LookupRes));
+ auto NDOrErr = Importer->Import(LookupRes);
+ assert(NDOrErr);
+ (void)static_cast<bool>(NDOrErr);
+ NamedDecl *ND = cast_or_null<NamedDecl>(*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
@@ -424,9 +440,12 @@ void ExternalASTMerger::FindExternalLexicalDecls(
Source<const DeclContext *> SourceDC) -> bool {
for (const Decl *SourceDecl : SourceDC.get()->decls()) {
if (IsKindWeWant(SourceDecl->getKind())) {
- Decl *ImportedDecl = Forward.Import(const_cast<Decl *>(SourceDecl));
- assert(!ImportedDecl || IsSameDC(ImportedDecl->getDeclContext(), DC));
- (void)ImportedDecl;
+ auto ImportedDeclOrErr = Forward.Import(SourceDecl);
+ if (ImportedDeclOrErr)
+ assert(!(*ImportedDeclOrErr) ||
+ IsSameDC((*ImportedDeclOrErr)->getDeclContext(), DC));
+ else
+ llvm::consumeError(ImportedDeclOrErr.takeError());
}
}
return false;
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index 40829c2e249dd..7301027574407 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/lib/AST/ExternalASTSource.cpp
@@ -1,9 +1,8 @@
//===- ExternalASTSource.cpp - Abstract External AST Interface ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/FormatString.cpp b/lib/AST/FormatString.cpp
index 04bd48f14a2a0..578d5bc567338 100644
--- a/lib/AST/FormatString.cpp
+++ b/lib/AST/FormatString.cpp
@@ -1,9 +1,8 @@
// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -224,6 +223,9 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
if (I != E && *I == 'h') {
++I;
lmKind = LengthModifier::AsChar;
+ } else if (I != E && *I == 'l' && LO.OpenCL) {
+ ++I;
+ lmKind = LengthModifier::AsShortLong;
} else {
lmKind = LengthModifier::AsShort;
}
@@ -488,7 +490,8 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
}
ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const {
- if (K != SpecificTy) // Won't be a valid vector element type.
+ // Check for valid vector element types.
+ if (T.isNull())
return ArgType::Invalid();
QualType Vec = C.getExtVectorType(T, NumElts);
@@ -573,6 +576,8 @@ analyze_format_string::LengthModifier::toString() const {
return "hh";
case AsShort:
return "h";
+ case AsShortLong:
+ return "hl";
case AsLong: // or AsWideChar
return "l";
case AsLongLong:
@@ -708,13 +713,18 @@ void OptionalAmount::toString(raw_ostream &os) const {
}
}
-bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
+bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
+ const LangOptions &LO) const {
switch (LM.getKind()) {
case LengthModifier::None:
return true;
// Handle most integer flags
case LengthModifier::AsShort:
+ // Length modifier only applies to FP vectors.
+ if (LO.OpenCL && CS.isDoubleArg())
+ return !VectorNumElts.isInvalid();
+
if (Target.getTriple().isOSMSVCRT()) {
switch (CS.getKind()) {
case ConversionSpecifier::cArg:
@@ -753,8 +763,18 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
return false;
}
+ case LengthModifier::AsShortLong:
+ return LO.OpenCL && !VectorNumElts.isInvalid();
+
// Handle 'l' flag
case LengthModifier::AsLong: // or AsWideChar
+ if (CS.isDoubleArg()) {
+ // Invalid for OpenCL FP scalars.
+ if (LO.OpenCL && VectorNumElts.isInvalid())
+ return false;
+ return true;
+ }
+
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
case ConversionSpecifier::DArg:
@@ -765,14 +785,6 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
- case ConversionSpecifier::aArg:
- case ConversionSpecifier::AArg:
- case ConversionSpecifier::fArg:
- case ConversionSpecifier::FArg:
- case ConversionSpecifier::eArg:
- case ConversionSpecifier::EArg:
- case ConversionSpecifier::gArg:
- case ConversionSpecifier::GArg:
case ConversionSpecifier::nArg:
case ConversionSpecifier::cArg:
case ConversionSpecifier::sArg:
@@ -879,6 +891,7 @@ bool FormatSpecifier::hasStandardLengthModifier() const {
case LengthModifier::AsInt3264:
case LengthModifier::AsInt64:
case LengthModifier::AsWide:
+ case LengthModifier::AsShortLong: // ???
return false;
}
llvm_unreachable("Invalid LengthModifier Kind!");
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index 0b82da133fa76..4b3d5bee5631e 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -1,9 +1,8 @@
//===- InheritViz.cpp - Graphviz visualization for inheritance --*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index 64580edf004b6..727a905d08a14 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -1,9 +1,8 @@
//===------- ItaniumCXXABI.cpp - AST support for the Itanium C++ ABI ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 98c843db31d62..6c813f09a4b3c 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -1,9 +1,8 @@
//===--- ItaniumMangle.cpp - Itanium C++ Name Mangling ----------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -61,7 +60,8 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) {
}
const DeclContext *DC = D->getDeclContext();
- if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC)) {
+ if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC) ||
+ isa<OMPDeclareMapperDecl>(DC)) {
return getEffectiveDeclContext(cast<Decl>(DC));
}
@@ -486,6 +486,7 @@ private:
const AbiTagList *AdditionalAbiTags);
void mangleBlockForPrefix(const BlockDecl *Block);
void mangleUnqualifiedBlock(const BlockDecl *Block);
+ void mangleTemplateParamDecl(const NamedDecl *Decl);
void mangleLambda(const CXXRecordDecl *Lambda);
void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
const AbiTagList *AdditionalAbiTags,
@@ -537,6 +538,7 @@ private:
unsigned knownArity);
void mangleCastExpression(const Expr *E, StringRef CastEncoding);
void mangleInitListElements(const InitListExpr *InitList);
+ void mangleDeclRefExpr(const NamedDecl *D);
void mangleExpression(const Expr *E, unsigned Arity = UnknownArity);
void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom);
void mangleCXXDtorType(CXXDtorType T);
@@ -1372,7 +1374,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// <unnamed-type-name> ::= <closure-type-name>
//
// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
- // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'.
+ // <lambda-sig> ::= <template-param-decl>* <parameter-type>+
+ // # Parameter types or 'v' for 'void'.
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
if (Record->isLambda() && Record->getLambdaManglingNumber()) {
assert(!AdditionalAbiTags &&
@@ -1503,7 +1506,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
Out << 'N';
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) {
- Qualifiers MethodQuals = Method->getTypeQualifiers();
+ Qualifiers MethodQuals = Method->getMethodQualifiers();
// We do not consider restrict a distinguishing attribute for overloading
// purposes so we must not mangle it.
MethodQuals.removeRestrict();
@@ -1678,6 +1681,24 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
Out << '_';
}
+// <template-param-decl>
+// ::= Ty # template type parameter
+// ::= Tn <type> # template non-type parameter
+// ::= Tt <template-param-decl>* E # template template parameter
+void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
+ if (isa<TemplateTypeParmDecl>(Decl)) {
+ Out << "Ty";
+ } else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) {
+ Out << "Tn";
+ mangleType(Tn->getType());
+ } else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) {
+ Out << "Tt";
+ for (auto *Param : *Tt->getTemplateParameters())
+ mangleTemplateParamDecl(Param);
+ Out << "E";
+ }
+}
+
void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
// If the context of a closure type is an initializer for a class member
// (static or nonstatic), it is encoded in a qualified name with a final
@@ -1705,6 +1726,8 @@ 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,
@@ -1869,6 +1892,7 @@ void CXXNameMangler::mangleType(TemplateName TN) {
break;
case TemplateName::OverloadedTemplate:
+ case TemplateName::AssumedTemplate:
llvm_unreachable("can't mangle an overloaded template name as a <type>");
case TemplateName::DependentTemplate: {
@@ -1941,6 +1965,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::ObjCTypeParam:
case Type::Atomic:
case Type::Pipe:
+ case Type::MacroQualified:
llvm_unreachable("type is illegal as a nested name specifier");
case Type::SubstTemplateTypeParmPack:
@@ -2007,6 +2032,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
}
case TemplateName::OverloadedTemplate:
+ case TemplateName::AssumedTemplate:
case TemplateName::DependentTemplate:
llvm_unreachable("invalid base for a template specialization type");
@@ -2581,17 +2607,22 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Double:
Out << 'd';
break;
- case BuiltinType::LongDouble:
- Out << (getASTContext().getTargetInfo().useFloat128ManglingForLongDouble()
- ? 'g'
- : 'e');
+ case BuiltinType::LongDouble: {
+ const TargetInfo *TI = getASTContext().getLangOpts().OpenMP &&
+ getASTContext().getLangOpts().OpenMPIsDevice
+ ? getASTContext().getAuxTargetInfo()
+ : &getASTContext().getTargetInfo();
+ Out << TI->getLongDoubleMangling();
break;
- case BuiltinType::Float128:
- if (getASTContext().getTargetInfo().useFloat128ManglingForLongDouble())
- Out << "U10__float128"; // Match the GCC mangling
- else
- Out << 'g';
+ }
+ case BuiltinType::Float128: {
+ const TargetInfo *TI = getASTContext().getLangOpts().OpenMP &&
+ getASTContext().getLangOpts().OpenMPIsDevice
+ ? getASTContext().getAuxTargetInfo()
+ : &getASTContext().getTargetInfo();
+ Out << TI->getFloat128Mangling();
break;
+ }
case BuiltinType::NullPtr:
Out << "Dn";
break;
@@ -2735,7 +2766,7 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) {
// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
// e.g. "const" in "int (A::*)() const".
- mangleQualifiers(T->getTypeQuals());
+ mangleQualifiers(T->getMethodQuals());
// Mangle instantiation-dependent exception-specification, if present,
// per cxx-abi-dev proposal on 2016-10-11.
@@ -2833,7 +2864,10 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionProtoType *Proto,
if (auto *Attr = FD->getParamDecl(I)->getAttr<PassObjectSizeAttr>()) {
// Attr can only take 1 character, so we can hardcode the length below.
assert(Attr->getType() <= 9 && Attr->getType() >= 0);
- Out << "U17pass_object_size" << Attr->getType();
+ if (Attr->isDynamic())
+ Out << "U25pass_dynamic_object_size" << Attr->getType();
+ else
+ Out << "U17pass_object_size" << Attr->getType();
}
}
}
@@ -3471,6 +3505,32 @@ void CXXNameMangler::mangleInitListElements(const InitListExpr *InitList) {
mangleExpression(InitList->getInit(i));
}
+void CXXNameMangler::mangleDeclRefExpr(const NamedDecl *D) {
+ switch (D->getKind()) {
+ default:
+ // <expr-primary> ::= L <mangled-name> E # external name
+ Out << 'L';
+ mangle(D);
+ Out << 'E';
+ break;
+
+ case Decl::ParmVar:
+ mangleFunctionParam(cast<ParmVarDecl>(D));
+ break;
+
+ case Decl::EnumConstant: {
+ const EnumConstantDecl *ED = cast<EnumConstantDecl>(D);
+ mangleIntegerLiteral(ED->getType(), ED->getInitVal());
+ break;
+ }
+
+ case Decl::NonTypeTemplateParm:
+ const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
+ mangleTemplateParameter(PD->getIndex());
+ break;
+ }
+}
+
void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
@@ -3561,7 +3621,9 @@ recurse:
case Expr::AsTypeExprClass:
case Expr::PseudoObjectExprClass:
case Expr::AtomicExprClass:
+ case Expr::SourceLocExprClass:
case Expr::FixedPointLiteralClass:
+ case Expr::BuiltinBitCastExprClass:
{
if (!NullOut) {
// As bad as this diagnostic is, it's better than crashing.
@@ -3725,7 +3787,7 @@ recurse:
if (TypeSourceInfo *ScopeInfo = PDE->getScopeTypeInfo()) {
if (Qualifier) {
mangleUnresolvedPrefix(Qualifier,
- /*Recursive=*/true);
+ /*recursive=*/true);
mangleUnresolvedTypeOrSimpleId(ScopeInfo->getType());
Out << 'E';
} else {
@@ -3896,7 +3958,7 @@ recurse:
Diags.Report(DiagID);
return;
}
- case UETT_OpenMPRequiredSimdAlign:
+ case UETT_OpenMPRequiredSimdAlign: {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error,
@@ -3904,6 +3966,7 @@ recurse:
Diags.Report(DiagID);
return;
}
+ }
if (SAE->isArgumentType()) {
Out << 't';
mangleType(SAE->getArgumentType());
@@ -4060,37 +4123,9 @@ recurse:
mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity);
break;
- case Expr::DeclRefExprClass: {
- const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
-
- switch (D->getKind()) {
- default:
- // <expr-primary> ::= L <mangled-name> E # external name
- Out << 'L';
- mangle(D);
- Out << 'E';
- break;
-
- case Decl::ParmVar:
- mangleFunctionParam(cast<ParmVarDecl>(D));
- break;
-
- case Decl::EnumConstant: {
- const EnumConstantDecl *ED = cast<EnumConstantDecl>(D);
- mangleIntegerLiteral(ED->getType(), ED->getInitVal());
- break;
- }
-
- case Decl::NonTypeTemplateParm: {
- const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
- mangleTemplateParameter(PD->getIndex());
- break;
- }
-
- }
-
+ case Expr::DeclRefExprClass:
+ mangleDeclRefExpr(cast<DeclRefExpr>(E)->getDecl());
break;
- }
case Expr::SubstNonTypeTemplateParmPackExprClass:
// FIXME: not clear how to mangle this!
@@ -4104,7 +4139,7 @@ recurse:
// FIXME: not clear how to mangle this!
const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E);
Out << "v110_SUBSTPACK";
- mangleFunctionParam(FPPE->getParameterPack());
+ mangleDeclRefExpr(FPPE->getParameterPack());
break;
}
@@ -4454,7 +4489,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
// It's possible to end up with a DeclRefExpr here in certain
// dependent cases, in which case we should mangle as a
// declaration.
- const Expr *E = A.getAsExpr()->IgnoreParens();
+ const Expr *E = A.getAsExpr()->IgnoreParenImpCasts();
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
const ValueDecl *D = DRE->getDecl();
if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) {
diff --git a/lib/AST/JSONNodeDumper.cpp b/lib/AST/JSONNodeDumper.cpp
new file mode 100644
index 0000000000000..04b933b0fb306
--- /dev/null
+++ b/lib/AST/JSONNodeDumper.cpp
@@ -0,0 +1,1569 @@
+#include "clang/AST/JSONNodeDumper.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+
+void JSONNodeDumper::addPreviousDeclaration(const Decl *D) {
+ switch (D->getKind()) {
+#define DECL(DERIVED, BASE) \
+ case Decl::DERIVED: \
+ return writePreviousDeclImpl(cast<DERIVED##Decl>(D));
+#define ABSTRACT_DECL(DECL)
+#include "clang/AST/DeclNodes.inc"
+#undef ABSTRACT_DECL
+#undef DECL
+ }
+ llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
+}
+
+void JSONNodeDumper::Visit(const Attr *A) {
+ const char *AttrName = nullptr;
+ switch (A->getKind()) {
+#define ATTR(X) \
+ case attr::X: \
+ AttrName = #X"Attr"; \
+ break;
+#include "clang/Basic/AttrList.inc"
+#undef ATTR
+ }
+ JOS.attribute("id", createPointerRepresentation(A));
+ JOS.attribute("kind", AttrName);
+ JOS.attributeObject("range", [A, this] { writeSourceRange(A->getRange()); });
+ attributeOnlyIfTrue("inherited", A->isInherited());
+ attributeOnlyIfTrue("implicit", A->isImplicit());
+
+ // FIXME: it would be useful for us to output the spelling kind as well as
+ // the actual spelling. This would allow us to distinguish between the
+ // various attribute syntaxes, but we don't currently track that information
+ // within the AST.
+ //JOS.attribute("spelling", A->getSpelling());
+
+ InnerAttrVisitor::Visit(A);
+}
+
+void JSONNodeDumper::Visit(const Stmt *S) {
+ if (!S)
+ return;
+
+ JOS.attribute("id", createPointerRepresentation(S));
+ JOS.attribute("kind", S->getStmtClassName());
+ JOS.attributeObject("range",
+ [S, this] { writeSourceRange(S->getSourceRange()); });
+
+ if (const auto *E = dyn_cast<Expr>(S)) {
+ JOS.attribute("type", createQualType(E->getType()));
+ const char *Category = nullptr;
+ switch (E->getValueKind()) {
+ case VK_LValue: Category = "lvalue"; break;
+ case VK_XValue: Category = "xvalue"; break;
+ case VK_RValue: Category = "rvalue"; break;
+ }
+ JOS.attribute("valueCategory", Category);
+ }
+ InnerStmtVisitor::Visit(S);
+}
+
+void JSONNodeDumper::Visit(const Type *T) {
+ JOS.attribute("id", createPointerRepresentation(T));
+ JOS.attribute("kind", (llvm::Twine(T->getTypeClassName()) + "Type").str());
+ JOS.attribute("type", createQualType(QualType(T, 0), /*Desugar*/ false));
+ attributeOnlyIfTrue("isDependent", T->isDependentType());
+ attributeOnlyIfTrue("isInstantiationDependent",
+ T->isInstantiationDependentType());
+ attributeOnlyIfTrue("isVariablyModified", T->isVariablyModifiedType());
+ attributeOnlyIfTrue("containsUnexpandedPack",
+ T->containsUnexpandedParameterPack());
+ attributeOnlyIfTrue("isImported", T->isFromAST());
+ InnerTypeVisitor::Visit(T);
+}
+
+void JSONNodeDumper::Visit(QualType T) {
+ JOS.attribute("id", createPointerRepresentation(T.getAsOpaquePtr()));
+ JOS.attribute("kind", "QualType");
+ JOS.attribute("type", createQualType(T));
+ JOS.attribute("qualifiers", T.split().Quals.getAsString());
+}
+
+void JSONNodeDumper::Visit(const Decl *D) {
+ JOS.attribute("id", createPointerRepresentation(D));
+
+ if (!D)
+ return;
+
+ JOS.attribute("kind", (llvm::Twine(D->getDeclKindName()) + "Decl").str());
+ JOS.attributeObject("loc",
+ [D, this] { writeSourceLocation(D->getLocation()); });
+ JOS.attributeObject("range",
+ [D, this] { writeSourceRange(D->getSourceRange()); });
+ attributeOnlyIfTrue("isImplicit", D->isImplicit());
+ attributeOnlyIfTrue("isInvalid", D->isInvalidDecl());
+
+ if (D->isUsed())
+ JOS.attribute("isUsed", true);
+ else if (D->isThisDeclarationReferenced())
+ JOS.attribute("isReferenced", true);
+
+ if (const auto *ND = dyn_cast<NamedDecl>(D))
+ attributeOnlyIfTrue("isHidden", ND->isHidden());
+
+ if (D->getLexicalDeclContext() != D->getDeclContext())
+ JOS.attribute("parentDeclContext",
+ createPointerRepresentation(D->getDeclContext()));
+
+ addPreviousDeclaration(D);
+ InnerDeclVisitor::Visit(D);
+}
+
+void JSONNodeDumper::Visit(const comments::Comment *C,
+ const comments::FullComment *FC) {
+ if (!C)
+ return;
+
+ JOS.attribute("id", createPointerRepresentation(C));
+ JOS.attribute("kind", C->getCommentKindName());
+ JOS.attributeObject("loc",
+ [C, this] { writeSourceLocation(C->getLocation()); });
+ JOS.attributeObject("range",
+ [C, this] { writeSourceRange(C->getSourceRange()); });
+
+ InnerCommentVisitor::visit(C, FC);
+}
+
+void JSONNodeDumper::Visit(const TemplateArgument &TA, SourceRange R,
+ const Decl *From, StringRef Label) {
+ JOS.attribute("kind", "TemplateArgument");
+ if (R.isValid())
+ JOS.attributeObject("range", [R, this] { writeSourceRange(R); });
+
+ if (From)
+ JOS.attribute(Label.empty() ? "fromDecl" : Label, createBareDeclRef(From));
+
+ InnerTemplateArgVisitor::Visit(TA);
+}
+
+void JSONNodeDumper::Visit(const CXXCtorInitializer *Init) {
+ JOS.attribute("kind", "CXXCtorInitializer");
+ if (Init->isAnyMemberInitializer())
+ JOS.attribute("anyInit", createBareDeclRef(Init->getAnyMember()));
+ else if (Init->isBaseInitializer())
+ JOS.attribute("baseInit",
+ createQualType(QualType(Init->getBaseClass(), 0)));
+ else if (Init->isDelegatingInitializer())
+ JOS.attribute("delegatingInit",
+ createQualType(Init->getTypeSourceInfo()->getType()));
+ else
+ llvm_unreachable("Unknown initializer type");
+}
+
+void JSONNodeDumper::Visit(const OMPClause *C) {}
+
+void JSONNodeDumper::Visit(const BlockDecl::Capture &C) {
+ JOS.attribute("kind", "Capture");
+ attributeOnlyIfTrue("byref", C.isByRef());
+ attributeOnlyIfTrue("nested", C.isNested());
+ if (C.getVariable())
+ JOS.attribute("var", createBareDeclRef(C.getVariable()));
+}
+
+void JSONNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) {
+ JOS.attribute("associationKind", A.getTypeSourceInfo() ? "case" : "default");
+ attributeOnlyIfTrue("selected", A.isSelected());
+}
+
+void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc,
+ bool IsSpelling) {
+ PresumedLoc Presumed = SM.getPresumedLoc(Loc);
+ unsigned ActualLine = IsSpelling ? SM.getSpellingLineNumber(Loc)
+ : SM.getExpansionLineNumber(Loc);
+ if (Presumed.isValid()) {
+ if (LastLocFilename != Presumed.getFilename()) {
+ JOS.attribute("file", Presumed.getFilename());
+ JOS.attribute("line", ActualLine);
+ } else if (LastLocLine != ActualLine)
+ JOS.attribute("line", ActualLine);
+
+ unsigned PresumedLine = Presumed.getLine();
+ if (ActualLine != PresumedLine && LastLocPresumedLine != PresumedLine)
+ JOS.attribute("presumedLine", PresumedLine);
+
+ JOS.attribute("col", Presumed.getColumn());
+ JOS.attribute("tokLen",
+ Lexer::MeasureTokenLength(Loc, SM, Ctx.getLangOpts()));
+ LastLocFilename = Presumed.getFilename();
+ LastLocPresumedLine = PresumedLine;
+ LastLocLine = ActualLine;
+ }
+}
+
+void JSONNodeDumper::writeSourceLocation(SourceLocation Loc) {
+ SourceLocation Spelling = SM.getSpellingLoc(Loc);
+ SourceLocation Expansion = SM.getExpansionLoc(Loc);
+
+ if (Expansion != Spelling) {
+ // If the expansion and the spelling are different, output subobjects
+ // describing both locations.
+ JOS.attributeObject("spellingLoc", [Spelling, this] {
+ writeBareSourceLocation(Spelling, /*IsSpelling*/ true);
+ });
+ JOS.attributeObject("expansionLoc", [Expansion, Loc, this] {
+ writeBareSourceLocation(Expansion, /*IsSpelling*/ false);
+ // If there is a macro expansion, add extra information if the interesting
+ // bit is the macro arg expansion.
+ if (SM.isMacroArgExpansion(Loc))
+ JOS.attribute("isMacroArgExpansion", true);
+ });
+ } else
+ writeBareSourceLocation(Spelling, /*IsSpelling*/ true);
+}
+
+void JSONNodeDumper::writeSourceRange(SourceRange R) {
+ JOS.attributeObject("begin",
+ [R, this] { writeSourceLocation(R.getBegin()); });
+ JOS.attributeObject("end", [R, this] { writeSourceLocation(R.getEnd()); });
+}
+
+std::string JSONNodeDumper::createPointerRepresentation(const void *Ptr) {
+ // Because JSON stores integer values as signed 64-bit integers, trying to
+ // represent them as such makes for very ugly pointer values in the resulting
+ // output. Instead, we convert the value to hex and treat it as a string.
+ return "0x" + llvm::utohexstr(reinterpret_cast<uint64_t>(Ptr), true);
+}
+
+llvm::json::Object JSONNodeDumper::createQualType(QualType QT, bool Desugar) {
+ SplitQualType SQT = QT.split();
+ llvm::json::Object Ret{{"qualType", QualType::getAsString(SQT, PrintPolicy)}};
+
+ if (Desugar && !QT.isNull()) {
+ SplitQualType DSQT = QT.getSplitDesugaredType();
+ if (DSQT != SQT)
+ Ret["desugaredQualType"] = QualType::getAsString(DSQT, PrintPolicy);
+ }
+ return Ret;
+}
+
+void JSONNodeDumper::writeBareDeclRef(const Decl *D) {
+ JOS.attribute("id", createPointerRepresentation(D));
+ if (!D)
+ return;
+
+ JOS.attribute("kind", (llvm::Twine(D->getDeclKindName()) + "Decl").str());
+ if (const auto *ND = dyn_cast<NamedDecl>(D))
+ JOS.attribute("name", ND->getDeclName().getAsString());
+ if (const auto *VD = dyn_cast<ValueDecl>(D))
+ JOS.attribute("type", createQualType(VD->getType()));
+}
+
+llvm::json::Object JSONNodeDumper::createBareDeclRef(const Decl *D) {
+ llvm::json::Object Ret{{"id", createPointerRepresentation(D)}};
+ if (!D)
+ return Ret;
+
+ Ret["kind"] = (llvm::Twine(D->getDeclKindName()) + "Decl").str();
+ if (const auto *ND = dyn_cast<NamedDecl>(D))
+ Ret["name"] = ND->getDeclName().getAsString();
+ if (const auto *VD = dyn_cast<ValueDecl>(D))
+ Ret["type"] = createQualType(VD->getType());
+ return Ret;
+}
+
+llvm::json::Array JSONNodeDumper::createCastPath(const CastExpr *C) {
+ llvm::json::Array Ret;
+ if (C->path_empty())
+ return Ret;
+
+ 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());
+
+ llvm::json::Object Val{{"name", RD->getName()}};
+ if (Base->isVirtual())
+ Val["isVirtual"] = true;
+ Ret.push_back(std::move(Val));
+ }
+ return Ret;
+}
+
+#define FIELD2(Name, Flag) if (RD->Flag()) Ret[Name] = true
+#define FIELD1(Flag) FIELD2(#Flag, Flag)
+
+static llvm::json::Object
+createDefaultConstructorDefinitionData(const CXXRecordDecl *RD) {
+ llvm::json::Object Ret;
+
+ FIELD2("exists", hasDefaultConstructor);
+ FIELD2("trivial", hasTrivialDefaultConstructor);
+ FIELD2("nonTrivial", hasNonTrivialDefaultConstructor);
+ FIELD2("userProvided", hasUserProvidedDefaultConstructor);
+ FIELD2("isConstexpr", hasConstexprDefaultConstructor);
+ FIELD2("needsImplicit", needsImplicitDefaultConstructor);
+ FIELD2("defaultedIsConstexpr", defaultedDefaultConstructorIsConstexpr);
+
+ return Ret;
+}
+
+static llvm::json::Object
+createCopyConstructorDefinitionData(const CXXRecordDecl *RD) {
+ llvm::json::Object Ret;
+
+ FIELD2("simple", hasSimpleCopyConstructor);
+ FIELD2("trivial", hasTrivialCopyConstructor);
+ FIELD2("nonTrivial", hasNonTrivialCopyConstructor);
+ FIELD2("userDeclared", hasUserDeclaredCopyConstructor);
+ FIELD2("hasConstParam", hasCopyConstructorWithConstParam);
+ FIELD2("implicitHasConstParam", implicitCopyConstructorHasConstParam);
+ FIELD2("needsImplicit", needsImplicitCopyConstructor);
+ FIELD2("needsOverloadResolution", needsOverloadResolutionForCopyConstructor);
+ if (!RD->needsOverloadResolutionForCopyConstructor())
+ FIELD2("defaultedIsDeleted", defaultedCopyConstructorIsDeleted);
+
+ return Ret;
+}
+
+static llvm::json::Object
+createMoveConstructorDefinitionData(const CXXRecordDecl *RD) {
+ llvm::json::Object Ret;
+
+ FIELD2("exists", hasMoveConstructor);
+ FIELD2("simple", hasSimpleMoveConstructor);
+ FIELD2("trivial", hasTrivialMoveConstructor);
+ FIELD2("nonTrivial", hasNonTrivialMoveConstructor);
+ FIELD2("userDeclared", hasUserDeclaredMoveConstructor);
+ FIELD2("needsImplicit", needsImplicitMoveConstructor);
+ FIELD2("needsOverloadResolution", needsOverloadResolutionForMoveConstructor);
+ if (!RD->needsOverloadResolutionForMoveConstructor())
+ FIELD2("defaultedIsDeleted", defaultedMoveConstructorIsDeleted);
+
+ return Ret;
+}
+
+static llvm::json::Object
+createCopyAssignmentDefinitionData(const CXXRecordDecl *RD) {
+ llvm::json::Object Ret;
+
+ FIELD2("trivial", hasTrivialCopyAssignment);
+ FIELD2("nonTrivial", hasNonTrivialCopyAssignment);
+ FIELD2("hasConstParam", hasCopyAssignmentWithConstParam);
+ FIELD2("implicitHasConstParam", implicitCopyAssignmentHasConstParam);
+ FIELD2("userDeclared", hasUserDeclaredCopyAssignment);
+ FIELD2("needsImplicit", needsImplicitCopyAssignment);
+ FIELD2("needsOverloadResolution", needsOverloadResolutionForCopyAssignment);
+
+ return Ret;
+}
+
+static llvm::json::Object
+createMoveAssignmentDefinitionData(const CXXRecordDecl *RD) {
+ llvm::json::Object Ret;
+
+ FIELD2("exists", hasMoveAssignment);
+ FIELD2("simple", hasSimpleMoveAssignment);
+ FIELD2("trivial", hasTrivialMoveAssignment);
+ FIELD2("nonTrivial", hasNonTrivialMoveAssignment);
+ FIELD2("userDeclared", hasUserDeclaredMoveAssignment);
+ FIELD2("needsImplicit", needsImplicitMoveAssignment);
+ FIELD2("needsOverloadResolution", needsOverloadResolutionForMoveAssignment);
+
+ return Ret;
+}
+
+static llvm::json::Object
+createDestructorDefinitionData(const CXXRecordDecl *RD) {
+ llvm::json::Object Ret;
+
+ FIELD2("simple", hasSimpleDestructor);
+ FIELD2("irrelevant", hasIrrelevantDestructor);
+ FIELD2("trivial", hasTrivialDestructor);
+ FIELD2("nonTrivial", hasNonTrivialDestructor);
+ FIELD2("userDeclared", hasUserDeclaredDestructor);
+ FIELD2("needsImplicit", needsImplicitDestructor);
+ FIELD2("needsOverloadResolution", needsOverloadResolutionForDestructor);
+ if (!RD->needsOverloadResolutionForDestructor())
+ FIELD2("defaultedIsDeleted", defaultedDestructorIsDeleted);
+
+ return Ret;
+}
+
+llvm::json::Object
+JSONNodeDumper::createCXXRecordDefinitionData(const CXXRecordDecl *RD) {
+ llvm::json::Object Ret;
+
+ // This data is common to all C++ classes.
+ FIELD1(isGenericLambda);
+ FIELD1(isLambda);
+ FIELD1(isEmpty);
+ FIELD1(isAggregate);
+ FIELD1(isStandardLayout);
+ FIELD1(isTriviallyCopyable);
+ FIELD1(isPOD);
+ FIELD1(isTrivial);
+ FIELD1(isPolymorphic);
+ FIELD1(isAbstract);
+ FIELD1(isLiteral);
+ FIELD1(canPassInRegisters);
+ FIELD1(hasUserDeclaredConstructor);
+ FIELD1(hasConstexprNonCopyMoveConstructor);
+ FIELD1(hasMutableFields);
+ FIELD1(hasVariantMembers);
+ FIELD2("canConstDefaultInit", allowConstDefaultInit);
+
+ Ret["defaultCtor"] = createDefaultConstructorDefinitionData(RD);
+ Ret["copyCtor"] = createCopyConstructorDefinitionData(RD);
+ Ret["moveCtor"] = createMoveConstructorDefinitionData(RD);
+ Ret["copyAssign"] = createCopyAssignmentDefinitionData(RD);
+ Ret["moveAssign"] = createMoveAssignmentDefinitionData(RD);
+ Ret["dtor"] = createDestructorDefinitionData(RD);
+
+ return Ret;
+}
+
+#undef FIELD1
+#undef FIELD2
+
+std::string JSONNodeDumper::createAccessSpecifier(AccessSpecifier AS) {
+ switch (AS) {
+ case AS_none: return "none";
+ case AS_private: return "private";
+ case AS_protected: return "protected";
+ case AS_public: return "public";
+ }
+ llvm_unreachable("Unknown access specifier");
+}
+
+llvm::json::Object
+JSONNodeDumper::createCXXBaseSpecifier(const CXXBaseSpecifier &BS) {
+ llvm::json::Object Ret;
+
+ Ret["type"] = createQualType(BS.getType());
+ Ret["access"] = createAccessSpecifier(BS.getAccessSpecifier());
+ Ret["writtenAccess"] =
+ createAccessSpecifier(BS.getAccessSpecifierAsWritten());
+ if (BS.isVirtual())
+ Ret["isVirtual"] = true;
+ if (BS.isPackExpansion())
+ Ret["isPackExpansion"] = true;
+
+ return Ret;
+}
+
+void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) {
+ JOS.attribute("decl", createBareDeclRef(TT->getDecl()));
+}
+
+void JSONNodeDumper::VisitFunctionType(const FunctionType *T) {
+ FunctionType::ExtInfo E = T->getExtInfo();
+ attributeOnlyIfTrue("noreturn", E.getNoReturn());
+ attributeOnlyIfTrue("producesResult", E.getProducesResult());
+ if (E.getHasRegParm())
+ JOS.attribute("regParm", E.getRegParm());
+ JOS.attribute("cc", FunctionType::getNameForCallConv(E.getCC()));
+}
+
+void JSONNodeDumper::VisitFunctionProtoType(const FunctionProtoType *T) {
+ FunctionProtoType::ExtProtoInfo E = T->getExtProtoInfo();
+ attributeOnlyIfTrue("trailingReturn", E.HasTrailingReturn);
+ attributeOnlyIfTrue("const", T->isConst());
+ attributeOnlyIfTrue("volatile", T->isVolatile());
+ attributeOnlyIfTrue("restrict", T->isRestrict());
+ attributeOnlyIfTrue("variadic", E.Variadic);
+ switch (E.RefQualifier) {
+ case RQ_LValue: JOS.attribute("refQualifier", "&"); break;
+ case RQ_RValue: JOS.attribute("refQualifier", "&&"); break;
+ case RQ_None: break;
+ }
+ switch (E.ExceptionSpec.Type) {
+ case EST_DynamicNone:
+ case EST_Dynamic: {
+ JOS.attribute("exceptionSpec", "throw");
+ llvm::json::Array Types;
+ for (QualType QT : E.ExceptionSpec.Exceptions)
+ Types.push_back(createQualType(QT));
+ JOS.attribute("exceptionTypes", std::move(Types));
+ } break;
+ case EST_MSAny:
+ JOS.attribute("exceptionSpec", "throw");
+ JOS.attribute("throwsAny", true);
+ break;
+ case EST_BasicNoexcept:
+ JOS.attribute("exceptionSpec", "noexcept");
+ break;
+ case EST_NoexceptTrue:
+ case EST_NoexceptFalse:
+ JOS.attribute("exceptionSpec", "noexcept");
+ JOS.attribute("conditionEvaluatesTo",
+ E.ExceptionSpec.Type == EST_NoexceptTrue);
+ //JOS.attributeWithCall("exceptionSpecExpr",
+ // [this, E]() { Visit(E.ExceptionSpec.NoexceptExpr); });
+ break;
+ case EST_NoThrow:
+ JOS.attribute("exceptionSpec", "nothrow");
+ break;
+ // FIXME: I cannot find a way to trigger these cases while dumping the AST. I
+ // suspect you can only run into them when executing an AST dump from within
+ // the debugger, which is not a use case we worry about for the JSON dumping
+ // feature.
+ case EST_DependentNoexcept:
+ case EST_Unevaluated:
+ case EST_Uninstantiated:
+ case EST_Unparsed:
+ case EST_None: break;
+ }
+ VisitFunctionType(T);
+}
+
+void JSONNodeDumper::VisitRValueReferenceType(const ReferenceType *RT) {
+ attributeOnlyIfTrue("spelledAsLValue", RT->isSpelledAsLValue());
+}
+
+void JSONNodeDumper::VisitArrayType(const ArrayType *AT) {
+ switch (AT->getSizeModifier()) {
+ case ArrayType::Star:
+ JOS.attribute("sizeModifier", "*");
+ break;
+ case ArrayType::Static:
+ JOS.attribute("sizeModifier", "static");
+ break;
+ case ArrayType::Normal:
+ break;
+ }
+
+ std::string Str = AT->getIndexTypeQualifiers().getAsString();
+ if (!Str.empty())
+ JOS.attribute("indexTypeQualifiers", Str);
+}
+
+void JSONNodeDumper::VisitConstantArrayType(const ConstantArrayType *CAT) {
+ // FIXME: this should use ZExt instead of SExt, but JSON doesn't allow a
+ // narrowing conversion to int64_t so it cannot be expressed.
+ JOS.attribute("size", CAT->getSize().getSExtValue());
+ VisitArrayType(CAT);
+}
+
+void JSONNodeDumper::VisitDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *VT) {
+ JOS.attributeObject(
+ "attrLoc", [VT, this] { writeSourceLocation(VT->getAttributeLoc()); });
+}
+
+void JSONNodeDumper::VisitVectorType(const VectorType *VT) {
+ JOS.attribute("numElements", VT->getNumElements());
+ switch (VT->getVectorKind()) {
+ case VectorType::GenericVector:
+ break;
+ case VectorType::AltiVecVector:
+ JOS.attribute("vectorKind", "altivec");
+ break;
+ case VectorType::AltiVecPixel:
+ JOS.attribute("vectorKind", "altivec pixel");
+ break;
+ case VectorType::AltiVecBool:
+ JOS.attribute("vectorKind", "altivec bool");
+ break;
+ case VectorType::NeonVector:
+ JOS.attribute("vectorKind", "neon");
+ break;
+ case VectorType::NeonPolyVector:
+ JOS.attribute("vectorKind", "neon poly");
+ break;
+ }
+}
+
+void JSONNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *UUT) {
+ JOS.attribute("decl", createBareDeclRef(UUT->getDecl()));
+}
+
+void JSONNodeDumper::VisitUnaryTransformType(const UnaryTransformType *UTT) {
+ switch (UTT->getUTTKind()) {
+ case UnaryTransformType::EnumUnderlyingType:
+ JOS.attribute("transformKind", "underlying_type");
+ break;
+ }
+}
+
+void JSONNodeDumper::VisitTagType(const TagType *TT) {
+ JOS.attribute("decl", createBareDeclRef(TT->getDecl()));
+}
+
+void JSONNodeDumper::VisitTemplateTypeParmType(
+ const TemplateTypeParmType *TTPT) {
+ JOS.attribute("depth", TTPT->getDepth());
+ JOS.attribute("index", TTPT->getIndex());
+ attributeOnlyIfTrue("isPack", TTPT->isParameterPack());
+ JOS.attribute("decl", createBareDeclRef(TTPT->getDecl()));
+}
+
+void JSONNodeDumper::VisitAutoType(const AutoType *AT) {
+ JOS.attribute("undeduced", !AT->isDeduced());
+ switch (AT->getKeyword()) {
+ case AutoTypeKeyword::Auto:
+ JOS.attribute("typeKeyword", "auto");
+ break;
+ case AutoTypeKeyword::DecltypeAuto:
+ JOS.attribute("typeKeyword", "decltype(auto)");
+ break;
+ case AutoTypeKeyword::GNUAutoType:
+ JOS.attribute("typeKeyword", "__auto_type");
+ break;
+ }
+}
+
+void JSONNodeDumper::VisitTemplateSpecializationType(
+ const TemplateSpecializationType *TST) {
+ attributeOnlyIfTrue("isAlias", TST->isTypeAlias());
+
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ TST->getTemplateName().print(OS, PrintPolicy);
+ JOS.attribute("templateName", OS.str());
+}
+
+void JSONNodeDumper::VisitInjectedClassNameType(
+ const InjectedClassNameType *ICNT) {
+ JOS.attribute("decl", createBareDeclRef(ICNT->getDecl()));
+}
+
+void JSONNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *OIT) {
+ JOS.attribute("decl", createBareDeclRef(OIT->getDecl()));
+}
+
+void JSONNodeDumper::VisitPackExpansionType(const PackExpansionType *PET) {
+ if (llvm::Optional<unsigned> N = PET->getNumExpansions())
+ JOS.attribute("numExpansions", *N);
+}
+
+void JSONNodeDumper::VisitElaboratedType(const ElaboratedType *ET) {
+ if (const NestedNameSpecifier *NNS = ET->getQualifier()) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ NNS->print(OS, PrintPolicy, /*ResolveTemplateArgs*/ true);
+ JOS.attribute("qualifier", OS.str());
+ }
+ if (const TagDecl *TD = ET->getOwnedTagDecl())
+ JOS.attribute("ownedTagDecl", createBareDeclRef(TD));
+}
+
+void JSONNodeDumper::VisitMacroQualifiedType(const MacroQualifiedType *MQT) {
+ JOS.attribute("macroName", MQT->getMacroIdentifier()->getName());
+}
+
+void JSONNodeDumper::VisitMemberPointerType(const MemberPointerType *MPT) {
+ attributeOnlyIfTrue("isData", MPT->isMemberDataPointer());
+ attributeOnlyIfTrue("isFunction", MPT->isMemberFunctionPointer());
+}
+
+void JSONNodeDumper::VisitNamedDecl(const NamedDecl *ND) {
+ if (ND && ND->getDeclName())
+ JOS.attribute("name", ND->getNameAsString());
+}
+
+void JSONNodeDumper::VisitTypedefDecl(const TypedefDecl *TD) {
+ VisitNamedDecl(TD);
+ JOS.attribute("type", createQualType(TD->getUnderlyingType()));
+}
+
+void JSONNodeDumper::VisitTypeAliasDecl(const TypeAliasDecl *TAD) {
+ VisitNamedDecl(TAD);
+ JOS.attribute("type", createQualType(TAD->getUnderlyingType()));
+}
+
+void JSONNodeDumper::VisitNamespaceDecl(const NamespaceDecl *ND) {
+ VisitNamedDecl(ND);
+ attributeOnlyIfTrue("isInline", ND->isInline());
+ if (!ND->isOriginalNamespace())
+ JOS.attribute("originalNamespace",
+ createBareDeclRef(ND->getOriginalNamespace()));
+}
+
+void JSONNodeDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD) {
+ JOS.attribute("nominatedNamespace",
+ createBareDeclRef(UDD->getNominatedNamespace()));
+}
+
+void JSONNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD) {
+ VisitNamedDecl(NAD);
+ JOS.attribute("aliasedNamespace",
+ createBareDeclRef(NAD->getAliasedNamespace()));
+}
+
+void JSONNodeDumper::VisitUsingDecl(const UsingDecl *UD) {
+ std::string Name;
+ if (const NestedNameSpecifier *NNS = UD->getQualifier()) {
+ llvm::raw_string_ostream SOS(Name);
+ NNS->print(SOS, UD->getASTContext().getPrintingPolicy());
+ }
+ Name += UD->getNameAsString();
+ JOS.attribute("name", Name);
+}
+
+void JSONNodeDumper::VisitUsingShadowDecl(const UsingShadowDecl *USD) {
+ JOS.attribute("target", createBareDeclRef(USD->getTargetDecl()));
+}
+
+void JSONNodeDumper::VisitVarDecl(const VarDecl *VD) {
+ VisitNamedDecl(VD);
+ JOS.attribute("type", createQualType(VD->getType()));
+
+ StorageClass SC = VD->getStorageClass();
+ if (SC != SC_None)
+ JOS.attribute("storageClass", VarDecl::getStorageClassSpecifierString(SC));
+ switch (VD->getTLSKind()) {
+ case VarDecl::TLS_Dynamic: JOS.attribute("tls", "dynamic"); break;
+ case VarDecl::TLS_Static: JOS.attribute("tls", "static"); break;
+ case VarDecl::TLS_None: break;
+ }
+ attributeOnlyIfTrue("nrvo", VD->isNRVOVariable());
+ attributeOnlyIfTrue("inline", VD->isInline());
+ attributeOnlyIfTrue("constexpr", VD->isConstexpr());
+ attributeOnlyIfTrue("modulePrivate", VD->isModulePrivate());
+ if (VD->hasInit()) {
+ switch (VD->getInitStyle()) {
+ case VarDecl::CInit: JOS.attribute("init", "c"); break;
+ case VarDecl::CallInit: JOS.attribute("init", "call"); break;
+ case VarDecl::ListInit: JOS.attribute("init", "list"); break;
+ }
+ }
+ attributeOnlyIfTrue("isParameterPack", VD->isParameterPack());
+}
+
+void JSONNodeDumper::VisitFieldDecl(const FieldDecl *FD) {
+ VisitNamedDecl(FD);
+ JOS.attribute("type", createQualType(FD->getType()));
+ attributeOnlyIfTrue("mutable", FD->isMutable());
+ attributeOnlyIfTrue("modulePrivate", FD->isModulePrivate());
+ attributeOnlyIfTrue("isBitfield", FD->isBitField());
+ attributeOnlyIfTrue("hasInClassInitializer", FD->hasInClassInitializer());
+}
+
+void JSONNodeDumper::VisitFunctionDecl(const FunctionDecl *FD) {
+ VisitNamedDecl(FD);
+ JOS.attribute("type", createQualType(FD->getType()));
+ StorageClass SC = FD->getStorageClass();
+ if (SC != SC_None)
+ JOS.attribute("storageClass", VarDecl::getStorageClassSpecifierString(SC));
+ attributeOnlyIfTrue("inline", FD->isInlineSpecified());
+ attributeOnlyIfTrue("virtual", FD->isVirtualAsWritten());
+ attributeOnlyIfTrue("pure", FD->isPure());
+ attributeOnlyIfTrue("explicitlyDeleted", FD->isDeletedAsWritten());
+ attributeOnlyIfTrue("constexpr", FD->isConstexpr());
+ attributeOnlyIfTrue("variadic", FD->isVariadic());
+
+ if (FD->isDefaulted())
+ JOS.attribute("explicitlyDefaulted",
+ FD->isDeleted() ? "deleted" : "default");
+}
+
+void JSONNodeDumper::VisitEnumDecl(const EnumDecl *ED) {
+ VisitNamedDecl(ED);
+ if (ED->isFixed())
+ JOS.attribute("fixedUnderlyingType", createQualType(ED->getIntegerType()));
+ if (ED->isScoped())
+ JOS.attribute("scopedEnumTag",
+ ED->isScopedUsingClassTag() ? "class" : "struct");
+}
+void JSONNodeDumper::VisitEnumConstantDecl(const EnumConstantDecl *ECD) {
+ VisitNamedDecl(ECD);
+ JOS.attribute("type", createQualType(ECD->getType()));
+}
+
+void JSONNodeDumper::VisitRecordDecl(const RecordDecl *RD) {
+ VisitNamedDecl(RD);
+ JOS.attribute("tagUsed", RD->getKindName());
+ attributeOnlyIfTrue("completeDefinition", RD->isCompleteDefinition());
+}
+void JSONNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *RD) {
+ VisitRecordDecl(RD);
+
+ // All other information requires a complete definition.
+ if (!RD->isCompleteDefinition())
+ return;
+
+ JOS.attribute("definitionData", createCXXRecordDefinitionData(RD));
+ if (RD->getNumBases()) {
+ JOS.attributeArray("bases", [this, RD] {
+ for (const auto &Spec : RD->bases())
+ JOS.value(createCXXBaseSpecifier(Spec));
+ });
+ }
+}
+
+void JSONNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("tagUsed", D->wasDeclaredWithTypename() ? "typename" : "class");
+ JOS.attribute("depth", D->getDepth());
+ JOS.attribute("index", D->getIndex());
+ attributeOnlyIfTrue("isParameterPack", D->isParameterPack());
+
+ if (D->hasDefaultArgument())
+ JOS.attributeObject("defaultArg", [=] {
+ Visit(D->getDefaultArgument(), SourceRange(),
+ D->getDefaultArgStorage().getInheritedFrom(),
+ D->defaultArgumentWasInherited() ? "inherited from" : "previous");
+ });
+}
+
+void JSONNodeDumper::VisitNonTypeTemplateParmDecl(
+ const NonTypeTemplateParmDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("type", createQualType(D->getType()));
+ JOS.attribute("depth", D->getDepth());
+ JOS.attribute("index", D->getIndex());
+ attributeOnlyIfTrue("isParameterPack", D->isParameterPack());
+
+ if (D->hasDefaultArgument())
+ JOS.attributeObject("defaultArg", [=] {
+ Visit(D->getDefaultArgument(), SourceRange(),
+ D->getDefaultArgStorage().getInheritedFrom(),
+ D->defaultArgumentWasInherited() ? "inherited from" : "previous");
+ });
+}
+
+void JSONNodeDumper::VisitTemplateTemplateParmDecl(
+ const TemplateTemplateParmDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("depth", D->getDepth());
+ JOS.attribute("index", D->getIndex());
+ attributeOnlyIfTrue("isParameterPack", D->isParameterPack());
+
+ if (D->hasDefaultArgument())
+ JOS.attributeObject("defaultArg", [=] {
+ Visit(D->getDefaultArgument().getArgument(),
+ D->getDefaultArgStorage().getInheritedFrom()->getSourceRange(),
+ D->getDefaultArgStorage().getInheritedFrom(),
+ D->defaultArgumentWasInherited() ? "inherited from" : "previous");
+ });
+}
+
+void JSONNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *LSD) {
+ StringRef Lang;
+ switch (LSD->getLanguage()) {
+ case LinkageSpecDecl::lang_c: Lang = "C"; break;
+ case LinkageSpecDecl::lang_cxx: Lang = "C++"; break;
+ }
+ JOS.attribute("language", Lang);
+ attributeOnlyIfTrue("hasBraces", LSD->hasBraces());
+}
+
+void JSONNodeDumper::VisitAccessSpecDecl(const AccessSpecDecl *ASD) {
+ JOS.attribute("access", createAccessSpecifier(ASD->getAccess()));
+}
+
+void JSONNodeDumper::VisitFriendDecl(const FriendDecl *FD) {
+ if (const TypeSourceInfo *T = FD->getFriendType())
+ JOS.attribute("type", createQualType(T->getType()));
+}
+
+void JSONNodeDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("type", createQualType(D->getType()));
+ attributeOnlyIfTrue("synthesized", D->getSynthesize());
+ switch (D->getAccessControl()) {
+ case ObjCIvarDecl::None: JOS.attribute("access", "none"); break;
+ case ObjCIvarDecl::Private: JOS.attribute("access", "private"); break;
+ case ObjCIvarDecl::Protected: JOS.attribute("access", "protected"); break;
+ case ObjCIvarDecl::Public: JOS.attribute("access", "public"); break;
+ case ObjCIvarDecl::Package: JOS.attribute("access", "package"); break;
+ }
+}
+
+void JSONNodeDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("returnType", createQualType(D->getReturnType()));
+ JOS.attribute("instance", D->isInstanceMethod());
+ attributeOnlyIfTrue("variadic", D->isVariadic());
+}
+
+void JSONNodeDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("type", createQualType(D->getUnderlyingType()));
+ attributeOnlyIfTrue("bounded", D->hasExplicitBound());
+ switch (D->getVariance()) {
+ case ObjCTypeParamVariance::Invariant:
+ break;
+ case ObjCTypeParamVariance::Covariant:
+ JOS.attribute("variance", "covariant");
+ break;
+ case ObjCTypeParamVariance::Contravariant:
+ JOS.attribute("variance", "contravariant");
+ break;
+ }
+}
+
+void JSONNodeDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("interface", createBareDeclRef(D->getClassInterface()));
+ JOS.attribute("implementation", createBareDeclRef(D->getImplementation()));
+
+ llvm::json::Array Protocols;
+ for (const auto* P : D->protocols())
+ Protocols.push_back(createBareDeclRef(P));
+ if (!Protocols.empty())
+ JOS.attribute("protocols", std::move(Protocols));
+}
+
+void JSONNodeDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("interface", createBareDeclRef(D->getClassInterface()));
+ JOS.attribute("categoryDecl", createBareDeclRef(D->getCategoryDecl()));
+}
+
+void JSONNodeDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
+ VisitNamedDecl(D);
+
+ llvm::json::Array Protocols;
+ for (const auto *P : D->protocols())
+ Protocols.push_back(createBareDeclRef(P));
+ if (!Protocols.empty())
+ JOS.attribute("protocols", std::move(Protocols));
+}
+
+void JSONNodeDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("super", createBareDeclRef(D->getSuperClass()));
+ JOS.attribute("implementation", createBareDeclRef(D->getImplementation()));
+
+ llvm::json::Array Protocols;
+ for (const auto* P : D->protocols())
+ Protocols.push_back(createBareDeclRef(P));
+ if (!Protocols.empty())
+ JOS.attribute("protocols", std::move(Protocols));
+}
+
+void JSONNodeDumper::VisitObjCImplementationDecl(
+ const ObjCImplementationDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("super", createBareDeclRef(D->getSuperClass()));
+ JOS.attribute("interface", createBareDeclRef(D->getClassInterface()));
+}
+
+void JSONNodeDumper::VisitObjCCompatibleAliasDecl(
+ const ObjCCompatibleAliasDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("interface", createBareDeclRef(D->getClassInterface()));
+}
+
+void JSONNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("type", createQualType(D->getType()));
+
+ switch (D->getPropertyImplementation()) {
+ case ObjCPropertyDecl::None: break;
+ case ObjCPropertyDecl::Required: JOS.attribute("control", "required"); break;
+ case ObjCPropertyDecl::Optional: JOS.attribute("control", "optional"); break;
+ }
+
+ ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes();
+ if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) {
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_getter)
+ JOS.attribute("getter", createBareDeclRef(D->getGetterMethodDecl()));
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_setter)
+ JOS.attribute("setter", createBareDeclRef(D->getSetterMethodDecl()));
+ attributeOnlyIfTrue("readonly", Attrs & ObjCPropertyDecl::OBJC_PR_readonly);
+ attributeOnlyIfTrue("assign", Attrs & ObjCPropertyDecl::OBJC_PR_assign);
+ attributeOnlyIfTrue("readwrite",
+ Attrs & ObjCPropertyDecl::OBJC_PR_readwrite);
+ attributeOnlyIfTrue("retain", Attrs & ObjCPropertyDecl::OBJC_PR_retain);
+ attributeOnlyIfTrue("copy", Attrs & ObjCPropertyDecl::OBJC_PR_copy);
+ attributeOnlyIfTrue("nonatomic",
+ Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic);
+ attributeOnlyIfTrue("atomic", Attrs & ObjCPropertyDecl::OBJC_PR_atomic);
+ attributeOnlyIfTrue("weak", Attrs & ObjCPropertyDecl::OBJC_PR_weak);
+ attributeOnlyIfTrue("strong", Attrs & ObjCPropertyDecl::OBJC_PR_strong);
+ attributeOnlyIfTrue("unsafe_unretained",
+ Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+ attributeOnlyIfTrue("class", Attrs & ObjCPropertyDecl::OBJC_PR_class);
+ attributeOnlyIfTrue("nullability",
+ Attrs & ObjCPropertyDecl::OBJC_PR_nullability);
+ attributeOnlyIfTrue("null_resettable",
+ Attrs & ObjCPropertyDecl::OBJC_PR_null_resettable);
+ }
+}
+
+void JSONNodeDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
+ VisitNamedDecl(D->getPropertyDecl());
+ JOS.attribute("implKind", D->getPropertyImplementation() ==
+ ObjCPropertyImplDecl::Synthesize
+ ? "synthesize"
+ : "dynamic");
+ JOS.attribute("propertyDecl", createBareDeclRef(D->getPropertyDecl()));
+ JOS.attribute("ivarDecl", createBareDeclRef(D->getPropertyIvarDecl()));
+}
+
+void JSONNodeDumper::VisitBlockDecl(const BlockDecl *D) {
+ attributeOnlyIfTrue("variadic", D->isVariadic());
+ attributeOnlyIfTrue("capturesThis", D->capturesCXXThis());
+}
+
+void JSONNodeDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *OEE) {
+ JOS.attribute("encodedType", createQualType(OEE->getEncodedType()));
+}
+
+void JSONNodeDumper::VisitObjCMessageExpr(const ObjCMessageExpr *OME) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+
+ OME->getSelector().print(OS);
+ JOS.attribute("selector", OS.str());
+
+ switch (OME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ JOS.attribute("receiverKind", "instance");
+ break;
+ case ObjCMessageExpr::Class:
+ JOS.attribute("receiverKind", "class");
+ JOS.attribute("classType", createQualType(OME->getClassReceiver()));
+ break;
+ case ObjCMessageExpr::SuperInstance:
+ JOS.attribute("receiverKind", "super (instance)");
+ JOS.attribute("superType", createQualType(OME->getSuperType()));
+ break;
+ case ObjCMessageExpr::SuperClass:
+ JOS.attribute("receiverKind", "super (class)");
+ JOS.attribute("superType", createQualType(OME->getSuperType()));
+ break;
+ }
+
+ QualType CallReturnTy = OME->getCallReturnType(Ctx);
+ if (OME->getType() != CallReturnTy)
+ JOS.attribute("callReturnType", createQualType(CallReturnTy));
+}
+
+void JSONNodeDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *OBE) {
+ if (const ObjCMethodDecl *MD = OBE->getBoxingMethod()) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+
+ MD->getSelector().print(OS);
+ JOS.attribute("selector", OS.str());
+ }
+}
+
+void JSONNodeDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *OSE) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+
+ OSE->getSelector().print(OS);
+ JOS.attribute("selector", OS.str());
+}
+
+void JSONNodeDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *OPE) {
+ JOS.attribute("protocol", createBareDeclRef(OPE->getProtocol()));
+}
+
+void JSONNodeDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *OPRE) {
+ if (OPRE->isImplicitProperty()) {
+ JOS.attribute("propertyKind", "implicit");
+ if (const ObjCMethodDecl *MD = OPRE->getImplicitPropertyGetter())
+ JOS.attribute("getter", createBareDeclRef(MD));
+ if (const ObjCMethodDecl *MD = OPRE->getImplicitPropertySetter())
+ JOS.attribute("setter", createBareDeclRef(MD));
+ } else {
+ JOS.attribute("propertyKind", "explicit");
+ JOS.attribute("property", createBareDeclRef(OPRE->getExplicitProperty()));
+ }
+
+ attributeOnlyIfTrue("isSuperReceiver", OPRE->isSuperReceiver());
+ attributeOnlyIfTrue("isMessagingGetter", OPRE->isMessagingGetter());
+ attributeOnlyIfTrue("isMessagingSetter", OPRE->isMessagingSetter());
+}
+
+void JSONNodeDumper::VisitObjCSubscriptRefExpr(
+ const ObjCSubscriptRefExpr *OSRE) {
+ JOS.attribute("subscriptKind",
+ OSRE->isArraySubscriptRefExpr() ? "array" : "dictionary");
+
+ if (const ObjCMethodDecl *MD = OSRE->getAtIndexMethodDecl())
+ JOS.attribute("getter", createBareDeclRef(MD));
+ if (const ObjCMethodDecl *MD = OSRE->setAtIndexMethodDecl())
+ JOS.attribute("setter", createBareDeclRef(MD));
+}
+
+void JSONNodeDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *OIRE) {
+ JOS.attribute("decl", createBareDeclRef(OIRE->getDecl()));
+ attributeOnlyIfTrue("isFreeIvar", OIRE->isFreeIvar());
+ JOS.attribute("isArrow", OIRE->isArrow());
+}
+
+void JSONNodeDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *OBLE) {
+ JOS.attribute("value", OBLE->getValue() ? "__objc_yes" : "__objc_no");
+}
+
+void JSONNodeDumper::VisitDeclRefExpr(const DeclRefExpr *DRE) {
+ JOS.attribute("referencedDecl", createBareDeclRef(DRE->getDecl()));
+ if (DRE->getDecl() != DRE->getFoundDecl())
+ JOS.attribute("foundReferencedDecl",
+ createBareDeclRef(DRE->getFoundDecl()));
+ switch (DRE->isNonOdrUse()) {
+ case NOUR_None: break;
+ case NOUR_Unevaluated: JOS.attribute("nonOdrUseReason", "unevaluated"); break;
+ case NOUR_Constant: JOS.attribute("nonOdrUseReason", "constant"); break;
+ case NOUR_Discarded: JOS.attribute("nonOdrUseReason", "discarded"); break;
+ }
+}
+
+void JSONNodeDumper::VisitPredefinedExpr(const PredefinedExpr *PE) {
+ JOS.attribute("name", PredefinedExpr::getIdentKindName(PE->getIdentKind()));
+}
+
+void JSONNodeDumper::VisitUnaryOperator(const UnaryOperator *UO) {
+ JOS.attribute("isPostfix", UO->isPostfix());
+ JOS.attribute("opcode", UnaryOperator::getOpcodeStr(UO->getOpcode()));
+ if (!UO->canOverflow())
+ JOS.attribute("canOverflow", false);
+}
+
+void JSONNodeDumper::VisitBinaryOperator(const BinaryOperator *BO) {
+ JOS.attribute("opcode", BinaryOperator::getOpcodeStr(BO->getOpcode()));
+}
+
+void JSONNodeDumper::VisitCompoundAssignOperator(
+ const CompoundAssignOperator *CAO) {
+ VisitBinaryOperator(CAO);
+ JOS.attribute("computeLHSType", createQualType(CAO->getComputationLHSType()));
+ JOS.attribute("computeResultType",
+ createQualType(CAO->getComputationResultType()));
+}
+
+void JSONNodeDumper::VisitMemberExpr(const MemberExpr *ME) {
+ // Note, we always write this Boolean field because the information it conveys
+ // is critical to understanding the AST node.
+ ValueDecl *VD = ME->getMemberDecl();
+ JOS.attribute("name", VD && VD->getDeclName() ? VD->getNameAsString() : "");
+ JOS.attribute("isArrow", ME->isArrow());
+ JOS.attribute("referencedMemberDecl", createPointerRepresentation(VD));
+ switch (ME->isNonOdrUse()) {
+ case NOUR_None: break;
+ case NOUR_Unevaluated: JOS.attribute("nonOdrUseReason", "unevaluated"); break;
+ case NOUR_Constant: JOS.attribute("nonOdrUseReason", "constant"); break;
+ case NOUR_Discarded: JOS.attribute("nonOdrUseReason", "discarded"); break;
+ }
+}
+
+void JSONNodeDumper::VisitCXXNewExpr(const CXXNewExpr *NE) {
+ attributeOnlyIfTrue("isGlobal", NE->isGlobalNew());
+ attributeOnlyIfTrue("isArray", NE->isArray());
+ attributeOnlyIfTrue("isPlacement", NE->getNumPlacementArgs() != 0);
+ switch (NE->getInitializationStyle()) {
+ case CXXNewExpr::NoInit: break;
+ case CXXNewExpr::CallInit: JOS.attribute("initStyle", "call"); break;
+ case CXXNewExpr::ListInit: JOS.attribute("initStyle", "list"); break;
+ }
+ if (const FunctionDecl *FD = NE->getOperatorNew())
+ JOS.attribute("operatorNewDecl", createBareDeclRef(FD));
+ if (const FunctionDecl *FD = NE->getOperatorDelete())
+ JOS.attribute("operatorDeleteDecl", createBareDeclRef(FD));
+}
+void JSONNodeDumper::VisitCXXDeleteExpr(const CXXDeleteExpr *DE) {
+ attributeOnlyIfTrue("isGlobal", DE->isGlobalDelete());
+ attributeOnlyIfTrue("isArray", DE->isArrayForm());
+ attributeOnlyIfTrue("isArrayAsWritten", DE->isArrayFormAsWritten());
+ if (const FunctionDecl *FD = DE->getOperatorDelete())
+ JOS.attribute("operatorDeleteDecl", createBareDeclRef(FD));
+}
+
+void JSONNodeDumper::VisitCXXThisExpr(const CXXThisExpr *TE) {
+ attributeOnlyIfTrue("implicit", TE->isImplicit());
+}
+
+void JSONNodeDumper::VisitCastExpr(const CastExpr *CE) {
+ JOS.attribute("castKind", CE->getCastKindName());
+ llvm::json::Array Path = createCastPath(CE);
+ if (!Path.empty())
+ JOS.attribute("path", std::move(Path));
+ // FIXME: This may not be useful information as it can be obtusely gleaned
+ // from the inner[] array.
+ if (const NamedDecl *ND = CE->getConversionFunction())
+ JOS.attribute("conversionFunc", createBareDeclRef(ND));
+}
+
+void JSONNodeDumper::VisitImplicitCastExpr(const ImplicitCastExpr *ICE) {
+ VisitCastExpr(ICE);
+ attributeOnlyIfTrue("isPartOfExplicitCast", ICE->isPartOfExplicitCast());
+}
+
+void JSONNodeDumper::VisitCallExpr(const CallExpr *CE) {
+ attributeOnlyIfTrue("adl", CE->usesADL());
+}
+
+void JSONNodeDumper::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr *TTE) {
+ switch (TTE->getKind()) {
+ case UETT_SizeOf: JOS.attribute("name", "sizeof"); break;
+ case UETT_AlignOf: JOS.attribute("name", "alignof"); break;
+ case UETT_VecStep: JOS.attribute("name", "vec_step"); break;
+ case UETT_PreferredAlignOf: JOS.attribute("name", "__alignof"); break;
+ case UETT_OpenMPRequiredSimdAlign:
+ JOS.attribute("name", "__builtin_omp_required_simd_align"); break;
+ }
+ if (TTE->isArgumentType())
+ JOS.attribute("argType", createQualType(TTE->getArgumentType()));
+}
+
+void JSONNodeDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *SOPE) {
+ VisitNamedDecl(SOPE->getPack());
+}
+
+void JSONNodeDumper::VisitUnresolvedLookupExpr(
+ const UnresolvedLookupExpr *ULE) {
+ JOS.attribute("usesADL", ULE->requiresADL());
+ JOS.attribute("name", ULE->getName().getAsString());
+
+ JOS.attributeArray("lookups", [this, ULE] {
+ for (const NamedDecl *D : ULE->decls())
+ JOS.value(createBareDeclRef(D));
+ });
+}
+
+void JSONNodeDumper::VisitAddrLabelExpr(const AddrLabelExpr *ALE) {
+ JOS.attribute("name", ALE->getLabel()->getName());
+ JOS.attribute("labelDeclId", createPointerRepresentation(ALE->getLabel()));
+}
+
+void JSONNodeDumper::VisitCXXTypeidExpr(const CXXTypeidExpr *CTE) {
+ if (CTE->isTypeOperand()) {
+ QualType Adjusted = CTE->getTypeOperand(Ctx);
+ QualType Unadjusted = CTE->getTypeOperandSourceInfo()->getType();
+ JOS.attribute("typeArg", createQualType(Unadjusted));
+ if (Adjusted != Unadjusted)
+ JOS.attribute("adjustedTypeArg", createQualType(Adjusted));
+ }
+}
+
+void JSONNodeDumper::VisitConstantExpr(const ConstantExpr *CE) {
+ if (CE->getResultAPValueKind() != APValue::None) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ CE->getAPValueResult().printPretty(OS, Ctx, CE->getType());
+ JOS.attribute("value", OS.str());
+ }
+}
+
+void JSONNodeDumper::VisitInitListExpr(const InitListExpr *ILE) {
+ if (const FieldDecl *FD = ILE->getInitializedFieldInUnion())
+ JOS.attribute("field", createBareDeclRef(FD));
+}
+
+void JSONNodeDumper::VisitGenericSelectionExpr(
+ const GenericSelectionExpr *GSE) {
+ attributeOnlyIfTrue("resultDependent", GSE->isResultDependent());
+}
+
+void JSONNodeDumper::VisitCXXUnresolvedConstructExpr(
+ const CXXUnresolvedConstructExpr *UCE) {
+ if (UCE->getType() != UCE->getTypeAsWritten())
+ JOS.attribute("typeAsWritten", createQualType(UCE->getTypeAsWritten()));
+ attributeOnlyIfTrue("list", UCE->isListInitialization());
+}
+
+void JSONNodeDumper::VisitCXXConstructExpr(const CXXConstructExpr *CE) {
+ CXXConstructorDecl *Ctor = CE->getConstructor();
+ JOS.attribute("ctorType", createQualType(Ctor->getType()));
+ attributeOnlyIfTrue("elidable", CE->isElidable());
+ attributeOnlyIfTrue("list", CE->isListInitialization());
+ attributeOnlyIfTrue("initializer_list", CE->isStdInitListInitialization());
+ attributeOnlyIfTrue("zeroing", CE->requiresZeroInitialization());
+ attributeOnlyIfTrue("hadMultipleCandidates", CE->hadMultipleCandidates());
+
+ switch (CE->getConstructionKind()) {
+ case CXXConstructExpr::CK_Complete:
+ JOS.attribute("constructionKind", "complete");
+ break;
+ case CXXConstructExpr::CK_Delegating:
+ JOS.attribute("constructionKind", "delegating");
+ break;
+ case CXXConstructExpr::CK_NonVirtualBase:
+ JOS.attribute("constructionKind", "non-virtual base");
+ break;
+ case CXXConstructExpr::CK_VirtualBase:
+ JOS.attribute("constructionKind", "virtual base");
+ break;
+ }
+}
+
+void JSONNodeDumper::VisitExprWithCleanups(const ExprWithCleanups *EWC) {
+ attributeOnlyIfTrue("cleanupsHaveSideEffects",
+ EWC->cleanupsHaveSideEffects());
+ if (EWC->getNumObjects()) {
+ JOS.attributeArray("cleanups", [this, EWC] {
+ for (const ExprWithCleanups::CleanupObject &CO : EWC->getObjects())
+ JOS.value(createBareDeclRef(CO));
+ });
+ }
+}
+
+void JSONNodeDumper::VisitCXXBindTemporaryExpr(
+ const CXXBindTemporaryExpr *BTE) {
+ const CXXTemporary *Temp = BTE->getTemporary();
+ JOS.attribute("temp", createPointerRepresentation(Temp));
+ if (const CXXDestructorDecl *Dtor = Temp->getDestructor())
+ JOS.attribute("dtor", createBareDeclRef(Dtor));
+}
+
+void JSONNodeDumper::VisitMaterializeTemporaryExpr(
+ const MaterializeTemporaryExpr *MTE) {
+ if (const ValueDecl *VD = MTE->getExtendingDecl())
+ JOS.attribute("extendingDecl", createBareDeclRef(VD));
+
+ switch (MTE->getStorageDuration()) {
+ case SD_Automatic:
+ JOS.attribute("storageDuration", "automatic");
+ break;
+ case SD_Dynamic:
+ JOS.attribute("storageDuration", "dynamic");
+ break;
+ case SD_FullExpression:
+ JOS.attribute("storageDuration", "full expression");
+ break;
+ case SD_Static:
+ JOS.attribute("storageDuration", "static");
+ break;
+ case SD_Thread:
+ JOS.attribute("storageDuration", "thread");
+ break;
+ }
+
+ attributeOnlyIfTrue("boundToLValueRef", MTE->isBoundToLvalueReference());
+}
+
+void JSONNodeDumper::VisitCXXDependentScopeMemberExpr(
+ const CXXDependentScopeMemberExpr *DSME) {
+ JOS.attribute("isArrow", DSME->isArrow());
+ JOS.attribute("member", DSME->getMember().getAsString());
+ attributeOnlyIfTrue("hasTemplateKeyword", DSME->hasTemplateKeyword());
+ attributeOnlyIfTrue("hasExplicitTemplateArgs",
+ DSME->hasExplicitTemplateArgs());
+
+ if (DSME->getNumTemplateArgs()) {
+ JOS.attributeArray("explicitTemplateArgs", [DSME, this] {
+ for (const TemplateArgumentLoc &TAL : DSME->template_arguments())
+ JOS.object(
+ [&TAL, this] { Visit(TAL.getArgument(), TAL.getSourceRange()); });
+ });
+ }
+}
+
+void JSONNodeDumper::VisitIntegerLiteral(const IntegerLiteral *IL) {
+ JOS.attribute("value",
+ IL->getValue().toString(
+ /*Radix=*/10, IL->getType()->isSignedIntegerType()));
+}
+void JSONNodeDumper::VisitCharacterLiteral(const CharacterLiteral *CL) {
+ // FIXME: This should probably print the character literal as a string,
+ // rather than as a numerical value. It would be nice if the behavior matched
+ // what we do to print a string literal; right now, it is impossible to tell
+ // the difference between 'a' and L'a' in C from the JSON output.
+ JOS.attribute("value", CL->getValue());
+}
+void JSONNodeDumper::VisitFixedPointLiteral(const FixedPointLiteral *FPL) {
+ JOS.attribute("value", FPL->getValueAsString(/*Radix=*/10));
+}
+void JSONNodeDumper::VisitFloatingLiteral(const FloatingLiteral *FL) {
+ llvm::SmallVector<char, 16> Buffer;
+ FL->getValue().toString(Buffer);
+ JOS.attribute("value", Buffer);
+}
+void JSONNodeDumper::VisitStringLiteral(const StringLiteral *SL) {
+ std::string Buffer;
+ llvm::raw_string_ostream SS(Buffer);
+ SL->outputString(SS);
+ JOS.attribute("value", SS.str());
+}
+void JSONNodeDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *BLE) {
+ JOS.attribute("value", BLE->getValue());
+}
+
+void JSONNodeDumper::VisitIfStmt(const IfStmt *IS) {
+ attributeOnlyIfTrue("hasInit", IS->hasInitStorage());
+ attributeOnlyIfTrue("hasVar", IS->hasVarStorage());
+ attributeOnlyIfTrue("hasElse", IS->hasElseStorage());
+ attributeOnlyIfTrue("isConstexpr", IS->isConstexpr());
+}
+
+void JSONNodeDumper::VisitSwitchStmt(const SwitchStmt *SS) {
+ attributeOnlyIfTrue("hasInit", SS->hasInitStorage());
+ attributeOnlyIfTrue("hasVar", SS->hasVarStorage());
+}
+void JSONNodeDumper::VisitCaseStmt(const CaseStmt *CS) {
+ attributeOnlyIfTrue("isGNURange", CS->caseStmtIsGNURange());
+}
+
+void JSONNodeDumper::VisitLabelStmt(const LabelStmt *LS) {
+ JOS.attribute("name", LS->getName());
+ JOS.attribute("declId", createPointerRepresentation(LS->getDecl()));
+}
+void JSONNodeDumper::VisitGotoStmt(const GotoStmt *GS) {
+ JOS.attribute("targetLabelDeclId",
+ createPointerRepresentation(GS->getLabel()));
+}
+
+void JSONNodeDumper::VisitWhileStmt(const WhileStmt *WS) {
+ attributeOnlyIfTrue("hasVar", WS->hasVarStorage());
+}
+
+void JSONNodeDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt* OACS) {
+ // FIXME: it would be nice for the ASTNodeTraverser would handle the catch
+ // parameter the same way for C++ and ObjC rather. In this case, C++ gets a
+ // null child node and ObjC gets no child node.
+ attributeOnlyIfTrue("isCatchAll", OACS->getCatchParamDecl() == nullptr);
+}
+
+void JSONNodeDumper::VisitNullTemplateArgument(const TemplateArgument &TA) {
+ JOS.attribute("isNull", true);
+}
+void JSONNodeDumper::VisitTypeTemplateArgument(const TemplateArgument &TA) {
+ JOS.attribute("type", createQualType(TA.getAsType()));
+}
+void JSONNodeDumper::VisitDeclarationTemplateArgument(
+ const TemplateArgument &TA) {
+ JOS.attribute("decl", createBareDeclRef(TA.getAsDecl()));
+}
+void JSONNodeDumper::VisitNullPtrTemplateArgument(const TemplateArgument &TA) {
+ JOS.attribute("isNullptr", true);
+}
+void JSONNodeDumper::VisitIntegralTemplateArgument(const TemplateArgument &TA) {
+ JOS.attribute("value", TA.getAsIntegral().getSExtValue());
+}
+void JSONNodeDumper::VisitTemplateTemplateArgument(const TemplateArgument &TA) {
+ // FIXME: cannot just call dump() on the argument, as that doesn't specify
+ // the output format.
+}
+void JSONNodeDumper::VisitTemplateExpansionTemplateArgument(
+ const TemplateArgument &TA) {
+ // FIXME: cannot just call dump() on the argument, as that doesn't specify
+ // the output format.
+}
+void JSONNodeDumper::VisitExpressionTemplateArgument(
+ const TemplateArgument &TA) {
+ JOS.attribute("isExpr", true);
+}
+void JSONNodeDumper::VisitPackTemplateArgument(const TemplateArgument &TA) {
+ JOS.attribute("isPack", true);
+}
+
+StringRef JSONNodeDumper::getCommentCommandName(unsigned CommandID) const {
+ if (Traits)
+ return Traits->getCommandInfo(CommandID)->Name;
+ if (const comments::CommandInfo *Info =
+ comments::CommandTraits::getBuiltinCommandInfo(CommandID))
+ return Info->Name;
+ return "<invalid>";
+}
+
+void JSONNodeDumper::visitTextComment(const comments::TextComment *C,
+ const comments::FullComment *) {
+ JOS.attribute("text", C->getText());
+}
+
+void JSONNodeDumper::visitInlineCommandComment(
+ const comments::InlineCommandComment *C, const comments::FullComment *) {
+ JOS.attribute("name", getCommentCommandName(C->getCommandID()));
+
+ switch (C->getRenderKind()) {
+ case comments::InlineCommandComment::RenderNormal:
+ JOS.attribute("renderKind", "normal");
+ break;
+ case comments::InlineCommandComment::RenderBold:
+ JOS.attribute("renderKind", "bold");
+ break;
+ case comments::InlineCommandComment::RenderEmphasized:
+ JOS.attribute("renderKind", "emphasized");
+ break;
+ case comments::InlineCommandComment::RenderMonospaced:
+ JOS.attribute("renderKind", "monospaced");
+ break;
+ }
+
+ llvm::json::Array Args;
+ for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
+ Args.push_back(C->getArgText(I));
+
+ if (!Args.empty())
+ JOS.attribute("args", std::move(Args));
+}
+
+void JSONNodeDumper::visitHTMLStartTagComment(
+ const comments::HTMLStartTagComment *C, const comments::FullComment *) {
+ JOS.attribute("name", C->getTagName());
+ attributeOnlyIfTrue("selfClosing", C->isSelfClosing());
+ attributeOnlyIfTrue("malformed", C->isMalformed());
+
+ llvm::json::Array Attrs;
+ for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I)
+ Attrs.push_back(
+ {{"name", C->getAttr(I).Name}, {"value", C->getAttr(I).Value}});
+
+ if (!Attrs.empty())
+ JOS.attribute("attrs", std::move(Attrs));
+}
+
+void JSONNodeDumper::visitHTMLEndTagComment(
+ const comments::HTMLEndTagComment *C, const comments::FullComment *) {
+ JOS.attribute("name", C->getTagName());
+}
+
+void JSONNodeDumper::visitBlockCommandComment(
+ const comments::BlockCommandComment *C, const comments::FullComment *) {
+ JOS.attribute("name", getCommentCommandName(C->getCommandID()));
+
+ llvm::json::Array Args;
+ for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
+ Args.push_back(C->getArgText(I));
+
+ if (!Args.empty())
+ JOS.attribute("args", std::move(Args));
+}
+
+void JSONNodeDumper::visitParamCommandComment(
+ const comments::ParamCommandComment *C, const comments::FullComment *FC) {
+ switch (C->getDirection()) {
+ case comments::ParamCommandComment::In:
+ JOS.attribute("direction", "in");
+ break;
+ case comments::ParamCommandComment::Out:
+ JOS.attribute("direction", "out");
+ break;
+ case comments::ParamCommandComment::InOut:
+ JOS.attribute("direction", "in,out");
+ break;
+ }
+ attributeOnlyIfTrue("explicit", C->isDirectionExplicit());
+
+ if (C->hasParamName())
+ JOS.attribute("param", C->isParamIndexValid() ? C->getParamName(FC)
+ : C->getParamNameAsWritten());
+
+ if (C->isParamIndexValid() && !C->isVarArgParam())
+ JOS.attribute("paramIdx", C->getParamIndex());
+}
+
+void JSONNodeDumper::visitTParamCommandComment(
+ const comments::TParamCommandComment *C, const comments::FullComment *FC) {
+ if (C->hasParamName())
+ JOS.attribute("param", C->isPositionValid() ? C->getParamName(FC)
+ : C->getParamNameAsWritten());
+ if (C->isPositionValid()) {
+ llvm::json::Array Positions;
+ for (unsigned I = 0, E = C->getDepth(); I < E; ++I)
+ Positions.push_back(C->getIndex(I));
+
+ if (!Positions.empty())
+ JOS.attribute("positions", std::move(Positions));
+ }
+}
+
+void JSONNodeDumper::visitVerbatimBlockComment(
+ const comments::VerbatimBlockComment *C, const comments::FullComment *) {
+ JOS.attribute("name", getCommentCommandName(C->getCommandID()));
+ JOS.attribute("closeName", C->getCloseName());
+}
+
+void JSONNodeDumper::visitVerbatimBlockLineComment(
+ const comments::VerbatimBlockLineComment *C,
+ const comments::FullComment *) {
+ JOS.attribute("text", C->getText());
+}
+
+void JSONNodeDumper::visitVerbatimLineComment(
+ const comments::VerbatimLineComment *C, const comments::FullComment *) {
+ JOS.attribute("text", C->getText());
+}
diff --git a/lib/AST/Linkage.h b/lib/AST/Linkage.h
index 8ad748bcc4a26..4e913540de86f 100644
--- a/lib/AST/Linkage.h
+++ b/lib/AST/Linkage.h
@@ -1,9 +1,8 @@
//===----- Linkage.h - Linkage calculation-related utilities ----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index bb29bffc1b8fb..625282368a4d1 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -1,9 +1,8 @@
//===--- Mangle.cpp - Mangle C++ Names --------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -18,10 +17,13 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Mangler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@@ -281,3 +283,205 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
mangleObjCMethodNameWithoutSize(MD, OS);
Out << OS.str().size() << OS.str();
}
+
+class ASTNameGenerator::Implementation {
+ std::unique_ptr<MangleContext> MC;
+ llvm::DataLayout DL;
+
+public:
+ explicit Implementation(ASTContext &Ctx)
+ : MC(Ctx.createMangleContext()), DL(Ctx.getTargetInfo().getDataLayout()) {
+ }
+
+ bool writeName(const Decl *D, raw_ostream &OS) {
+ // First apply frontend mangling.
+ SmallString<128> FrontendBuf;
+ llvm::raw_svector_ostream FrontendBufOS(FrontendBuf);
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isDependentContext())
+ return true;
+ if (writeFuncOrVarName(FD, FrontendBufOS))
+ return true;
+ } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+ if (writeFuncOrVarName(VD, FrontendBufOS))
+ return true;
+ } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ MC->mangleObjCMethodNameWithoutSize(MD, OS);
+ return false;
+ } else if (auto *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ writeObjCClassName(ID, FrontendBufOS);
+ } else {
+ return true;
+ }
+
+ // Now apply backend mangling.
+ llvm::Mangler::getNameWithPrefix(OS, FrontendBufOS.str(), DL);
+ return false;
+ }
+
+ std::string getName(const Decl *D) {
+ std::string Name;
+ {
+ llvm::raw_string_ostream OS(Name);
+ writeName(D, OS);
+ }
+ return Name;
+ }
+
+ enum ObjCKind {
+ ObjCClass,
+ ObjCMetaclass,
+ };
+
+ static StringRef getClassSymbolPrefix(ObjCKind Kind,
+ const ASTContext &Context) {
+ if (Context.getLangOpts().ObjCRuntime.isGNUFamily())
+ return Kind == ObjCMetaclass ? "_OBJC_METACLASS_" : "_OBJC_CLASS_";
+ return Kind == ObjCMetaclass ? "OBJC_METACLASS_$_" : "OBJC_CLASS_$_";
+ }
+
+ std::vector<std::string> getAllManglings(const ObjCContainerDecl *OCD) {
+ StringRef ClassName;
+ if (const auto *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
+ ClassName = OID->getObjCRuntimeNameAsString();
+ else if (const auto *OID = dyn_cast<ObjCImplementationDecl>(OCD))
+ ClassName = OID->getObjCRuntimeNameAsString();
+
+ if (ClassName.empty())
+ return {};
+
+ auto Mangle = [&](ObjCKind Kind, StringRef ClassName) -> std::string {
+ SmallString<40> Mangled;
+ auto Prefix = getClassSymbolPrefix(Kind, OCD->getASTContext());
+ llvm::Mangler::getNameWithPrefix(Mangled, Prefix + ClassName, DL);
+ return Mangled.str();
+ };
+
+ return {
+ Mangle(ObjCClass, ClassName),
+ Mangle(ObjCMetaclass, ClassName),
+ };
+ }
+
+ std::vector<std::string> getAllManglings(const Decl *D) {
+ if (const auto *OCD = dyn_cast<ObjCContainerDecl>(D))
+ return getAllManglings(OCD);
+
+ if (!(isa<CXXRecordDecl>(D) || isa<CXXMethodDecl>(D)))
+ return {};
+
+ const NamedDecl *ND = cast<NamedDecl>(D);
+
+ ASTContext &Ctx = ND->getASTContext();
+ std::unique_ptr<MangleContext> M(Ctx.createMangleContext());
+
+ std::vector<std::string> Manglings;
+
+ auto hasDefaultCXXMethodCC = [](ASTContext &C, const CXXMethodDecl *MD) {
+ auto DefaultCC = C.getDefaultCallingConvention(/*IsVariadic=*/false,
+ /*IsCXXMethod=*/true);
+ auto CC = MD->getType()->getAs<FunctionProtoType>()->getCallConv();
+ return CC == DefaultCC;
+ };
+
+ if (const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(ND)) {
+ Manglings.emplace_back(getMangledStructor(CD, Ctor_Base));
+
+ if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily())
+ if (!CD->getParent()->isAbstract())
+ Manglings.emplace_back(getMangledStructor(CD, Ctor_Complete));
+
+ if (Ctx.getTargetInfo().getCXXABI().isMicrosoft())
+ if (CD->hasAttr<DLLExportAttr>() && CD->isDefaultConstructor())
+ if (!(hasDefaultCXXMethodCC(Ctx, CD) && CD->getNumParams() == 0))
+ Manglings.emplace_back(getMangledStructor(CD, Ctor_DefaultClosure));
+ } else if (const auto *DD = dyn_cast_or_null<CXXDestructorDecl>(ND)) {
+ Manglings.emplace_back(getMangledStructor(DD, Dtor_Base));
+ if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily()) {
+ Manglings.emplace_back(getMangledStructor(DD, Dtor_Complete));
+ if (DD->isVirtual())
+ Manglings.emplace_back(getMangledStructor(DD, Dtor_Deleting));
+ }
+ } else if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(ND)) {
+ Manglings.emplace_back(getName(ND));
+ if (MD->isVirtual())
+ if (const auto *TIV = Ctx.getVTableContext()->getThunkInfo(MD))
+ for (const auto &T : *TIV)
+ Manglings.emplace_back(getMangledThunk(MD, T));
+ }
+
+ return Manglings;
+ }
+
+private:
+ bool writeFuncOrVarName(const NamedDecl *D, raw_ostream &OS) {
+ if (MC->shouldMangleDeclName(D)) {
+ if (const auto *CtorD = dyn_cast<CXXConstructorDecl>(D))
+ MC->mangleCXXCtor(CtorD, Ctor_Complete, OS);
+ else if (const auto *DtorD = dyn_cast<CXXDestructorDecl>(D))
+ MC->mangleCXXDtor(DtorD, Dtor_Complete, OS);
+ else
+ MC->mangleName(D, OS);
+ return false;
+ } else {
+ IdentifierInfo *II = D->getIdentifier();
+ if (!II)
+ return true;
+ OS << II->getName();
+ return false;
+ }
+ }
+
+ void writeObjCClassName(const ObjCInterfaceDecl *D, raw_ostream &OS) {
+ OS << getClassSymbolPrefix(ObjCClass, D->getASTContext());
+ OS << D->getObjCRuntimeNameAsString();
+ }
+
+ std::string getMangledStructor(const NamedDecl *ND, unsigned StructorType) {
+ std::string FrontendBuf;
+ llvm::raw_string_ostream FOS(FrontendBuf);
+
+ if (const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(ND))
+ MC->mangleCXXCtor(CD, static_cast<CXXCtorType>(StructorType), FOS);
+ else if (const auto *DD = dyn_cast_or_null<CXXDestructorDecl>(ND))
+ MC->mangleCXXDtor(DD, static_cast<CXXDtorType>(StructorType), FOS);
+
+ std::string BackendBuf;
+ llvm::raw_string_ostream BOS(BackendBuf);
+
+ llvm::Mangler::getNameWithPrefix(BOS, FOS.str(), DL);
+
+ return BOS.str();
+ }
+
+ std::string getMangledThunk(const CXXMethodDecl *MD, const ThunkInfo &T) {
+ std::string FrontendBuf;
+ llvm::raw_string_ostream FOS(FrontendBuf);
+
+ MC->mangleThunk(MD, T, FOS);
+
+ std::string BackendBuf;
+ llvm::raw_string_ostream BOS(BackendBuf);
+
+ llvm::Mangler::getNameWithPrefix(BOS, FOS.str(), DL);
+
+ return BOS.str();
+ }
+};
+
+ASTNameGenerator::ASTNameGenerator(ASTContext &Ctx)
+ : Impl(llvm::make_unique<Implementation>(Ctx)) {}
+
+ASTNameGenerator::~ASTNameGenerator() {}
+
+bool ASTNameGenerator::writeName(const Decl *D, raw_ostream &OS) {
+ return Impl->writeName(D, OS);
+}
+
+std::string ASTNameGenerator::getName(const Decl *D) {
+ return Impl->getName(D);
+}
+
+std::vector<std::string> ASTNameGenerator::getAllManglings(const Decl *D) {
+ return Impl->getAllManglings(D);
+}
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 3b417c1352850..4dc4156df9ca4 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -1,9 +1,8 @@
//===------- MicrosoftCXXABI.cpp - AST support for the Microsoft C++ ABI --===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 92e9679e49aa3..5e9358e24fc9d 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -1,9 +1,8 @@
//===--- MicrosoftMangle.cpp - Microsoft Visual C++ Name Mangling ---------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -32,6 +31,7 @@
#include "llvm/Support/xxhash.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/StringSaver.h"
using namespace clang;
@@ -97,7 +97,8 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) {
}
const DeclContext *DC = D->getDeclContext();
- if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC)) {
+ if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC) ||
+ isa<OMPDeclareMapperDecl>(DC)) {
return getEffectiveDeclContext(cast<Decl>(DC));
}
@@ -265,9 +266,15 @@ class MicrosoftCXXNameMangler {
BackRefVec NameBackReferences;
typedef llvm::DenseMap<const void *, unsigned> ArgBackRefMap;
- ArgBackRefMap TypeBackReferences;
+ ArgBackRefMap FunArgBackReferences;
+ ArgBackRefMap TemplateArgBackReferences;
+
+ typedef llvm::DenseMap<const void *, StringRef> TemplateArgStringMap;
+ TemplateArgStringMap TemplateArgStrings;
+ llvm::StringSaver TemplateArgStringStorage;
+ llvm::BumpPtrAllocator TemplateArgStringStorageAlloc;
- typedef std::set<int> PassObjectSizeArgsSet;
+ typedef std::set<std::pair<int, bool>> PassObjectSizeArgsSet;
PassObjectSizeArgsSet PassObjectSizeArgs;
ASTContext &getASTContext() const { return Context.getASTContext(); }
@@ -281,18 +288,21 @@ public:
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_)
: Context(C), Out(Out_), Structor(nullptr), StructorType(-1),
+ TemplateArgStringStorage(TemplateArgStringStorageAlloc),
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
64) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
const CXXConstructorDecl *D, CXXCtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
+ TemplateArgStringStorage(TemplateArgStringStorageAlloc),
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
64) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
+ TemplateArgStringStorage(TemplateArgStringStorageAlloc),
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
64) {}
@@ -343,7 +353,7 @@ private:
const TemplateArgumentList &TemplateArgs);
void mangleObjCMethodName(const ObjCMethodDecl *MD);
- void mangleArgumentType(QualType T, SourceRange Range);
+ void mangleFunctionArgumentType(QualType T, SourceRange Range);
void manglePassObjectSizeArg(const PassObjectSizeAttr *POSA);
bool isArtificialTagType(QualType T) const;
@@ -793,7 +803,7 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// the X<Y> part is aliased. However, if you need to mangle
// void foo(A::X<A::Y>, A::X<B::Y>),
// the A::X<> part is not aliased.
- // That said, from the mangler's perspective we have a structure like this:
+ // That is, from the mangler's perspective we have a structure like this:
// namespace[s] -> type[ -> template-parameters]
// but from the Clang perspective we have
// type [ -> template-parameters]
@@ -803,12 +813,40 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// the mangled type name as a key to check the mangling of different types
// for aliasing.
- llvm::SmallString<64> TemplateMangling;
- llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
- Extra.mangleTemplateInstantiationName(TD, *TemplateArgs);
-
- mangleSourceName(TemplateMangling);
+ // It's important to key cache reads off ND, not TD -- the same TD can
+ // be used with different TemplateArgs, but ND uniquely identifies
+ // TD / TemplateArg pairs.
+ ArgBackRefMap::iterator Found = TemplateArgBackReferences.find(ND);
+ if (Found == TemplateArgBackReferences.end()) {
+
+ TemplateArgStringMap::iterator Found = TemplateArgStrings.find(ND);
+ if (Found == TemplateArgStrings.end()) {
+ // Mangle full template name into temporary buffer.
+ llvm::SmallString<64> TemplateMangling;
+ llvm::raw_svector_ostream Stream(TemplateMangling);
+ MicrosoftCXXNameMangler Extra(Context, Stream);
+ Extra.mangleTemplateInstantiationName(TD, *TemplateArgs);
+
+ // Use the string backref vector to possibly get a back reference.
+ mangleSourceName(TemplateMangling);
+
+ // Memoize back reference for this type if one exist, else memoize
+ // the mangling itself.
+ BackRefVec::iterator StringFound =
+ llvm::find(NameBackReferences, TemplateMangling);
+ if (StringFound != NameBackReferences.end()) {
+ TemplateArgBackReferences[ND] =
+ StringFound - NameBackReferences.begin();
+ } else {
+ TemplateArgStrings[ND] =
+ TemplateArgStringStorage.save(TemplateMangling.str());
+ }
+ } else {
+ Out << Found->second; // Outputs a StringRef.
+ }
+ } else {
+ Out << Found->second; // Outputs a back reference (an int).
+ }
return;
}
@@ -1242,15 +1280,8 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
case OO_Array_Delete: Out << "?_V"; break;
// <operator-name> ::= ?__L # co_await
case OO_Coawait: Out << "?__L"; break;
-
- case OO_Spaceship: {
- // FIXME: Once MS picks a mangling, use it.
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this three-way comparison operator yet");
- Diags.Report(Loc, DiagID);
- break;
- }
+ // <operator-name> ::= ?__M # <=>
+ case OO_Spaceship: Out << "?__M"; break;
case OO_Conditional: {
DiagnosticsEngine &Diags = Context.getDiags();
@@ -1268,8 +1299,7 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
void MicrosoftCXXNameMangler::mangleSourceName(StringRef Name) {
// <source name> ::= <identifier> @
- BackRefVec::iterator Found =
- std::find(NameBackReferences.begin(), NameBackReferences.end(), Name);
+ BackRefVec::iterator Found = llvm::find(NameBackReferences, Name);
if (Found == NameBackReferences.end()) {
if (NameBackReferences.size() < 10)
NameBackReferences.push_back(Name);
@@ -1290,11 +1320,13 @@ void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
// Always start with the unqualified name.
// Templates have their own context for back references.
- ArgBackRefMap OuterArgsContext;
+ ArgBackRefMap OuterFunArgsContext;
+ ArgBackRefMap OuterTemplateArgsContext;
BackRefVec OuterTemplateContext;
PassObjectSizeArgsSet OuterPassObjectSizeArgs;
NameBackReferences.swap(OuterTemplateContext);
- TypeBackReferences.swap(OuterArgsContext);
+ FunArgBackReferences.swap(OuterFunArgsContext);
+ TemplateArgBackReferences.swap(OuterTemplateArgsContext);
PassObjectSizeArgs.swap(OuterPassObjectSizeArgs);
mangleUnscopedTemplateName(TD);
@@ -1302,7 +1334,8 @@ void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
// Restore the previous back reference contexts.
NameBackReferences.swap(OuterTemplateContext);
- TypeBackReferences.swap(OuterArgsContext);
+ FunArgBackReferences.swap(OuterFunArgsContext);
+ TemplateArgBackReferences.swap(OuterTemplateArgsContext);
PassObjectSizeArgs.swap(OuterPassObjectSizeArgs);
}
@@ -1707,8 +1740,8 @@ void MicrosoftCXXNameMangler::manglePointerCVQualifiers(Qualifiers Quals) {
}
}
-void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
- SourceRange Range) {
+void MicrosoftCXXNameMangler::mangleFunctionArgumentType(QualType T,
+ SourceRange Range) {
// MSVC will backreference two canonically equivalent types that have slightly
// different manglings when mangled alone.
@@ -1738,9 +1771,9 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
TypePtr = T.getCanonicalType().getAsOpaquePtr();
}
- ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
+ ArgBackRefMap::iterator Found = FunArgBackReferences.find(TypePtr);
- if (Found == TypeBackReferences.end()) {
+ if (Found == FunArgBackReferences.end()) {
size_t OutSizeBefore = Out.tell();
mangleType(T, Range, QMM_Drop);
@@ -1749,9 +1782,9 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
// Only types longer than 1 character are considered
// and only 10 back references slots are available:
bool LongerThanOneChar = (Out.tell() - OutSizeBefore > 1);
- if (LongerThanOneChar && TypeBackReferences.size() < 10) {
- size_t Size = TypeBackReferences.size();
- TypeBackReferences[TypePtr] = Size;
+ if (LongerThanOneChar && FunArgBackReferences.size() < 10) {
+ size_t Size = FunArgBackReferences.size();
+ FunArgBackReferences[TypePtr] = Size;
}
} else {
Out << Found->second;
@@ -1761,18 +1794,20 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
void MicrosoftCXXNameMangler::manglePassObjectSizeArg(
const PassObjectSizeAttr *POSA) {
int Type = POSA->getType();
+ bool Dynamic = POSA->isDynamic();
- auto Iter = PassObjectSizeArgs.insert(Type).first;
+ auto Iter = PassObjectSizeArgs.insert({Type, Dynamic}).first;
auto *TypePtr = (const void *)&*Iter;
- ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
+ ArgBackRefMap::iterator Found = FunArgBackReferences.find(TypePtr);
- if (Found == TypeBackReferences.end()) {
- mangleArtificialTagType(TTK_Enum, "__pass_object_size" + llvm::utostr(Type),
- {"__clang"});
+ if (Found == FunArgBackReferences.end()) {
+ std::string Name =
+ Dynamic ? "__pass_dynamic_object_size" : "__pass_object_size";
+ mangleArtificialTagType(TTK_Enum, Name + llvm::utostr(Type), {"__clang"});
- if (TypeBackReferences.size() < 10) {
- size_t Size = TypeBackReferences.size();
- TypeBackReferences[TypePtr] = Size;
+ if (FunArgBackReferences.size() < 10) {
+ size_t Size = FunArgBackReferences.size();
+ FunArgBackReferences[TypePtr] = Size;
}
} else {
Out << Found->second;
@@ -1937,8 +1972,9 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
// ::= _M # unsigned __int128
// ::= _N # bool
// _O # <array in parameter>
- // ::= _T # __float80 (Intel)
+ // ::= _Q # char8_t
// ::= _S # char16_t
+ // ::= _T # __float80 (Intel)
// ::= _U # char32_t
// ::= _W # wchar_t
// ::= _Z # __float80 (Digital Mars)
@@ -1999,6 +2035,9 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
case BuiltinType::Bool:
Out << "_N";
break;
+ case BuiltinType::Char8:
+ Out << "_Q";
+ break;
case BuiltinType::Char16:
Out << "_S";
break;
@@ -2094,7 +2133,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
case BuiltinType::SatUShortFract:
case BuiltinType::SatUFract:
case BuiltinType::SatULongFract:
- case BuiltinType::Char8:
case BuiltinType::Float128: {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(
@@ -2112,7 +2150,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, Qualifiers,
// Structors only appear in decls, so at this point we know it's not a
// structor type.
// FIXME: This may not be lambda-friendly.
- if (T->getTypeQuals() || T->getRefQualifier() != RQ_None) {
+ if (T->getMethodQuals() || T->getRefQualifier() != RQ_None) {
Out << "$$A8@@";
mangleFunctionType(T, /*D=*/nullptr, /*ForceThisQuals=*/true);
} else {
@@ -2161,7 +2199,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
// If this is a C++ instance method, mangle the CVR qualifiers for the
// this pointer.
if (HasThisQuals) {
- Qualifiers Quals = Proto->getTypeQuals();
+ Qualifiers Quals = Proto->getMethodQuals();
manglePointerExtQualifiers(Quals, /*PointeeType=*/QualType());
mangleRefQualifier(Proto->getRefQualifier());
mangleQualifiers(Quals, /*IsMember=*/false);
@@ -2195,12 +2233,12 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
Out << 'X';
} else if (StructorType == Ctor_CopyingClosure) {
// Copy constructor closure always takes an unqualified reference.
- mangleArgumentType(getASTContext().getLValueReferenceType(
- Proto->getParamType(0)
- ->getAs<LValueReferenceType>()
- ->getPointeeType(),
- /*SpelledAsLValue=*/true),
- Range);
+ mangleFunctionArgumentType(getASTContext().getLValueReferenceType(
+ Proto->getParamType(0)
+ ->getAs<LValueReferenceType>()
+ ->getPointeeType(),
+ /*SpelledAsLValue=*/true),
+ Range);
Out << '@';
} else {
llvm_unreachable("unexpected constructor closure!");
@@ -2242,7 +2280,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
} else {
// Happens for function pointer type arguments for example.
for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) {
- mangleArgumentType(Proto->getParamType(I), Range);
+ mangleFunctionArgumentType(Proto->getParamType(I), Range);
// Mangle each pass_object_size parameter as if it's a parameter of enum
// type passed directly after the parameter with the pass_object_size
// attribute. The aforementioned enum's name is __pass_object_size, and we
@@ -2734,10 +2772,12 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T,
if (T->qual_empty() && !T->isSpecialized())
return mangleType(T->getBaseType(), Range, QMM_Drop);
- ArgBackRefMap OuterArgsContext;
+ ArgBackRefMap OuterFunArgsContext;
+ ArgBackRefMap OuterTemplateArgsContext;
BackRefVec OuterTemplateContext;
- TypeBackReferences.swap(OuterArgsContext);
+ FunArgBackReferences.swap(OuterFunArgsContext);
+ TemplateArgBackReferences.swap(OuterTemplateArgsContext);
NameBackReferences.swap(OuterTemplateContext);
mangleTagTypeKind(TTK_Struct);
@@ -2761,7 +2801,8 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T,
Out << '@';
- TypeBackReferences.swap(OuterArgsContext);
+ FunArgBackReferences.swap(OuterFunArgsContext);
+ TemplateArgBackReferences.swap(OuterTemplateArgsContext);
NameBackReferences.swap(OuterTemplateContext);
}
@@ -3154,12 +3195,18 @@ void MicrosoftMangleContextImpl::mangleCXXCatchableType(
}
Mangler.getStream() << RTTIMangling;
- // VS2015 CTP6 omits the copy-constructor in the mangled name. This name is,
- // in fact, superfluous but I'm not sure the change was made consciously.
+ // VS2015 and VS2017.1 omit the copy-constructor in the mangled name but
+ // both older and newer versions include it.
+ // FIXME: It is known that the Ctor is present in 2013, and in 2017.7
+ // (_MSC_VER 1914) and newer, and that it's omitted in 2015 and 2017.4
+ // (_MSC_VER 1911), but it's unknown when exactly it reappeared (1914?
+ // Or 1912, 1913 aleady?).
+ bool OmitCopyCtor = getASTContext().getLangOpts().isCompatibleWithMSVC(
+ LangOptions::MSVC2015) &&
+ !getASTContext().getLangOpts().isCompatibleWithMSVC(
+ LangOptions::MSVC2017_7);
llvm::SmallString<64> CopyCtorMangling;
- if (!getASTContext().getLangOpts().isCompatibleWithMSVC(
- LangOptions::MSVC2015) &&
- CD) {
+ if (!OmitCopyCtor && CD) {
llvm::raw_svector_ostream Stream(CopyCtorMangling);
msvc_hashing_ostream MHO(Stream);
mangleCXXCtor(CD, CT, MHO);
@@ -3457,8 +3504,7 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
} else {
const char SpecialChars[] = {',', '/', '\\', ':', '.',
' ', '\n', '\t', '\'', '-'};
- const char *Pos =
- std::find(std::begin(SpecialChars), std::end(SpecialChars), Byte);
+ const char *Pos = llvm::find(SpecialChars, Byte);
if (Pos != std::end(SpecialChars)) {
Mangler.getStream() << '?' << (Pos - std::begin(SpecialChars));
} else {
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index 5b8300893e2d5..5104dc59d621e 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -1,9 +1,8 @@
//===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 42f6a133d7174..09d85102585bd 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -1,9 +1,8 @@
//===- NestedNameSpecifier.cpp - C++ nested name specifiers ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp
index a4c344ce0a9b1..3b89c630b451e 100644
--- a/lib/AST/ODRHash.cpp
+++ b/lib/AST/ODRHash.cpp
@@ -1,9 +1,8 @@
//===-- ODRHash.cpp - Hashing to diagnose ODR failures ----------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
///
@@ -72,8 +71,13 @@ void ODRHash::AddDeclarationNameImpl(DeclarationName Name) {
AddBoolean(S.isKeywordSelector());
AddBoolean(S.isUnarySelector());
unsigned NumArgs = S.getNumArgs();
+ ID.AddInteger(NumArgs);
for (unsigned i = 0; i < NumArgs; ++i) {
- AddIdentifierInfo(S.getIdentifierInfoForSlot(i));
+ const IdentifierInfo *II = S.getIdentifierInfoForSlot(i);
+ AddBoolean(II);
+ if (II) {
+ AddIdentifierInfo(II);
+ }
}
break;
}
@@ -141,6 +145,7 @@ void ODRHash::AddTemplateName(TemplateName Name) {
break;
// TODO: Support these cases.
case TemplateName::OverloadedTemplate:
+ case TemplateName::AssumedTemplate:
case TemplateName::QualifiedTemplate:
case TemplateName::DependentTemplate:
case TemplateName::SubstTemplateTemplateParm:
@@ -696,7 +701,52 @@ public:
ID.AddInteger(Quals.getAsOpaqueValue());
}
+ // Return the RecordType if the typedef only strips away a keyword.
+ // Otherwise, return the original type.
+ static const Type *RemoveTypedef(const Type *T) {
+ const auto *TypedefT = dyn_cast<TypedefType>(T);
+ if (!TypedefT) {
+ return T;
+ }
+
+ const TypedefNameDecl *D = TypedefT->getDecl();
+ QualType UnderlyingType = D->getUnderlyingType();
+
+ if (UnderlyingType.hasLocalQualifiers()) {
+ return T;
+ }
+
+ const auto *ElaboratedT = dyn_cast<ElaboratedType>(UnderlyingType);
+ if (!ElaboratedT) {
+ return T;
+ }
+
+ if (ElaboratedT->getQualifier() != nullptr) {
+ return T;
+ }
+
+ QualType NamedType = ElaboratedT->getNamedType();
+ if (NamedType.hasLocalQualifiers()) {
+ return T;
+ }
+
+ const auto *RecordT = dyn_cast<RecordType>(NamedType);
+ if (!RecordT) {
+ return T;
+ }
+
+ const IdentifierInfo *TypedefII = TypedefT->getDecl()->getIdentifier();
+ const IdentifierInfo *RecordII = RecordT->getDecl()->getIdentifier();
+ if (!TypedefII || !RecordII ||
+ TypedefII->getName() != RecordII->getName()) {
+ return T;
+ }
+
+ return RecordT;
+ }
+
void Visit(const Type *T) {
+ T = RemoveTypedef(T);
ID.AddInteger(T->getTypeClass());
Inherited::Visit(T);
}
@@ -704,14 +754,36 @@ public:
void VisitType(const Type *T) {}
void VisitAdjustedType(const AdjustedType *T) {
- AddQualType(T->getOriginalType());
- AddQualType(T->getAdjustedType());
+ QualType Original = T->getOriginalType();
+ QualType Adjusted = T->getAdjustedType();
+
+ // The original type and pointee type can be the same, as in the case of
+ // function pointers decaying to themselves. Set a bool and only process
+ // the type once, to prevent doubling the work.
+ SplitQualType split = Adjusted.split();
+ if (auto Pointer = dyn_cast<PointerType>(split.Ty)) {
+ if (Pointer->getPointeeType() == Original) {
+ Hash.AddBoolean(true);
+ ID.AddInteger(split.Quals.getAsOpaqueValue());
+ AddQualType(Original);
+ VisitType(T);
+ return;
+ }
+ }
+
+ // The original type and pointee type are different, such as in the case
+ // of a array decaying to an element pointer. Set a bool to false and
+ // process both types.
+ Hash.AddBoolean(false);
+ AddQualType(Original);
+ AddQualType(Adjusted);
+
VisitType(T);
}
void VisitDecayedType(const DecayedType *T) {
- AddQualType(T->getDecayedType());
- AddQualType(T->getPointeeType());
+ // getDecayedType and getPointeeType are derived from getAdjustedType
+ // and don't need to be separately processed.
VisitAdjustedType(T);
}
diff --git a/lib/AST/OpenMPClause.cpp b/lib/AST/OpenMPClause.cpp
index 76098f15bf36f..9d8a7ebc3023e 100644
--- a/lib/AST/OpenMPClause.cpp
+++ b/lib/AST/OpenMPClause.cpp
@@ -1,9 +1,8 @@
//===- OpenMPClause.cpp - Classes for OpenMP clauses ----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -36,6 +35,20 @@ OMPClause::child_range OMPClause::children() {
llvm_unreachable("unknown OMPClause");
}
+OMPClause::child_range OMPClause::used_children() {
+ switch (getClauseKind()) {
+#define OPENMP_CLAUSE(Name, Class) \
+ case OMPC_##Name: \
+ return static_cast<Class *>(this)->used_children();
+#include "clang/Basic/OpenMPKinds.def"
+ case OMPC_threadprivate:
+ case OMPC_uniform:
+ case OMPC_unknown:
+ break;
+ }
+ llvm_unreachable("unknown OMPClause");
+}
+
OMPClauseWithPreInit *OMPClauseWithPreInit::get(OMPClause *C) {
auto *Res = OMPClauseWithPreInit::get(const_cast<const OMPClause *>(C));
return Res ? const_cast<OMPClauseWithPreInit *>(Res) : nullptr;
@@ -74,6 +87,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_final:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
+ case OMPC_allocate:
case OMPC_collapse:
case OMPC_private:
case OMPC_shared:
@@ -145,6 +160,8 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
+ case OMPC_allocate:
case OMPC_collapse:
case OMPC_private:
case OMPC_shared:
@@ -192,6 +209,25 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
return nullptr;
}
+/// Gets the address of the original, non-captured, expression used in the
+/// clause as the preinitializer.
+static Stmt **getAddrOfExprAsWritten(Stmt *S) {
+ if (!S)
+ return nullptr;
+ if (auto *DS = dyn_cast<DeclStmt>(S)) {
+ assert(DS->isSingleDecl() && "Only single expression must be captured.");
+ if (auto *OED = dyn_cast<OMPCapturedExprDecl>(DS->getSingleDecl()))
+ return OED->getInitAddress();
+ }
+ return nullptr;
+}
+
+OMPClause::child_range OMPIfClause::used_children() {
+ if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
+ return child_range(C, C + 1);
+ return child_range(&Condition, &Condition + 1);
+}
+
OMPOrderedClause *OMPOrderedClause::Create(const ASTContext &C, Expr *Num,
unsigned NumLoops,
SourceLocation StartLoc,
@@ -698,6 +734,25 @@ OMPInReductionClause *OMPInReductionClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPInReductionClause(N);
}
+OMPAllocateClause *
+OMPAllocateClause::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc, Expr *Allocator,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ // Allocate space for private variables and initializer expressions.
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size()));
+ auto *Clause = new (Mem) OMPAllocateClause(StartLoc, LParenLoc, Allocator,
+ ColonLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPAllocateClause *OMPAllocateClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
+ return new (Mem) OMPAllocateClause(N);
+}
+
OMPFlushClause *OMPFlushClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -791,24 +846,23 @@ unsigned OMPClauseMappableExprCommon::getUniqueDeclarationsTotalNumber(
return TotalNum;
}
-OMPMapClause *
-OMPMapClause::Create(const ASTContext &C, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc,
- ArrayRef<Expr *> Vars, ArrayRef<ValueDecl *> Declarations,
- MappableExprComponentListsRef ComponentLists,
- ArrayRef<OpenMPMapModifierKind> MapModifiers,
- ArrayRef<SourceLocation> MapModifiersLoc,
- OpenMPMapClauseKind Type, bool TypeIsImplicit,
- SourceLocation TypeLoc) {
- unsigned NumVars = Vars.size();
- unsigned NumUniqueDeclarations =
- getUniqueDeclarationsTotalNumber(Declarations);
- unsigned NumComponentLists = ComponentLists.size();
- unsigned NumComponents = getComponentsTotalNumber(ComponentLists);
+OMPMapClause *OMPMapClause::Create(
+ const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars,
+ ArrayRef<ValueDecl *> Declarations,
+ MappableExprComponentListsRef ComponentLists, ArrayRef<Expr *> UDMapperRefs,
+ ArrayRef<OpenMPMapModifierKind> MapModifiers,
+ ArrayRef<SourceLocation> MapModifiersLoc,
+ NestedNameSpecifierLoc UDMQualifierLoc, DeclarationNameInfo MapperId,
+ OpenMPMapClauseKind Type, bool TypeIsImplicit, SourceLocation TypeLoc) {
+ OMPMappableExprListSizeTy Sizes;
+ Sizes.NumVars = Vars.size();
+ Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations);
+ Sizes.NumComponentLists = ComponentLists.size();
+ Sizes.NumComponents = getComponentsTotalNumber(ComponentLists);
// We need to allocate:
- // NumVars x Expr* - we have an original list expression for each clause list
- // entry.
+ // 2 x NumVars x Expr* - we have an original list expression and an associated
+ // user-defined mapper for each clause list entry.
// NumUniqueDeclarations x ValueDecl* - unique base declarations associated
// with each component list.
// (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the
@@ -819,47 +873,47 @@ OMPMapClause::Create(const ASTContext &C, SourceLocation StartLoc,
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- NumVars, NumUniqueDeclarations,
- NumUniqueDeclarations + NumComponentLists, NumComponents));
- OMPMapClause *Clause = new (Mem) OMPMapClause(
- MapModifiers, MapModifiersLoc, Type, TypeIsImplicit, TypeLoc, StartLoc,
- LParenLoc, EndLoc, NumVars, NumUniqueDeclarations, NumComponentLists,
- NumComponents);
+ 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
+ Sizes.NumComponents));
+ OMPMapClause *Clause = new (Mem)
+ OMPMapClause(MapModifiers, MapModifiersLoc, UDMQualifierLoc, MapperId,
+ Type, TypeIsImplicit, TypeLoc, Locs, Sizes);
Clause->setVarRefs(Vars);
+ Clause->setUDMapperRefs(UDMapperRefs);
Clause->setClauseInfo(Declarations, ComponentLists);
Clause->setMapType(Type);
Clause->setMapLoc(TypeLoc);
return Clause;
}
-OMPMapClause *OMPMapClause::CreateEmpty(const ASTContext &C, unsigned NumVars,
- unsigned NumUniqueDeclarations,
- unsigned NumComponentLists,
- unsigned NumComponents) {
+OMPMapClause *
+OMPMapClause::CreateEmpty(const ASTContext &C,
+ const OMPMappableExprListSizeTy &Sizes) {
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- NumVars, NumUniqueDeclarations,
- NumUniqueDeclarations + NumComponentLists, NumComponents));
- return new (Mem) OMPMapClause(NumVars, NumUniqueDeclarations,
- NumComponentLists, NumComponents);
-}
-
-OMPToClause *OMPToClause::Create(const ASTContext &C, SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc, ArrayRef<Expr *> Vars,
- ArrayRef<ValueDecl *> Declarations,
- MappableExprComponentListsRef ComponentLists) {
- unsigned NumVars = Vars.size();
- unsigned NumUniqueDeclarations =
- getUniqueDeclarationsTotalNumber(Declarations);
- unsigned NumComponentLists = ComponentLists.size();
- unsigned NumComponents = getComponentsTotalNumber(ComponentLists);
+ 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
+ Sizes.NumComponents));
+ return new (Mem) OMPMapClause(Sizes);
+}
+
+OMPToClause *OMPToClause::Create(
+ const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars,
+ ArrayRef<ValueDecl *> Declarations,
+ MappableExprComponentListsRef ComponentLists, ArrayRef<Expr *> UDMapperRefs,
+ NestedNameSpecifierLoc UDMQualifierLoc, DeclarationNameInfo MapperId) {
+ OMPMappableExprListSizeTy Sizes;
+ Sizes.NumVars = Vars.size();
+ Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations);
+ Sizes.NumComponentLists = ComponentLists.size();
+ Sizes.NumComponents = getComponentsTotalNumber(ComponentLists);
// We need to allocate:
- // NumVars x Expr* - we have an original list expression for each clause list
- // entry.
+ // 2 x NumVars x Expr* - we have an original list expression and an associated
+ // user-defined mapper for each clause list entry.
// NumUniqueDeclarations x ValueDecl* - unique base declarations associated
// with each component list.
// (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the
@@ -870,45 +924,43 @@ OMPToClause *OMPToClause::Create(const ASTContext &C, SourceLocation StartLoc,
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- NumVars, NumUniqueDeclarations,
- NumUniqueDeclarations + NumComponentLists, NumComponents));
+ 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
+ Sizes.NumComponents));
- OMPToClause *Clause = new (Mem)
- OMPToClause(StartLoc, LParenLoc, EndLoc, NumVars, NumUniqueDeclarations,
- NumComponentLists, NumComponents);
+ auto *Clause = new (Mem) OMPToClause(UDMQualifierLoc, MapperId, Locs, Sizes);
Clause->setVarRefs(Vars);
+ Clause->setUDMapperRefs(UDMapperRefs);
Clause->setClauseInfo(Declarations, ComponentLists);
return Clause;
}
-OMPToClause *OMPToClause::CreateEmpty(const ASTContext &C, unsigned NumVars,
- unsigned NumUniqueDeclarations,
- unsigned NumComponentLists,
- unsigned NumComponents) {
+OMPToClause *OMPToClause::CreateEmpty(const ASTContext &C,
+ const OMPMappableExprListSizeTy &Sizes) {
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- NumVars, NumUniqueDeclarations,
- NumUniqueDeclarations + NumComponentLists, NumComponents));
- return new (Mem) OMPToClause(NumVars, NumUniqueDeclarations,
- NumComponentLists, NumComponents);
-}
-
-OMPFromClause *
-OMPFromClause::Create(const ASTContext &C, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc,
- ArrayRef<Expr *> Vars, ArrayRef<ValueDecl *> Declarations,
- MappableExprComponentListsRef ComponentLists) {
- unsigned NumVars = Vars.size();
- unsigned NumUniqueDeclarations =
- getUniqueDeclarationsTotalNumber(Declarations);
- unsigned NumComponentLists = ComponentLists.size();
- unsigned NumComponents = getComponentsTotalNumber(ComponentLists);
+ 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
+ Sizes.NumComponents));
+ return new (Mem) OMPToClause(Sizes);
+}
+
+OMPFromClause *OMPFromClause::Create(
+ const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars,
+ ArrayRef<ValueDecl *> Declarations,
+ MappableExprComponentListsRef ComponentLists, ArrayRef<Expr *> UDMapperRefs,
+ NestedNameSpecifierLoc UDMQualifierLoc, DeclarationNameInfo MapperId) {
+ OMPMappableExprListSizeTy Sizes;
+ Sizes.NumVars = Vars.size();
+ Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations);
+ Sizes.NumComponentLists = ComponentLists.size();
+ Sizes.NumComponents = getComponentsTotalNumber(ComponentLists);
// We need to allocate:
- // NumVars x Expr* - we have an original list expression for each clause list
- // entry.
+ // 2 x NumVars x Expr* - we have an original list expression and an associated
+ // user-defined mapper for each clause list entry.
// NumUniqueDeclarations x ValueDecl* - unique base declarations associated
// with each component list.
// (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the
@@ -919,29 +971,29 @@ OMPFromClause::Create(const ASTContext &C, SourceLocation StartLoc,
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- NumVars, NumUniqueDeclarations,
- NumUniqueDeclarations + NumComponentLists, NumComponents));
+ 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
+ Sizes.NumComponents));
- OMPFromClause *Clause = new (Mem)
- OMPFromClause(StartLoc, LParenLoc, EndLoc, NumVars, NumUniqueDeclarations,
- NumComponentLists, NumComponents);
+ auto *Clause =
+ new (Mem) OMPFromClause(UDMQualifierLoc, MapperId, Locs, Sizes);
Clause->setVarRefs(Vars);
+ Clause->setUDMapperRefs(UDMapperRefs);
Clause->setClauseInfo(Declarations, ComponentLists);
return Clause;
}
-OMPFromClause *OMPFromClause::CreateEmpty(const ASTContext &C, unsigned NumVars,
- unsigned NumUniqueDeclarations,
- unsigned NumComponentLists,
- unsigned NumComponents) {
+OMPFromClause *
+OMPFromClause::CreateEmpty(const ASTContext &C,
+ const OMPMappableExprListSizeTy &Sizes) {
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- NumVars, NumUniqueDeclarations,
- NumUniqueDeclarations + NumComponentLists, NumComponents));
- return new (Mem) OMPFromClause(NumVars, NumUniqueDeclarations,
- NumComponentLists, NumComponents);
+ 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
+ Sizes.NumComponents));
+ return new (Mem) OMPFromClause(Sizes);
}
void OMPUseDevicePtrClause::setPrivateCopies(ArrayRef<Expr *> VL) {
@@ -957,15 +1009,15 @@ void OMPUseDevicePtrClause::setInits(ArrayRef<Expr *> VL) {
}
OMPUseDevicePtrClause *OMPUseDevicePtrClause::Create(
- const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation EndLoc, ArrayRef<Expr *> Vars, ArrayRef<Expr *> PrivateVars,
- ArrayRef<Expr *> Inits, ArrayRef<ValueDecl *> Declarations,
+ const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars,
+ ArrayRef<Expr *> PrivateVars, ArrayRef<Expr *> Inits,
+ ArrayRef<ValueDecl *> Declarations,
MappableExprComponentListsRef ComponentLists) {
- unsigned NumVars = Vars.size();
- unsigned NumUniqueDeclarations =
- getUniqueDeclarationsTotalNumber(Declarations);
- unsigned NumComponentLists = ComponentLists.size();
- unsigned NumComponents = getComponentsTotalNumber(ComponentLists);
+ OMPMappableExprListSizeTy Sizes;
+ Sizes.NumVars = Vars.size();
+ Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations);
+ Sizes.NumComponentLists = ComponentLists.size();
+ Sizes.NumComponents = getComponentsTotalNumber(ComponentLists);
// We need to allocate:
// 3 x NumVars x Expr* - we have an original list expression for each clause
@@ -980,12 +1032,11 @@ OMPUseDevicePtrClause *OMPUseDevicePtrClause::Create(
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- 3 * NumVars, NumUniqueDeclarations,
- NumUniqueDeclarations + NumComponentLists, NumComponents));
+ 3 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
+ Sizes.NumComponents));
- OMPUseDevicePtrClause *Clause = new (Mem) OMPUseDevicePtrClause(
- StartLoc, LParenLoc, EndLoc, NumVars, NumUniqueDeclarations,
- NumComponentLists, NumComponents);
+ OMPUseDevicePtrClause *Clause = new (Mem) OMPUseDevicePtrClause(Locs, Sizes);
Clause->setVarRefs(Vars);
Clause->setPrivateCopies(PrivateVars);
@@ -994,29 +1045,28 @@ OMPUseDevicePtrClause *OMPUseDevicePtrClause::Create(
return Clause;
}
-OMPUseDevicePtrClause *OMPUseDevicePtrClause::CreateEmpty(
- const ASTContext &C, unsigned NumVars, unsigned NumUniqueDeclarations,
- unsigned NumComponentLists, unsigned NumComponents) {
+OMPUseDevicePtrClause *
+OMPUseDevicePtrClause::CreateEmpty(const ASTContext &C,
+ const OMPMappableExprListSizeTy &Sizes) {
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- 3 * NumVars, NumUniqueDeclarations,
- NumUniqueDeclarations + NumComponentLists, NumComponents));
- return new (Mem) OMPUseDevicePtrClause(NumVars, NumUniqueDeclarations,
- NumComponentLists, NumComponents);
+ 3 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
+ Sizes.NumComponents));
+ return new (Mem) OMPUseDevicePtrClause(Sizes);
}
OMPIsDevicePtrClause *
-OMPIsDevicePtrClause::Create(const ASTContext &C, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc,
+OMPIsDevicePtrClause::Create(const ASTContext &C, const OMPVarListLocTy &Locs,
ArrayRef<Expr *> Vars,
ArrayRef<ValueDecl *> Declarations,
MappableExprComponentListsRef ComponentLists) {
- unsigned NumVars = Vars.size();
- unsigned NumUniqueDeclarations =
- getUniqueDeclarationsTotalNumber(Declarations);
- unsigned NumComponentLists = ComponentLists.size();
- unsigned NumComponents = getComponentsTotalNumber(ComponentLists);
+ OMPMappableExprListSizeTy Sizes;
+ Sizes.NumVars = Vars.size();
+ Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations);
+ Sizes.NumComponentLists = ComponentLists.size();
+ Sizes.NumComponents = getComponentsTotalNumber(ComponentLists);
// We need to allocate:
// NumVars x Expr* - we have an original list expression for each clause list
@@ -1031,28 +1081,27 @@ OMPIsDevicePtrClause::Create(const ASTContext &C, SourceLocation StartLoc,
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- NumVars, NumUniqueDeclarations,
- NumUniqueDeclarations + NumComponentLists, NumComponents));
+ Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
+ Sizes.NumComponents));
- OMPIsDevicePtrClause *Clause = new (Mem) OMPIsDevicePtrClause(
- StartLoc, LParenLoc, EndLoc, NumVars, NumUniqueDeclarations,
- NumComponentLists, NumComponents);
+ OMPIsDevicePtrClause *Clause = new (Mem) OMPIsDevicePtrClause(Locs, Sizes);
Clause->setVarRefs(Vars);
Clause->setClauseInfo(Declarations, ComponentLists);
return Clause;
}
-OMPIsDevicePtrClause *OMPIsDevicePtrClause::CreateEmpty(
- const ASTContext &C, unsigned NumVars, unsigned NumUniqueDeclarations,
- unsigned NumComponentLists, unsigned NumComponents) {
+OMPIsDevicePtrClause *
+OMPIsDevicePtrClause::CreateEmpty(const ASTContext &C,
+ const OMPMappableExprListSizeTy &Sizes) {
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- NumVars, NumUniqueDeclarations,
- NumUniqueDeclarations + NumComponentLists, NumComponents));
- return new (Mem) OMPIsDevicePtrClause(NumVars, NumUniqueDeclarations,
- NumComponentLists, NumComponents);
+ Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
+ Sizes.NumComponents));
+ return new (Mem) OMPIsDevicePtrClause(Sizes);
}
//===----------------------------------------------------------------------===//
@@ -1091,6 +1140,12 @@ void OMPClausePrinter::VisitOMPSimdlenClause(OMPSimdlenClause *Node) {
OS << ")";
}
+void OMPClausePrinter::VisitOMPAllocatorClause(OMPAllocatorClause *Node) {
+ OS << "allocator(";
+ Node->getAllocator()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
void OMPClausePrinter::VisitOMPCollapseClause(OMPCollapseClause *Node) {
OS << "collapse(";
Node->getNumForLoops()->printPretty(OS, nullptr, Policy, 0);
@@ -1261,6 +1316,21 @@ void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) {
}
}
+void OMPClausePrinter::VisitOMPAllocateClause(OMPAllocateClause *Node) {
+ if (Node->varlist_empty())
+ return;
+ OS << "allocate";
+ if (Expr *Allocator = Node->getAllocator()) {
+ OS << "(";
+ Allocator->printPretty(OS, nullptr, Policy, 0);
+ OS << ":";
+ VisitOMPClauseList(Node, ' ');
+ } else {
+ VisitOMPClauseList(Node, '(');
+ }
+ OS << ")";
+}
+
void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) {
if (!Node->varlist_empty()) {
OS << "private";
@@ -1432,6 +1502,14 @@ void OMPClausePrinter::VisitOMPMapClause(OMPMapClause *Node) {
if (Node->getMapTypeModifier(I) != OMPC_MAP_MODIFIER_unknown) {
OS << getOpenMPSimpleClauseTypeName(OMPC_map,
Node->getMapTypeModifier(I));
+ if (Node->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_mapper) {
+ OS << '(';
+ NestedNameSpecifier *MapperNNS =
+ Node->getMapperQualifierLoc().getNestedNameSpecifier();
+ if (MapperNNS)
+ MapperNNS->print(OS, Policy);
+ OS << Node->getMapperIdInfo() << ')';
+ }
OS << ',';
}
}
@@ -1446,7 +1524,19 @@ void OMPClausePrinter::VisitOMPMapClause(OMPMapClause *Node) {
void OMPClausePrinter::VisitOMPToClause(OMPToClause *Node) {
if (!Node->varlist_empty()) {
OS << "to";
- VisitOMPClauseList(Node, '(');
+ DeclarationNameInfo MapperId = Node->getMapperIdInfo();
+ if (MapperId.getName() && !MapperId.getName().isEmpty()) {
+ OS << '(';
+ OS << "mapper(";
+ NestedNameSpecifier *MapperNNS =
+ Node->getMapperQualifierLoc().getNestedNameSpecifier();
+ if (MapperNNS)
+ MapperNNS->print(OS, Policy);
+ OS << MapperId << "):";
+ VisitOMPClauseList(Node, ' ');
+ } else {
+ VisitOMPClauseList(Node, '(');
+ }
OS << ")";
}
}
@@ -1454,7 +1544,19 @@ void OMPClausePrinter::VisitOMPToClause(OMPToClause *Node) {
void OMPClausePrinter::VisitOMPFromClause(OMPFromClause *Node) {
if (!Node->varlist_empty()) {
OS << "from";
- VisitOMPClauseList(Node, '(');
+ DeclarationNameInfo MapperId = Node->getMapperIdInfo();
+ if (MapperId.getName() && !MapperId.getName().isEmpty()) {
+ OS << '(';
+ OS << "mapper(";
+ NestedNameSpecifier *MapperNNS =
+ Node->getMapperQualifierLoc().getNestedNameSpecifier();
+ if (MapperNNS)
+ MapperNNS->print(OS, Policy);
+ OS << MapperId << "):";
+ VisitOMPClauseList(Node, ' ');
+ } else {
+ VisitOMPClauseList(Node, '(');
+ }
OS << ")";
}
}
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index 88c178aa372fc..2ff5c9d8aeb57 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -1,9 +1,8 @@
//===--- ParentMap.cpp - Mappings from Stmts to their Parents ---*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -84,6 +83,18 @@ static void BuildParentMap(MapTy& M, Stmt* S,
}
break;
}
+ case Stmt::CapturedStmtClass:
+ for (Stmt *SubStmt : S->children()) {
+ if (SubStmt) {
+ M[SubStmt] = S;
+ BuildParentMap(M, SubStmt, OVMode);
+ }
+ }
+ if (Stmt *SubStmt = cast<CapturedStmt>(S)->getCapturedStmt()) {
+ M[SubStmt] = S;
+ BuildParentMap(M, SubStmt, OVMode);
+ }
+ break;
default:
for (Stmt *SubStmt : S->children()) {
if (SubStmt) {
diff --git a/lib/AST/PrintfFormatString.cpp b/lib/AST/PrintfFormatString.cpp
index e0a0c5b7582aa..a1207aae5aa25 100644
--- a/lib/AST/PrintfFormatString.cpp
+++ b/lib/AST/PrintfFormatString.cpp
@@ -1,9 +1,8 @@
//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -316,7 +315,11 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case 'f': k = ConversionSpecifier::fArg; break;
case 'g': k = ConversionSpecifier::gArg; break;
case 'i': k = ConversionSpecifier::iArg; break;
- case 'n': k = ConversionSpecifier::nArg; break;
+ case 'n':
+ // Not handled, but reserved in OpenCL.
+ if (!LO.OpenCL)
+ k = ConversionSpecifier::nArg;
+ break;
case 'o': k = ConversionSpecifier::oArg; break;
case 'p': k = ConversionSpecifier::pArg; break;
case 's': k = ConversionSpecifier::sArg; break;
@@ -487,10 +490,12 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
// GNU extension.
return Ctx.LongLongTy;
case LengthModifier::None:
+ case LengthModifier::AsShortLong:
return Ctx.IntTy;
case LengthModifier::AsInt32:
return ArgType(Ctx.IntTy, "__int32");
- case LengthModifier::AsChar: return ArgType::AnyCharTy;
+ case LengthModifier::AsChar:
+ return ArgType::AnyCharTy;
case LengthModifier::AsShort: return Ctx.ShortTy;
case LengthModifier::AsLong: return Ctx.LongTy;
case LengthModifier::AsLongLong:
@@ -521,6 +526,7 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
// GNU extension.
return Ctx.UnsignedLongLongTy;
case LengthModifier::None:
+ case LengthModifier::AsShortLong:
return Ctx.UnsignedIntTy;
case LengthModifier::AsInt32:
return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
@@ -550,6 +556,18 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
}
if (CS.isDoubleArg()) {
+ if (!VectorNumElts.isInvalid()) {
+ switch (LM.getKind()) {
+ case LengthModifier::AsShort:
+ return Ctx.HalfTy;
+ case LengthModifier::AsShortLong:
+ return Ctx.FloatTy;
+ case LengthModifier::AsLong:
+ default:
+ return Ctx.DoubleTy;
+ }
+ }
+
if (LM.getKind() == LengthModifier::AsLongDouble)
return Ctx.LongDoubleTy;
return Ctx.DoubleTy;
@@ -583,6 +601,8 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
case LengthModifier::AsInt64:
case LengthModifier::AsWide:
return ArgType::Invalid();
+ case LengthModifier::AsShortLong:
+ llvm_unreachable("only used for OpenCL which doesn not handle nArg");
}
}
@@ -761,10 +781,13 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
case BuiltinType::UInt:
case BuiltinType::Int:
case BuiltinType::Float:
+ LM.setKind(VectorNumElts.isInvalid() ?
+ LengthModifier::None : LengthModifier::AsShortLong);
+ break;
case BuiltinType::Double:
- LM.setKind(LengthModifier::None);
+ LM.setKind(VectorNumElts.isInvalid() ?
+ LengthModifier::None : LengthModifier::AsLong);
break;
-
case BuiltinType::Char_U:
case BuiltinType::UChar:
case BuiltinType::Char_S:
@@ -797,7 +820,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
namedTypeToLengthModifier(QT, LM);
// If fixing the length modifier was enough, we might be done.
- if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
// If we're going to offer a fix anyway, make sure the sign matches.
switch (CS.getKind()) {
case ConversionSpecifier::uArg:
diff --git a/lib/AST/QualTypeNames.cpp b/lib/AST/QualTypeNames.cpp
index 8b605ef295a02..f28f00171cce3 100644
--- a/lib/AST/QualTypeNames.cpp
+++ b/lib/AST/QualTypeNames.cpp
@@ -1,11 +1,8 @@
//===------- QualTypeNames.cpp - Generate Complete QualType Names ---------===//
//
-// The LLVM Compiler Infrastructure
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -382,6 +379,19 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
return QT;
}
+ if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
+ // Get the qualifiers.
+ Qualifiers Quals = QT.getQualifiers();
+ // Fully qualify the pointee and class types.
+ QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
+ QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx,
+ WithGlobalNsPrefix);
+ QT = Ctx.getMemberPointerType(QT, Class.getTypePtr());
+ // Add back the qualifiers.
+ QT = Ctx.getQualifiedType(QT, Quals);
+ return QT;
+ }
+
// In case of myType& we need to strip the reference first, fully
// qualify and attach the reference once again.
if (isa<ReferenceType>(QT.getTypePtr())) {
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp
index ab873a3964195..df53b7fa10047 100644
--- a/lib/AST/RawCommentList.cpp
+++ b/lib/AST/RawCommentList.cpp
@@ -1,9 +1,8 @@
//===--- RawCommentList.cpp - Processing raw comments -----------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index 9db23d50d0af2..e7b500e1902d7 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -1,9 +1,8 @@
//===- RecordLayout.cpp - Layout information for a struct/union -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 62dc22c814033..2a3419a0cec3d 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -1,9 +1,8 @@
//=== RecordLayoutBuilder.cpp - Helper class for building record layouts ---==//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -128,9 +127,10 @@ class EmptySubobjectMap {
CharUnits Offset, bool PlacingEmptyBase);
void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
- const CXXRecordDecl *Class,
- CharUnits Offset);
- void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset);
+ const CXXRecordDecl *Class, CharUnits Offset,
+ bool PlacingOverlappingField);
+ void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset,
+ bool PlacingOverlappingField);
/// AnyEmptySubobjectsBeyondOffset - Returns whether there are any empty
/// subobjects beyond the given offset.
@@ -239,7 +239,7 @@ EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
return true;
const ClassVectorTy &Classes = I->second;
- if (std::find(Classes.begin(), Classes.end(), RD) == Classes.end())
+ if (llvm::find(Classes, RD) == Classes.end())
return true;
// There is already an empty class of the same type at this offset.
@@ -255,7 +255,7 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD,
// If we have empty structures inside a union, we can assign both
// the same offset. Just avoid pushing them twice in the list.
ClassVectorTy &Classes = EmptyClassOffsets[Offset];
- if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end())
+ if (llvm::is_contained(Classes, RD))
return;
Classes.push_back(RD);
@@ -352,7 +352,7 @@ void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
continue;
CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
- UpdateEmptyFieldSubobjects(*I, FieldOffset);
+ UpdateEmptyFieldSubobjects(*I, FieldOffset, PlacingEmptyBase);
}
}
@@ -472,20 +472,25 @@ EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD,
return false;
// We are able to place the member variable at this offset.
- // Make sure to update the empty base subobject map.
- UpdateEmptyFieldSubobjects(FD, Offset);
+ // Make sure to update the empty field subobject map.
+ UpdateEmptyFieldSubobjects(FD, Offset, FD->hasAttr<NoUniqueAddressAttr>());
return true;
}
-void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
- const CXXRecordDecl *Class,
- CharUnits Offset) {
+void EmptySubobjectMap::UpdateEmptyFieldSubobjects(
+ const CXXRecordDecl *RD, const CXXRecordDecl *Class, CharUnits Offset,
+ bool PlacingOverlappingField) {
// We know that the only empty subobjects that can conflict with empty
- // field subobjects are subobjects of empty bases that can be placed at offset
- // zero. Because of this, we only need to keep track of empty field
- // subobjects with offsets less than the size of the largest empty
- // subobject for our class.
- if (Offset >= SizeOfLargestEmptySubobject)
+ // field subobjects are subobjects of empty bases and potentially-overlapping
+ // fields that can be placed at offset zero. Because of this, we only need to
+ // keep track of empty field subobjects with offsets less than the size of
+ // the largest empty subobject for our class.
+ //
+ // (Proof: we will only consider placing a subobject at offset zero or at
+ // >= the current dsize. The only cases where the earlier subobject can be
+ // placed beyond the end of dsize is if it's an empty base or a
+ // potentially-overlapping field.)
+ if (!PlacingOverlappingField && Offset >= SizeOfLargestEmptySubobject)
return;
AddSubobjectAtOffset(RD, Offset);
@@ -500,7 +505,8 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
- UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset);
+ UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset,
+ PlacingOverlappingField);
}
if (RD == Class) {
@@ -509,7 +515,8 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *VBaseDecl = Base.getType()->getAsCXXRecordDecl();
CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
- UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset);
+ UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset,
+ PlacingOverlappingField);
}
}
@@ -522,15 +529,15 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
- UpdateEmptyFieldSubobjects(*I, FieldOffset);
+ UpdateEmptyFieldSubobjects(*I, FieldOffset, PlacingOverlappingField);
}
}
-void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
- CharUnits Offset) {
+void EmptySubobjectMap::UpdateEmptyFieldSubobjects(
+ const FieldDecl *FD, CharUnits Offset, bool PlacingOverlappingField) {
QualType T = FD->getType();
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
- UpdateEmptyFieldSubobjects(RD, RD, Offset);
+ UpdateEmptyFieldSubobjects(RD, RD, Offset, PlacingOverlappingField);
return;
}
@@ -553,10 +560,12 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
// offset zero. Because of this, we only need to keep track of empty field
// subobjects with offsets less than the size of the largest empty
// subobject for our class.
- if (ElementOffset >= SizeOfLargestEmptySubobject)
+ if (!PlacingOverlappingField &&
+ ElementOffset >= SizeOfLargestEmptySubobject)
return;
- UpdateEmptyFieldSubobjects(RD, RD, ElementOffset);
+ UpdateEmptyFieldSubobjects(RD, RD, ElementOffset,
+ PlacingOverlappingField);
ElementOffset += Layout.getSize();
}
}
@@ -623,6 +632,10 @@ protected:
CharUnits NonVirtualSize;
CharUnits NonVirtualAlignment;
+ /// If we've laid out a field but not included its tail padding in Size yet,
+ /// this is the size up to the end of that field.
+ CharUnits PaddedFieldSize;
+
/// PrimaryBase - the primary base class (if one exists) of the class
/// we're laying out.
const CXXRecordDecl *PrimaryBase;
@@ -671,7 +684,8 @@ protected:
UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0),
MaxFieldAlignment(CharUnits::Zero()), DataSize(0),
NonVirtualSize(CharUnits::Zero()),
- NonVirtualAlignment(CharUnits::One()), PrimaryBase(nullptr),
+ NonVirtualAlignment(CharUnits::One()),
+ PaddedFieldSize(CharUnits::Zero()), PrimaryBase(nullptr),
PrimaryBaseIsVirtual(false), HasOwnVFPtr(false),
HasPackedField(false), FirstNearlyEmptyVBase(nullptr) {}
@@ -981,7 +995,6 @@ void ItaniumRecordLayoutBuilder::EnsureVTablePointerAlignment(
// Round up the current record size to pointer alignment.
setSize(getSize().alignTo(BaseAlign));
- setDataSize(getSize());
// Update the alignment.
UpdateAlignment(BaseAlign, UnpackedBaseAlign);
@@ -1173,6 +1186,7 @@ ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
// Query the external layout to see if it provides an offset.
bool HasExternalLayout = false;
if (UseExternalLayout) {
+ // FIXME: This appears to be reversed.
if (Base->IsVirtual)
HasExternalLayout = External.getExternalNVBaseOffset(Base->Class, Offset);
else
@@ -1343,8 +1357,8 @@ void ItaniumRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
// We start laying out ivars not at the end of the superclass
// structure, but at the next byte following the last field.
- setSize(SL.getDataSize());
- setDataSize(getSize());
+ setDataSize(SL.getDataSize());
+ setSize(getDataSize());
}
InitializeLayout(D);
@@ -1730,32 +1744,49 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
UnfilledBitsInLastUnit = 0;
LastBitfieldTypeSize = 0;
+ auto *FieldClass = D->getType()->getAsCXXRecordDecl();
+ bool PotentiallyOverlapping = D->hasAttr<NoUniqueAddressAttr>() && FieldClass;
+ bool IsOverlappingEmptyField = PotentiallyOverlapping && FieldClass->isEmpty();
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
- CharUnits FieldOffset =
- IsUnion ? CharUnits::Zero() : getDataSize();
+
+ CharUnits FieldOffset = (IsUnion || IsOverlappingEmptyField)
+ ? CharUnits::Zero()
+ : getDataSize();
CharUnits FieldSize;
CharUnits FieldAlign;
+ // The amount of this class's dsize occupied by the field.
+ // This is equal to FieldSize unless we're permitted to pack
+ // into the field's tail padding.
+ CharUnits EffectiveFieldSize;
if (D->getType()->isIncompleteArrayType()) {
// This is a flexible array member; we can't directly
// query getTypeInfo about these, so we figure it out here.
// Flexible array members don't have any size, but they
// have to be aligned appropriately for their element type.
- FieldSize = CharUnits::Zero();
+ EffectiveFieldSize = FieldSize = CharUnits::Zero();
const ArrayType* ATy = Context.getAsArrayType(D->getType());
FieldAlign = Context.getTypeAlignInChars(ATy->getElementType());
} else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
unsigned AS = Context.getTargetAddressSpace(RT->getPointeeType());
- FieldSize =
+ EffectiveFieldSize = FieldSize =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS));
FieldAlign =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(AS));
} else {
std::pair<CharUnits, CharUnits> FieldInfo =
Context.getTypeInfoInChars(D->getType());
- FieldSize = FieldInfo.first;
+ EffectiveFieldSize = FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
+ // A potentially-overlapping field occupies its dsize or nvsize, whichever
+ // is larger.
+ if (PotentiallyOverlapping) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(FieldClass);
+ EffectiveFieldSize =
+ std::max(Layout.getNonVirtualSize(), Layout.getDataSize());
+ }
+
if (IsMsStruct) {
// If MS bitfield layout is required, figure out what type is being
// laid out and align the field to the width of that type.
@@ -1835,7 +1866,12 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
// Check if we can place the field at this offset.
while (!EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset)) {
// We couldn't place the field at the offset. Try again at a new offset.
- FieldOffset += FieldAlign;
+ // We try offset 0 (for an empty field) and then dsize(C) onwards.
+ if (FieldOffset == CharUnits::Zero() &&
+ getDataSize() != CharUnits::Zero())
+ FieldOffset = getDataSize().alignTo(FieldAlign);
+ else
+ FieldOffset += FieldAlign;
}
}
}
@@ -1854,18 +1890,23 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
if (FieldSize % ASanAlignment)
ExtraSizeForAsan +=
ASanAlignment - CharUnits::fromQuantity(FieldSize % ASanAlignment);
- FieldSize += ExtraSizeForAsan;
+ EffectiveFieldSize = FieldSize = FieldSize + ExtraSizeForAsan;
}
// Reserve space for this field.
- uint64_t FieldSizeInBits = Context.toBits(FieldSize);
- if (IsUnion)
- setDataSize(std::max(getDataSizeInBits(), FieldSizeInBits));
- else
- setDataSize(FieldOffset + FieldSize);
+ if (!IsOverlappingEmptyField) {
+ uint64_t EffectiveFieldSizeInBits = Context.toBits(EffectiveFieldSize);
+ if (IsUnion)
+ setDataSize(std::max(getDataSizeInBits(), EffectiveFieldSizeInBits));
+ else
+ setDataSize(FieldOffset + EffectiveFieldSize);
- // Update the size.
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+ PaddedFieldSize = std::max(PaddedFieldSize, FieldOffset + FieldSize);
+ setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+ } else {
+ setSize(std::max(getSizeInBits(),
+ (uint64_t)Context.toBits(FieldOffset + FieldSize)));
+ }
// Remember max struct/class alignment.
UnadjustedAlignment = std::max(UnadjustedAlignment, FieldAlign);
@@ -1886,6 +1927,10 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
setSize(CharUnits::One());
}
+ // If we have any remaining field tail padding, include that in the overall
+ // size.
+ setSize(std::max(getSizeInBits(), (uint64_t)Context.toBits(PaddedFieldSize)));
+
// Finally, round the size of the record up to the alignment of the
// record itself.
uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit;
@@ -2693,7 +2738,8 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
auto FieldBitOffset = External.getExternalFieldOffset(FD);
placeFieldAtBitOffset(FieldBitOffset);
auto NewSize = Context.toCharUnitsFromBits(
- llvm::alignTo(FieldBitOffset + Width, Context.getCharWidth()));
+ llvm::alignDown(FieldBitOffset, Context.toBits(Info.Alignment)) +
+ Context.toBits(Info.Size));
Size = std::max(Size, NewSize);
Alignment = std::max(Alignment, Info.Alignment);
} else if (IsUnion) {
@@ -2742,12 +2788,17 @@ void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) {
CharUnits InjectionSite = VBPtrOffset;
// But before we do, make sure it's properly aligned.
VBPtrOffset = VBPtrOffset.alignTo(PointerInfo.Alignment);
+ // Determine where the first field should be laid out after the vbptr.
+ CharUnits FieldStart = VBPtrOffset + PointerInfo.Size;
// Shift everything after the vbptr down, unless we're using an external
// layout.
- if (UseExternalLayout)
+ if (UseExternalLayout) {
+ // It is possible that there were no fields or bases located after vbptr,
+ // so the size was not adjusted before.
+ if (Size < FieldStart)
+ Size = FieldStart;
return;
- // Determine where the first field should be laid out after the vbptr.
- CharUnits FieldStart = VBPtrOffset + PointerInfo.Size;
+ }
// Make sure that the amount we push the fields back by is a multiple of the
// alignment.
CharUnits Offset = (FieldStart - InjectionSite)
@@ -2772,8 +2823,14 @@ void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) {
if (HasVBPtr)
VBPtrOffset += Offset;
- if (UseExternalLayout)
+ if (UseExternalLayout) {
+ // The class may have no bases or fields, but still have a vfptr
+ // (e.g. it's an interface class). The size was not correctly set before
+ // in this case.
+ if (FieldOffsets.empty() && Bases.empty())
+ Size += Offset;
return;
+ }
Size += Offset;
@@ -3276,10 +3333,10 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD,
}
// Sort nvbases by offset.
- std::stable_sort(Bases.begin(), Bases.end(),
- [&](const CXXRecordDecl *L, const CXXRecordDecl *R) {
- return Layout.getBaseClassOffset(L) < Layout.getBaseClassOffset(R);
- });
+ llvm::stable_sort(
+ Bases, [&](const CXXRecordDecl *L, const CXXRecordDecl *R) {
+ return Layout.getBaseClassOffset(L) < Layout.getBaseClassOffset(R);
+ });
// Dump (non-virtual) bases
for (const CXXRecordDecl *Base : Bases) {
diff --git a/lib/AST/ScanfFormatString.cpp b/lib/AST/ScanfFormatString.cpp
index 08ba7a7a4f5c6..8d763f28e57fd 100644
--- a/lib/AST/ScanfFormatString.cpp
+++ b/lib/AST/ScanfFormatString.cpp
@@ -1,9 +1,8 @@
//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -143,7 +142,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
// Look for the length modifier.
- if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {
+ if (ParseLengthModifier(FS, I, E, LO, /*IsScanf=*/true) && I == E) {
// No more characters left?
H.HandleIncompleteSpecifier(Start, E - Start);
return true;
@@ -262,9 +261,10 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsInt32:
case LengthModifier::AsInt3264:
case LengthModifier::AsWide:
+ case LengthModifier::AsShortLong:
return ArgType::Invalid();
}
- llvm_unreachable("Unsupported LenghtModifier Type");
+ llvm_unreachable("Unsupported LengthModifier Type");
// Unsigned int.
case ConversionSpecifier::oArg:
@@ -302,9 +302,10 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsInt32:
case LengthModifier::AsInt3264:
case LengthModifier::AsWide:
+ case LengthModifier::AsShortLong:
return ArgType::Invalid();
}
- llvm_unreachable("Unsupported LenghtModifier Type");
+ llvm_unreachable("Unsupported LengthModifier Type");
// Float.
case ConversionSpecifier::aArg:
@@ -397,6 +398,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsInt32:
case LengthModifier::AsInt3264:
case LengthModifier::AsWide:
+ case LengthModifier::AsShortLong:
return ArgType::Invalid();
}
@@ -502,7 +504,7 @@ bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
namedTypeToLengthModifier(PT, LM);
// If fixing the length modifier was enough, we are done.
- if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
const analyze_scanf::ArgType &AT = getArgType(Ctx);
if (AT.isValid() && AT.matchesType(Ctx, QT))
return true;
diff --git a/lib/AST/SelectorLocationsKind.cpp b/lib/AST/SelectorLocationsKind.cpp
index 8b72c85d7ef70..2c34c9c60c2b2 100644
--- a/lib/AST/SelectorLocationsKind.cpp
+++ b/lib/AST/SelectorLocationsKind.cpp
@@ -1,9 +1,8 @@
//===--- SelectorLocationsKind.cpp - Kind of selector locations -*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 116291bfa1efb..0a4d403106bd4 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -1,9 +1,8 @@
//===- Stmt.cpp - Statement AST Node Implementation -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -118,30 +117,6 @@ void Stmt::EnableStatistics() {
StatisticsEnabled = true;
}
-Stmt *Stmt::IgnoreImplicit() {
- Stmt *s = this;
-
- Stmt *lasts = nullptr;
-
- while (s != lasts) {
- lasts = s;
-
- if (auto *fe = dyn_cast<FullExpr>(s))
- s = fe->getSubExpr();
-
- if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s))
- s = mte->GetTemporaryExpr();
-
- if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s))
- s = bte->getSubExpr();
-
- if (auto *ice = dyn_cast<ImplicitCastExpr>(s))
- s = ice->getSubExpr();
- }
-
- return s;
-}
-
/// Skip no-op (attributed, compound) container stmts and skip captured
/// stmt at the top, if \a IgnoreCaptured is true.
Stmt *Stmt::IgnoreContainers(bool IgnoreCaptured) {
@@ -345,6 +320,23 @@ CompoundStmt *CompoundStmt::CreateEmpty(const ASTContext &C,
return New;
}
+const Expr *ValueStmt::getExprStmt() const {
+ const Stmt *S = this;
+ do {
+ if (const auto *E = dyn_cast<Expr>(S))
+ return E;
+
+ if (const auto *LS = dyn_cast<LabelStmt>(S))
+ S = LS->getSubStmt();
+ else if (const auto *AS = dyn_cast<AttributedStmt>(S))
+ S = AS->getSubStmt();
+ else
+ llvm_unreachable("unknown kind of ValueStmt");
+ } while (isa<ValueStmt>(S));
+
+ return nullptr;
+}
+
const char *LabelStmt::getName() const {
return getDecl()->getIdentifier()->getNameStart();
}
@@ -452,6 +444,14 @@ void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) {
Exprs[i + NumOutputs] = E;
}
+AddrLabelExpr *GCCAsmStmt::getLabelExpr(unsigned i) const {
+ return cast<AddrLabelExpr>(Exprs[i + NumInputs]);
+}
+
+StringRef GCCAsmStmt::getLabelName(unsigned i) const {
+ return getLabelExpr(i)->getLabel()->getName();
+}
+
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
StringRef GCCAsmStmt::getInputConstraint(unsigned i) const {
@@ -464,13 +464,16 @@ void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C,
Stmt **Exprs,
unsigned NumOutputs,
unsigned NumInputs,
+ unsigned NumLabels,
StringLiteral **Clobbers,
unsigned NumClobbers) {
this->NumOutputs = NumOutputs;
this->NumInputs = NumInputs;
this->NumClobbers = NumClobbers;
+ this->NumLabels = NumLabels;
+ assert(!(NumOutputs && NumLabels) && "asm goto cannot have outputs");
- unsigned NumExprs = NumOutputs + NumInputs;
+ unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
C.Deallocate(this->Names);
this->Names = new (C) IdentifierInfo*[NumExprs];
@@ -480,9 +483,10 @@ void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C,
this->Exprs = new (C) Stmt*[NumExprs];
std::copy(Exprs, Exprs + NumExprs, this->Exprs);
+ unsigned NumConstraints = NumOutputs + NumInputs;
C.Deallocate(this->Constraints);
- this->Constraints = new (C) StringLiteral*[NumExprs];
- std::copy(Constraints, Constraints + NumExprs, this->Constraints);
+ this->Constraints = new (C) StringLiteral*[NumConstraints];
+ std::copy(Constraints, Constraints + NumConstraints, this->Constraints);
C.Deallocate(this->Clobbers);
this->Clobbers = new (C) StringLiteral*[NumClobbers];
@@ -505,6 +509,10 @@ int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const {
if (getInputName(i) == SymbolicName)
return getNumOutputs() + NumPlusOperands + i;
+ for (unsigned i = 0, e = getNumLabels(); i != e; ++i)
+ if (getLabelName(i) == SymbolicName)
+ return i + getNumInputs();
+
// Not found.
return -1;
}
@@ -622,8 +630,8 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
while (CurPtr != StrEnd && isDigit(*CurPtr))
N = N*10 + ((*CurPtr++)-'0');
- unsigned NumOperands =
- getNumOutputs() + getNumPlusOperands() + getNumInputs();
+ unsigned NumOperands = getNumOutputs() + getNumPlusOperands() +
+ getNumInputs() + getNumLabels();
if (N >= NumOperands) {
DiagOffs = CurPtr-StrStart-1;
return diag::err_asm_invalid_operand_number;
@@ -736,10 +744,12 @@ GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc,
unsigned numinputs, IdentifierInfo **names,
StringLiteral **constraints, Expr **exprs,
StringLiteral *asmstr, unsigned numclobbers,
- StringLiteral **clobbers, SourceLocation rparenloc)
+ StringLiteral **clobbers, unsigned numlabels,
+ SourceLocation rparenloc)
: AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
- numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) {
- unsigned NumExprs = NumOutputs + NumInputs;
+ numinputs, numclobbers),
+ RParenLoc(rparenloc), AsmStr(asmstr), NumLabels(numlabels) {
+ unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
Names = new (C) IdentifierInfo*[NumExprs];
std::copy(names, names + NumExprs, Names);
@@ -747,8 +757,9 @@ GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc,
Exprs = new (C) Stmt*[NumExprs];
std::copy(exprs, exprs + NumExprs, Exprs);
- Constraints = new (C) StringLiteral*[NumExprs];
- std::copy(constraints, constraints + NumExprs, Constraints);
+ unsigned NumConstraints = NumOutputs + NumInputs;
+ Constraints = new (C) StringLiteral*[NumConstraints];
+ std::copy(constraints, constraints + NumConstraints, Constraints);
Clobbers = new (C) StringLiteral*[NumClobbers];
std::copy(clobbers, clobbers + NumClobbers, Clobbers);
@@ -1262,6 +1273,10 @@ Stmt::child_range CapturedStmt::children() {
return child_range(getStoredStmts(), getStoredStmts() + NumCaptures);
}
+Stmt::const_child_range CapturedStmt::children() const {
+ return const_child_range(getStoredStmts(), getStoredStmts() + NumCaptures);
+}
+
CapturedDecl *CapturedStmt::getCapturedDecl() {
return CapDeclAndKind.getPointer();
}
diff --git a/lib/AST/StmtCXX.cpp b/lib/AST/StmtCXX.cpp
index 12367f8fd54b3..060d090fc06ac 100644
--- a/lib/AST/StmtCXX.cpp
+++ b/lib/AST/StmtCXX.cpp
@@ -1,9 +1,8 @@
//===--- StmtCXX.cpp - Classes for representing C++ statements ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
index 00056e83af2c0..70c8dc94e2df6 100644
--- a/lib/AST/StmtIterator.cpp
+++ b/lib/AST/StmtIterator.cpp
@@ -1,9 +1,8 @@
//===- StmtIterator.cpp - Iterators for Statements ------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/StmtObjC.cpp b/lib/AST/StmtObjC.cpp
index ed21e2d0d2b6b..3d586795517c4 100644
--- a/lib/AST/StmtObjC.cpp
+++ b/lib/AST/StmtObjC.cpp
@@ -1,9 +1,8 @@
//===--- StmtObjC.cpp - Classes for representing ObjC statements ---------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/StmtOpenMP.cpp b/lib/AST/StmtOpenMP.cpp
index 85a2daa0801af..4e829897cebe6 100644
--- a/lib/AST/StmtOpenMP.cpp
+++ b/lib/AST/StmtOpenMP.cpp
@@ -1,9 +1,8 @@
//===--- StmtOpenMP.cpp - Classes for OpenMP directives -------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -23,6 +22,25 @@ void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) {
std::copy(Clauses.begin(), Clauses.end(), getClauses().begin());
}
+bool OMPExecutableDirective::isStandaloneDirective() const {
+ // Special case: 'omp target enter data', 'omp target exit data',
+ // 'omp target update' are stand-alone directives, but for implementation
+ // reasons they have empty synthetic structured block, to simplify codegen.
+ if (isa<OMPTargetEnterDataDirective>(this) ||
+ isa<OMPTargetExitDataDirective>(this) ||
+ isa<OMPTargetUpdateDirective>(this))
+ return true;
+ return !hasAssociatedStmt() || !getAssociatedStmt();
+}
+
+const Stmt *OMPExecutableDirective::getStructuredBlock() const {
+ assert(!isStandaloneDirective() &&
+ "Standalone Executable Directives don't have Structured Blocks.");
+ if (auto *LD = dyn_cast<OMPLoopDirective>(this))
+ return LD->getBody();
+ return getInnermostCapturedStmt()->getCapturedStmt();
+}
+
void OMPLoopDirective::setCounters(ArrayRef<Expr *> A) {
assert(A.size() == getCollapsedNumber() &&
"Number of loop counters is not the same as the collapsed number");
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index ae726e3871076..46802d765e1f0 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1,9 +1,8 @@
//===- StmtPrinter.cpp - Printing implementation for Stmt ASTs ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -37,6 +36,7 @@
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/ExpressionTraits.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/JsonSupport.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Lambda.h"
#include "clang/Basic/OpenMPKinds.h"
@@ -414,12 +414,15 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
if (Node->isVolatile())
OS << "volatile ";
+ if (Node->isAsmGoto())
+ OS << "goto ";
+
OS << "(";
VisitStringLiteral(Node->getAsmString());
// Outputs
if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 ||
- Node->getNumClobbers() != 0)
+ Node->getNumClobbers() != 0 || Node->getNumLabels() != 0)
OS << " : ";
for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) {
@@ -439,7 +442,8 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
}
// Inputs
- if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0)
+ if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0 ||
+ Node->getNumLabels() != 0)
OS << " : ";
for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) {
@@ -459,7 +463,7 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
}
// Clobbers
- if (Node->getNumClobbers() != 0)
+ if (Node->getNumClobbers() != 0 || Node->getNumLabels())
OS << " : ";
for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) {
@@ -469,6 +473,16 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
VisitStringLiteral(Node->getClobberStringLiteral(i));
}
+ // Labels
+ if (Node->getNumLabels() != 0)
+ OS << " : ";
+
+ for (unsigned i = 0, e = Node->getNumLabels(); i != e; ++i) {
+ if (i != 0)
+ OS << ", ";
+ OS << Node->getLabelName(i);
+ }
+
OS << ");";
if (Policy.IncludeNewlines) OS << NL;
}
@@ -906,6 +920,10 @@ void StmtPrinter::VisitOMPTargetTeamsDistributeSimdDirective(
// Expr printing methods.
//===----------------------------------------------------------------------===//
+void StmtPrinter::VisitSourceLocExpr(SourceLocExpr *Node) {
+ OS << Node->getBuiltinStr() << "()";
+}
+
void StmtPrinter::VisitConstantExpr(ConstantExpr *Node) {
PrintExpr(Node->getSubExpr());
}
@@ -1262,15 +1280,15 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
OS << "_Generic(";
PrintExpr(Node->getControllingExpr());
- for (unsigned i = 0; i != Node->getNumAssocs(); ++i) {
+ for (const GenericSelectionExpr::Association &Assoc : Node->associations()) {
OS << ", ";
- QualType T = Node->getAssocType(i);
+ QualType T = Assoc.getType();
if (T.isNull())
OS << "default";
else
T.print(OS, Policy);
OS << ": ";
- PrintExpr(Node->getAssocExpr(i));
+ PrintExpr(Assoc.getAssociationExpr());
}
OS << ")";
}
@@ -1604,21 +1622,14 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
// C++
void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
- const char *OpStrings[NUM_OVERLOADED_OPERATORS] = {
- "",
-#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
- Spelling,
-#include "clang/Basic/OperatorKinds.def"
- };
-
OverloadedOperatorKind Kind = Node->getOperator();
if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) {
if (Node->getNumArgs() == 1) {
- OS << OpStrings[Kind] << ' ';
+ OS << getOperatorSpelling(Kind) << ' ';
PrintExpr(Node->getArg(0));
} else {
PrintExpr(Node->getArg(0));
- OS << ' ' << OpStrings[Kind];
+ OS << ' ' << getOperatorSpelling(Kind);
}
} else if (Kind == OO_Arrow) {
PrintExpr(Node->getArg(0));
@@ -1638,11 +1649,11 @@ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
PrintExpr(Node->getArg(1));
OS << ']';
} else if (Node->getNumArgs() == 1) {
- OS << OpStrings[Kind] << ' ';
+ OS << getOperatorSpelling(Kind) << ' ';
PrintExpr(Node->getArg(0));
} else if (Node->getNumArgs() == 2) {
PrintExpr(Node->getArg(0));
- OS << ' ' << OpStrings[Kind] << ' ';
+ OS << ' ' << getOperatorSpelling(Kind) << ' ';
PrintExpr(Node->getArg(1));
} else {
llvm_unreachable("unknown overloaded operator");
@@ -1692,6 +1703,14 @@ void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) {
VisitCXXNamedCastExpr(Node);
}
+void StmtPrinter::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *Node) {
+ OS << "__builtin_bit_cast(";
+ Node->getTypeInfoAsWritten()->getType().print(OS, Policy);
+ OS << ", ";
+ PrintExpr(Node->getSubExpr());
+ OS << ")";
+}
+
void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
OS << "typeid(";
if (Node->isTypeOperand()) {
@@ -1896,13 +1915,22 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
llvm_unreachable("VLA type in explicit captures.");
}
+ if (C->isPackExpansion())
+ OS << "...";
+
if (Node->isInitCapture(C))
PrintExpr(C->getCapturedVar()->getInit());
}
OS << ']';
+ if (!Node->getExplicitTemplateParameters().empty()) {
+ Node->getTemplateParameterList()->print(
+ OS, Node->getLambdaClass()->getASTContext(),
+ /*OmitTemplateKW*/true);
+ }
+
if (Node->hasExplicitParameters()) {
- OS << " (";
+ OS << '(';
CXXMethodDecl *Method = Node->getCallOperator();
NeedComma = false;
for (const auto *P : Method->parameters()) {
@@ -1937,9 +1965,11 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
}
// Print the body.
- CompoundStmt *Body = Node->getBody();
OS << ' ';
- PrintStmt(Body);
+ if (Policy.TerseOutput)
+ OS << "{}";
+ else
+ PrintRawCompoundStmt(Node->getBody());
}
void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
@@ -1969,10 +1999,11 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
if (E->isParenTypeId())
OS << "(";
std::string TypeS;
- if (Expr *Size = E->getArraySize()) {
+ if (Optional<Expr *> Size = E->getArraySize()) {
llvm::raw_string_ostream s(TypeS);
s << '[';
- Size->printPretty(s, Helper, Policy);
+ if (*Size)
+ (*Size)->printPretty(s, Helper, Policy);
s << ']';
}
E->getAllocatedType().print(OS, Policy, TypeS);
@@ -2380,12 +2411,21 @@ void Stmt::dumpPretty(const ASTContext &Context) const {
printPretty(llvm::errs(), nullptr, PrintingPolicy(Context.getLangOpts()));
}
-void Stmt::printPretty(raw_ostream &OS, PrinterHelper *Helper,
+void Stmt::printPretty(raw_ostream &Out, PrinterHelper *Helper,
const PrintingPolicy &Policy, unsigned Indentation,
- StringRef NL,
- const ASTContext *Context) const {
- StmtPrinter P(OS, Helper, Policy, Indentation, NL, Context);
- P.Visit(const_cast<Stmt*>(this));
+ StringRef NL, const ASTContext *Context) const {
+ StmtPrinter P(Out, Helper, Policy, Indentation, NL, Context);
+ P.Visit(const_cast<Stmt *>(this));
+}
+
+void Stmt::printJson(raw_ostream &Out, PrinterHelper *Helper,
+ const PrintingPolicy &Policy, bool AddQuotes) const {
+ std::string Buf;
+ llvm::raw_string_ostream TempOut(Buf);
+
+ printPretty(TempOut, Helper, Policy);
+
+ Out << JsonFormat(TempOut.str(), AddQuotes);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index ec4dac03d4974..f92c3dc60ba5c 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -1,9 +1,8 @@
//===---- StmtProfile.cpp - Profile implementation for Stmt ASTs ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -322,6 +321,9 @@ void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) {
ID.AddInteger(S->getNumClobbers());
for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
VisitStringLiteral(S->getClobberStringLiteral(I));
+ ID.AddInteger(S->getNumLabels());
+ for (auto *L : S->labels())
+ VisitDecl(L->getLabel());
}
void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) {
@@ -458,6 +460,11 @@ void OMPClauseProfiler::VisitOMPSimdlenClause(const OMPSimdlenClause *C) {
Profiler->VisitStmt(C->getSimdlen());
}
+void OMPClauseProfiler::VisitOMPAllocatorClause(const OMPAllocatorClause *C) {
+ if (C->getAllocator())
+ Profiler->VisitStmt(C->getAllocator());
+}
+
void OMPClauseProfiler::VisitOMPCollapseClause(const OMPCollapseClause *C) {
if (C->getNumForLoops())
Profiler->VisitStmt(C->getNumForLoops());
@@ -712,6 +719,11 @@ void OMPClauseProfiler::VisitOMPDeviceClause(const OMPDeviceClause *C) {
void OMPClauseProfiler::VisitOMPMapClause(const OMPMapClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseProfiler::VisitOMPAllocateClause(const OMPAllocateClause *C) {
+ if (Expr *Allocator = C->getAllocator())
+ Profiler->VisitStmt(Allocator);
+ VisitOMPClauseList(C);
+}
void OMPClauseProfiler::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) {
VistOMPClauseWithPreInit(C);
if (C->getNumTeams())
@@ -1260,13 +1272,14 @@ void StmtProfiler::VisitBlockExpr(const BlockExpr *S) {
void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) {
VisitExpr(S);
- for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
- QualType T = S->getAssocType(i);
+ for (const GenericSelectionExpr::ConstAssociation &Assoc :
+ S->associations()) {
+ QualType T = Assoc.getType();
if (T.isNull())
ID.AddPointer(nullptr);
else
VisitType(T);
- VisitExpr(S->getAssocExpr(i));
+ VisitExpr(Assoc.getAssociationExpr());
}
}
@@ -1556,6 +1569,11 @@ void StmtProfiler::VisitCXXConstCastExpr(const CXXConstCastExpr *S) {
VisitCXXNamedCastExpr(S);
}
+void StmtProfiler::VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *S) {
+ VisitExpr(S);
+ VisitType(S->getTypeInfoAsWritten()->getType());
+}
+
void StmtProfiler::VisitUserDefinedLiteral(const UserDefinedLiteral *S) {
VisitCallExpr(S);
}
@@ -1872,6 +1890,10 @@ void StmtProfiler::VisitTypoExpr(const TypoExpr *E) {
VisitExpr(E);
}
+void StmtProfiler::VisitSourceLocExpr(const SourceLocExpr *E) {
+ VisitExpr(E);
+}
+
void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) {
VisitExpr(S);
}
diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp
index 8be287e7cb217..4eb0da8a0e105 100644
--- a/lib/AST/StmtViz.cpp
+++ b/lib/AST/StmtViz.cpp
@@ -1,9 +1,8 @@
//===--- StmtViz.cpp - Graphviz visualization for Stmt ASTs -----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index a78927d229b9f..cb4cbd2f76a12 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -1,9 +1,8 @@
//===- TemplateBase.cpp - Common template AST class implementation --------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index 0a7a6bc3c6a7a..06e1dcec74492 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -1,9 +1,8 @@
//===- TemplateName.cpp - C++ Template Name Representation ----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -67,6 +66,8 @@ TemplateName::TemplateName(void *Ptr) {
TemplateName::TemplateName(TemplateDecl *Template) : Storage(Template) {}
TemplateName::TemplateName(OverloadedTemplateStorage *Storage)
: Storage(Storage) {}
+TemplateName::TemplateName(AssumedTemplateStorage *Storage)
+ : Storage(Storage) {}
TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage)
: Storage(Storage) {}
TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage)
@@ -88,6 +89,8 @@ TemplateName::NameKind TemplateName::getKind() const {
= Storage.get<UncommonTemplateNameStorage*>();
if (uncommon->getAsOverloadedStorage())
return OverloadedTemplate;
+ if (uncommon->getAsAssumedTemplateName())
+ return AssumedTemplate;
if (uncommon->getAsSubstTemplateTemplateParm())
return SubstTemplateTemplateParm;
return SubstTemplateTemplateParmPack;
@@ -114,6 +117,14 @@ OverloadedTemplateStorage *TemplateName::getAsOverloadedTemplate() const {
return nullptr;
}
+AssumedTemplateStorage *TemplateName::getAsAssumedTemplateName() const {
+ if (UncommonTemplateNameStorage *Uncommon =
+ Storage.dyn_cast<UncommonTemplateNameStorage *>())
+ return Uncommon->getAsAssumedTemplateName();
+
+ return nullptr;
+}
+
SubstTemplateTemplateParmStorage *
TemplateName::getAsSubstTemplateTemplateParm() const {
if (UncommonTemplateNameStorage *uncommon =
@@ -231,7 +242,9 @@ TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
} else if (SubstTemplateTemplateParmPackStorage *SubstPack
= getAsSubstTemplateTemplateParmPack())
OS << *SubstPack->getParameterPack();
- else {
+ else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {
+ Assumed->getDeclName().print(OS, Policy);
+ } else {
OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
(*OTS->begin())->printName(OS);
}
@@ -251,6 +264,20 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
return DB << NameStr;
}
+const PartialDiagnostic&clang::operator<<(const PartialDiagnostic &PD,
+ TemplateName N) {
+ std::string NameStr;
+ llvm::raw_string_ostream OS(NameStr);
+ LangOptions LO;
+ LO.CPlusPlus = true;
+ LO.Bool = true;
+ OS << '\'';
+ N.print(OS, PrintingPolicy(LO));
+ OS << '\'';
+ OS.flush();
+ return PD << NameStr;
+}
+
void TemplateName::dump(raw_ostream &OS) const {
LangOptions LO; // FIXME!
LO.CPlusPlus = true;
diff --git a/lib/AST/TextNodeDumper.cpp b/lib/AST/TextNodeDumper.cpp
index b51a9006226ae..cba9091b10652 100644
--- a/lib/AST/TextNodeDumper.cpp
+++ b/lib/AST/TextNodeDumper.cpp
@@ -1,9 +1,8 @@
//===--- TextNodeDumper.cpp - Printing of AST nodes -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -122,6 +121,9 @@ void TextNodeDumper::Visit(const Stmt *Node) {
dumpPointer(Node);
dumpSourceRange(Node->getSourceRange());
+ if (Node->isOMPStructuredBlock())
+ OS << " openmp_structured_block";
+
if (const auto *E = dyn_cast<Expr>(Node)) {
dumpType(E->getType());
@@ -221,6 +223,7 @@ void TextNodeDumper::Visit(const Decl *D) {
return;
}
+ Context = &D->getASTContext();
{
ColorScope Color(OS, ShowColors, DeclKindNameColor);
OS << D->getDeclKindName() << "Decl";
@@ -253,9 +256,25 @@ void TextNodeDumper::Visit(const Decl *D) {
if (D->isInvalidDecl())
OS << " invalid";
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- if (FD->isConstexpr())
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isConstexprSpecified())
OS << " constexpr";
+ if (FD->isConsteval())
+ OS << " consteval";
+ }
+
+ if (!isa<FunctionDecl>(*D)) {
+ const auto *MD = dyn_cast<ObjCMethodDecl>(D);
+ if (!MD || !MD->isThisDeclarationADefinition()) {
+ const auto *DC = dyn_cast<DeclContext>(D);
+ if (DC && DC->hasExternalLexicalStorage()) {
+ ColorScope Color(OS, ShowColors, UndeserializedColor);
+ OS << " <undeserialized declarations>";
+ }
+ }
+ }
+
+ ConstDeclVisitor<TextNodeDumper>::Visit(D);
}
void TextNodeDumper::Visit(const CXXCtorInitializer *Init) {
@@ -302,6 +321,19 @@ void TextNodeDumper::Visit(const OMPClause *C) {
OS << " <implicit>";
}
+void TextNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) {
+ const TypeSourceInfo *TSI = A.getTypeSourceInfo();
+ if (TSI) {
+ OS << "case ";
+ dumpType(TSI->getType());
+ } else {
+ OS << "default";
+ }
+
+ if (A.isSelected())
+ OS << " selected";
+}
+
void TextNodeDumper::dumpPointer(const void *Ptr) {
ColorScope Color(OS, ShowColors, AddressColor);
OS << ' ' << Ptr;
@@ -416,12 +448,6 @@ void TextNodeDumper::dumpAccessSpecifier(AccessSpecifier AS) {
}
}
-void TextNodeDumper::dumpCXXTemporary(const CXXTemporary *Temporary) {
- OS << "(CXXTemporary";
- dumpPointer(Temporary);
- OS << ")";
-}
-
void TextNodeDumper::dumpDeclRef(const Decl *D, StringRef Label) {
if (!D)
return;
@@ -658,6 +684,14 @@ void TextNodeDumper::VisitCaseStmt(const CaseStmt *Node) {
OS << " gnu_range";
}
+void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) {
+ if (Node->getResultAPValueKind() != APValue::None) {
+ ColorScope Color(OS, ShowColors, ValueColor);
+ OS << " ";
+ Node->getAPValueResult().printPretty(OS, *Context, Node->getType());
+ }
+}
+
void TextNodeDumper::VisitCallExpr(const CallExpr *Node) {
if (Node->usesADL())
OS << " adl";
@@ -687,6 +721,12 @@ void TextNodeDumper::VisitDeclRefExpr(const DeclRefExpr *Node) {
dumpBareDeclRef(Node->getFoundDecl());
OS << ")";
}
+ switch (Node->isNonOdrUse()) {
+ case NOUR_None: break;
+ case NOUR_Unevaluated: OS << " non_odr_use_unevaluated"; break;
+ case NOUR_Constant: OS << " non_odr_use_constant"; break;
+ case NOUR_Discarded: OS << " non_odr_use_discarded"; break;
+ }
}
void TextNodeDumper::VisitUnresolvedLookupExpr(
@@ -753,6 +793,11 @@ void TextNodeDumper::VisitInitListExpr(const InitListExpr *ILE) {
}
}
+void TextNodeDumper::VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
+ if (E->isResultDependent())
+ OS << " result_dependent";
+}
+
void TextNodeDumper::VisitUnaryOperator(const UnaryOperator *Node) {
OS << " " << (Node->isPostfix() ? "postfix" : "prefix") << " '"
<< UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
@@ -786,6 +831,12 @@ void TextNodeDumper::VisitUnaryExprOrTypeTraitExpr(
void TextNodeDumper::VisitMemberExpr(const MemberExpr *Node) {
OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl();
dumpPointer(Node->getMemberDecl());
+ switch (Node->isNonOdrUse()) {
+ case NOUR_None: break;
+ case NOUR_Unevaluated: OS << " non_odr_use_unevaluated"; break;
+ case NOUR_Constant: OS << " non_odr_use_constant"; break;
+ case NOUR_Discarded: OS << " non_odr_use_discarded"; break;
+ }
}
void TextNodeDumper::VisitExtVectorElementExpr(
@@ -824,6 +875,8 @@ void TextNodeDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) {
}
void TextNodeDumper::VisitCXXThisExpr(const CXXThisExpr *Node) {
+ if (Node->isImplicit())
+ OS << " implicit";
OS << " this";
}
@@ -855,8 +908,9 @@ void TextNodeDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) {
void TextNodeDumper::VisitCXXBindTemporaryExpr(
const CXXBindTemporaryExpr *Node) {
- OS << " ";
- dumpCXXTemporary(Node->getTemporary());
+ OS << " (CXXTemporary";
+ dumpPointer(Node);
+ OS << ")";
}
void TextNodeDumper::VisitCXXNewExpr(const CXXNewExpr *Node) {
@@ -1096,6 +1150,8 @@ void TextNodeDumper::VisitFunctionProtoType(const FunctionProtoType *T) {
OS << " volatile";
if (T->isRestrict())
OS << " restrict";
+ if (T->getExtProtoInfo().Variadic)
+ OS << " variadic";
switch (EPI.RefQualifier) {
case RQ_None:
break;
@@ -1166,3 +1222,721 @@ void TextNodeDumper::VisitPackExpansionType(const PackExpansionType *T) {
if (auto N = T->getNumExpansions())
OS << " expansions " << *N;
}
+
+void TextNodeDumper::VisitLabelDecl(const LabelDecl *D) { dumpName(D); }
+
+void TextNodeDumper::VisitTypedefDecl(const TypedefDecl *D) {
+ dumpName(D);
+ dumpType(D->getUnderlyingType());
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+}
+
+void TextNodeDumper::VisitEnumDecl(const EnumDecl *D) {
+ if (D->isScoped()) {
+ if (D->isScopedUsingClassTag())
+ OS << " class";
+ else
+ OS << " struct";
+ }
+ dumpName(D);
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+ if (D->isFixed())
+ dumpType(D->getIntegerType());
+}
+
+void TextNodeDumper::VisitRecordDecl(const RecordDecl *D) {
+ OS << ' ' << D->getKindName();
+ dumpName(D);
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+ if (D->isCompleteDefinition())
+ OS << " definition";
+}
+
+void TextNodeDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+}
+
+void TextNodeDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+
+ for (const auto *Child : D->chain())
+ dumpDeclRef(Child);
+}
+
+void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+
+ StorageClass SC = D->getStorageClass();
+ if (SC != SC_None)
+ OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
+ if (D->isInlineSpecified())
+ OS << " inline";
+ if (D->isVirtualAsWritten())
+ OS << " virtual";
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+
+ if (D->isPure())
+ OS << " pure";
+ if (D->isDefaulted()) {
+ OS << " default";
+ if (D->isDeleted())
+ OS << "_delete";
+ }
+ if (D->isDeletedAsWritten())
+ OS << " delete";
+ if (D->isTrivial())
+ OS << " trivial";
+
+ if (const auto *FPT = D->getType()->getAs<FunctionProtoType>()) {
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ switch (EPI.ExceptionSpec.Type) {
+ default:
+ break;
+ case EST_Unevaluated:
+ OS << " noexcept-unevaluated " << EPI.ExceptionSpec.SourceDecl;
+ break;
+ case EST_Uninstantiated:
+ OS << " noexcept-uninstantiated " << EPI.ExceptionSpec.SourceTemplate;
+ break;
+ }
+ }
+
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
+ if (MD->size_overridden_methods() != 0) {
+ auto dumpOverride = [=](const CXXMethodDecl *D) {
+ SplitQualType T_split = D->getType().split();
+ OS << D << " " << D->getParent()->getName()
+ << "::" << D->getNameAsString() << " '"
+ << QualType::getAsString(T_split, PrintPolicy) << "'";
+ };
+
+ AddChild([=] {
+ auto Overrides = MD->overridden_methods();
+ OS << "Overrides: [ ";
+ dumpOverride(*Overrides.begin());
+ for (const auto *Override :
+ llvm::make_range(Overrides.begin() + 1, Overrides.end())) {
+ OS << ", ";
+ dumpOverride(Override);
+ }
+ OS << " ]";
+ });
+ }
+ }
+
+ // Since NumParams comes from the FunctionProtoType of the FunctionDecl and
+ // the Params are set later, it is possible for a dump during debugging to
+ // encounter a FunctionDecl that has been created but hasn't been assigned
+ // ParmVarDecls yet.
+ if (!D->param_empty() && !D->param_begin())
+ OS << " <<<NULL params x " << D->getNumParams() << ">>>";
+}
+
+void TextNodeDumper::VisitFieldDecl(const FieldDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (D->isMutable())
+ OS << " mutable";
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+}
+
+void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ StorageClass SC = D->getStorageClass();
+ if (SC != SC_None)
+ OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
+ switch (D->getTLSKind()) {
+ case VarDecl::TLS_None:
+ break;
+ case VarDecl::TLS_Static:
+ OS << " tls";
+ break;
+ case VarDecl::TLS_Dynamic:
+ OS << " tls_dynamic";
+ break;
+ }
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+ if (D->isNRVOVariable())
+ OS << " nrvo";
+ if (D->isInline())
+ OS << " inline";
+ if (D->isConstexpr())
+ OS << " constexpr";
+ if (D->hasInit()) {
+ switch (D->getInitStyle()) {
+ case VarDecl::CInit:
+ OS << " cinit";
+ break;
+ case VarDecl::CallInit:
+ OS << " callinit";
+ break;
+ case VarDecl::ListInit:
+ OS << " listinit";
+ break;
+ }
+ }
+ if (D->isParameterPack())
+ OS << " pack";
+}
+
+void TextNodeDumper::VisitBindingDecl(const BindingDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+}
+
+void TextNodeDumper::VisitCapturedDecl(const CapturedDecl *D) {
+ if (D->isNothrow())
+ OS << " nothrow";
+}
+
+void TextNodeDumper::VisitImportDecl(const ImportDecl *D) {
+ OS << ' ' << D->getImportedModule()->getFullModuleName();
+
+ for (Decl *InitD :
+ D->getASTContext().getModuleInitializers(D->getImportedModule()))
+ dumpDeclRef(InitD, "initializer");
+}
+
+void TextNodeDumper::VisitPragmaCommentDecl(const PragmaCommentDecl *D) {
+ OS << ' ';
+ switch (D->getCommentKind()) {
+ case PCK_Unknown:
+ llvm_unreachable("unexpected pragma comment kind");
+ case PCK_Compiler:
+ OS << "compiler";
+ break;
+ case PCK_ExeStr:
+ OS << "exestr";
+ break;
+ case PCK_Lib:
+ OS << "lib";
+ break;
+ case PCK_Linker:
+ OS << "linker";
+ break;
+ case PCK_User:
+ OS << "user";
+ break;
+ }
+ StringRef Arg = D->getArg();
+ if (!Arg.empty())
+ OS << " \"" << Arg << "\"";
+}
+
+void TextNodeDumper::VisitPragmaDetectMismatchDecl(
+ const PragmaDetectMismatchDecl *D) {
+ OS << " \"" << D->getName() << "\" \"" << D->getValue() << "\"";
+}
+
+void TextNodeDumper::VisitOMPExecutableDirective(
+ const OMPExecutableDirective *D) {
+ if (D->isStandaloneDirective())
+ OS << " openmp_standalone_directive";
+}
+
+void TextNodeDumper::VisitOMPDeclareReductionDecl(
+ const OMPDeclareReductionDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ OS << " combiner";
+ dumpPointer(D->getCombiner());
+ if (const auto *Initializer = D->getInitializer()) {
+ OS << " initializer";
+ dumpPointer(Initializer);
+ switch (D->getInitializerKind()) {
+ case OMPDeclareReductionDecl::DirectInit:
+ OS << " omp_priv = ";
+ break;
+ case OMPDeclareReductionDecl::CopyInit:
+ OS << " omp_priv ()";
+ break;
+ case OMPDeclareReductionDecl::CallInit:
+ break;
+ }
+ }
+}
+
+void TextNodeDumper::VisitOMPRequiresDecl(const OMPRequiresDecl *D) {
+ for (const auto *C : D->clauselists()) {
+ AddChild([=] {
+ if (!C) {
+ ColorScope Color(OS, ShowColors, NullColor);
+ OS << "<<<NULL>>> OMPClause";
+ return;
+ }
+ {
+ ColorScope Color(OS, ShowColors, AttrColor);
+ StringRef ClauseName(getOpenMPClauseName(C->getClauseKind()));
+ OS << "OMP" << ClauseName.substr(/*Start=*/0, /*N=*/1).upper()
+ << ClauseName.drop_front() << "Clause";
+ }
+ dumpPointer(C);
+ dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc()));
+ });
+ }
+}
+
+void TextNodeDumper::VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+}
+
+void TextNodeDumper::VisitNamespaceDecl(const NamespaceDecl *D) {
+ dumpName(D);
+ if (D->isInline())
+ OS << " inline";
+ if (!D->isOriginalNamespace())
+ dumpDeclRef(D->getOriginalNamespace(), "original");
+}
+
+void TextNodeDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
+ OS << ' ';
+ dumpBareDeclRef(D->getNominatedNamespace());
+}
+
+void TextNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getAliasedNamespace());
+}
+
+void TextNodeDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) {
+ dumpName(D);
+ dumpType(D->getUnderlyingType());
+}
+
+void TextNodeDumper::VisitTypeAliasTemplateDecl(
+ const TypeAliasTemplateDecl *D) {
+ dumpName(D);
+}
+
+void TextNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
+ VisitRecordDecl(D);
+ if (!D->isCompleteDefinition())
+ return;
+
+ AddChild([=] {
+ {
+ ColorScope Color(OS, ShowColors, DeclKindNameColor);
+ OS << "DefinitionData";
+ }
+#define FLAG(fn, name) \
+ if (D->fn()) \
+ OS << " " #name;
+ FLAG(isParsingBaseSpecifiers, parsing_base_specifiers);
+
+ FLAG(isGenericLambda, generic);
+ FLAG(isLambda, lambda);
+
+ FLAG(canPassInRegisters, pass_in_registers);
+ FLAG(isEmpty, empty);
+ FLAG(isAggregate, aggregate);
+ FLAG(isStandardLayout, standard_layout);
+ FLAG(isTriviallyCopyable, trivially_copyable);
+ FLAG(isPOD, pod);
+ FLAG(isTrivial, trivial);
+ FLAG(isPolymorphic, polymorphic);
+ FLAG(isAbstract, abstract);
+ FLAG(isLiteral, literal);
+
+ FLAG(hasUserDeclaredConstructor, has_user_declared_ctor);
+ FLAG(hasConstexprNonCopyMoveConstructor, has_constexpr_non_copy_move_ctor);
+ FLAG(hasMutableFields, has_mutable_fields);
+ FLAG(hasVariantMembers, has_variant_members);
+ FLAG(allowConstDefaultInit, can_const_default_init);
+
+ AddChild([=] {
+ {
+ ColorScope Color(OS, ShowColors, DeclKindNameColor);
+ OS << "DefaultConstructor";
+ }
+ FLAG(hasDefaultConstructor, exists);
+ FLAG(hasTrivialDefaultConstructor, trivial);
+ FLAG(hasNonTrivialDefaultConstructor, non_trivial);
+ FLAG(hasUserProvidedDefaultConstructor, user_provided);
+ FLAG(hasConstexprDefaultConstructor, constexpr);
+ FLAG(needsImplicitDefaultConstructor, needs_implicit);
+ FLAG(defaultedDefaultConstructorIsConstexpr, defaulted_is_constexpr);
+ });
+
+ AddChild([=] {
+ {
+ ColorScope Color(OS, ShowColors, DeclKindNameColor);
+ OS << "CopyConstructor";
+ }
+ FLAG(hasSimpleCopyConstructor, simple);
+ FLAG(hasTrivialCopyConstructor, trivial);
+ FLAG(hasNonTrivialCopyConstructor, non_trivial);
+ FLAG(hasUserDeclaredCopyConstructor, user_declared);
+ FLAG(hasCopyConstructorWithConstParam, has_const_param);
+ FLAG(needsImplicitCopyConstructor, needs_implicit);
+ FLAG(needsOverloadResolutionForCopyConstructor,
+ needs_overload_resolution);
+ if (!D->needsOverloadResolutionForCopyConstructor())
+ FLAG(defaultedCopyConstructorIsDeleted, defaulted_is_deleted);
+ FLAG(implicitCopyConstructorHasConstParam, implicit_has_const_param);
+ });
+
+ AddChild([=] {
+ {
+ ColorScope Color(OS, ShowColors, DeclKindNameColor);
+ OS << "MoveConstructor";
+ }
+ FLAG(hasMoveConstructor, exists);
+ FLAG(hasSimpleMoveConstructor, simple);
+ FLAG(hasTrivialMoveConstructor, trivial);
+ FLAG(hasNonTrivialMoveConstructor, non_trivial);
+ FLAG(hasUserDeclaredMoveConstructor, user_declared);
+ FLAG(needsImplicitMoveConstructor, needs_implicit);
+ FLAG(needsOverloadResolutionForMoveConstructor,
+ needs_overload_resolution);
+ if (!D->needsOverloadResolutionForMoveConstructor())
+ FLAG(defaultedMoveConstructorIsDeleted, defaulted_is_deleted);
+ });
+
+ AddChild([=] {
+ {
+ ColorScope Color(OS, ShowColors, DeclKindNameColor);
+ OS << "CopyAssignment";
+ }
+ FLAG(hasTrivialCopyAssignment, trivial);
+ FLAG(hasNonTrivialCopyAssignment, non_trivial);
+ FLAG(hasCopyAssignmentWithConstParam, has_const_param);
+ FLAG(hasUserDeclaredCopyAssignment, user_declared);
+ FLAG(needsImplicitCopyAssignment, needs_implicit);
+ FLAG(needsOverloadResolutionForCopyAssignment, needs_overload_resolution);
+ FLAG(implicitCopyAssignmentHasConstParam, implicit_has_const_param);
+ });
+
+ AddChild([=] {
+ {
+ ColorScope Color(OS, ShowColors, DeclKindNameColor);
+ OS << "MoveAssignment";
+ }
+ FLAG(hasMoveAssignment, exists);
+ FLAG(hasSimpleMoveAssignment, simple);
+ FLAG(hasTrivialMoveAssignment, trivial);
+ FLAG(hasNonTrivialMoveAssignment, non_trivial);
+ FLAG(hasUserDeclaredMoveAssignment, user_declared);
+ FLAG(needsImplicitMoveAssignment, needs_implicit);
+ FLAG(needsOverloadResolutionForMoveAssignment, needs_overload_resolution);
+ });
+
+ AddChild([=] {
+ {
+ ColorScope Color(OS, ShowColors, DeclKindNameColor);
+ OS << "Destructor";
+ }
+ FLAG(hasSimpleDestructor, simple);
+ FLAG(hasIrrelevantDestructor, irrelevant);
+ FLAG(hasTrivialDestructor, trivial);
+ FLAG(hasNonTrivialDestructor, non_trivial);
+ FLAG(hasUserDeclaredDestructor, user_declared);
+ FLAG(needsImplicitDestructor, needs_implicit);
+ FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution);
+ if (!D->needsOverloadResolutionForDestructor())
+ FLAG(defaultedDestructorIsDeleted, defaulted_is_deleted);
+ });
+ });
+
+ for (const auto &I : D->bases()) {
+ AddChild([=] {
+ if (I.isVirtual())
+ OS << "virtual ";
+ dumpAccessSpecifier(I.getAccessSpecifier());
+ dumpType(I.getType());
+ if (I.isPackExpansion())
+ OS << "...";
+ });
+ }
+}
+
+void TextNodeDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
+ dumpName(D);
+}
+
+void TextNodeDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
+ dumpName(D);
+}
+
+void TextNodeDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
+ dumpName(D);
+}
+
+void TextNodeDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) {
+ dumpName(D);
+}
+
+void TextNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
+ if (D->wasDeclaredWithTypename())
+ OS << " typename";
+ else
+ OS << " class";
+ OS << " depth " << D->getDepth() << " index " << D->getIndex();
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+}
+
+void TextNodeDumper::VisitNonTypeTemplateParmDecl(
+ const NonTypeTemplateParmDecl *D) {
+ dumpType(D->getType());
+ OS << " depth " << D->getDepth() << " index " << D->getIndex();
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+}
+
+void TextNodeDumper::VisitTemplateTemplateParmDecl(
+ const TemplateTemplateParmDecl *D) {
+ OS << " depth " << D->getDepth() << " index " << D->getIndex();
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+}
+
+void TextNodeDumper::VisitUsingDecl(const UsingDecl *D) {
+ OS << ' ';
+ if (D->getQualifier())
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+}
+
+void TextNodeDumper::VisitUnresolvedUsingTypenameDecl(
+ const UnresolvedUsingTypenameDecl *D) {
+ OS << ' ';
+ if (D->getQualifier())
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+}
+
+void TextNodeDumper::VisitUnresolvedUsingValueDecl(
+ const UnresolvedUsingValueDecl *D) {
+ OS << ' ';
+ if (D->getQualifier())
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+ dumpType(D->getType());
+}
+
+void TextNodeDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) {
+ OS << ' ';
+ dumpBareDeclRef(D->getTargetDecl());
+}
+
+void TextNodeDumper::VisitConstructorUsingShadowDecl(
+ const ConstructorUsingShadowDecl *D) {
+ if (D->constructsVirtualBase())
+ OS << " virtual";
+
+ AddChild([=] {
+ OS << "target ";
+ dumpBareDeclRef(D->getTargetDecl());
+ });
+
+ AddChild([=] {
+ OS << "nominated ";
+ dumpBareDeclRef(D->getNominatedBaseClass());
+ OS << ' ';
+ dumpBareDeclRef(D->getNominatedBaseClassShadowDecl());
+ });
+
+ AddChild([=] {
+ OS << "constructed ";
+ dumpBareDeclRef(D->getConstructedBaseClass());
+ OS << ' ';
+ dumpBareDeclRef(D->getConstructedBaseClassShadowDecl());
+ });
+}
+
+void TextNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
+ switch (D->getLanguage()) {
+ case LinkageSpecDecl::lang_c:
+ OS << " C";
+ break;
+ case LinkageSpecDecl::lang_cxx:
+ OS << " C++";
+ break;
+ }
+}
+
+void TextNodeDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) {
+ OS << ' ';
+ dumpAccessSpecifier(D->getAccess());
+}
+
+void TextNodeDumper::VisitFriendDecl(const FriendDecl *D) {
+ if (TypeSourceInfo *T = D->getFriendType())
+ dumpType(T->getType());
+}
+
+void TextNodeDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (D->getSynthesize())
+ OS << " synthesize";
+
+ switch (D->getAccessControl()) {
+ case ObjCIvarDecl::None:
+ OS << " none";
+ break;
+ case ObjCIvarDecl::Private:
+ OS << " private";
+ break;
+ case ObjCIvarDecl::Protected:
+ OS << " protected";
+ break;
+ case ObjCIvarDecl::Public:
+ OS << " public";
+ break;
+ case ObjCIvarDecl::Package:
+ OS << " package";
+ break;
+ }
+}
+
+void TextNodeDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
+ if (D->isInstanceMethod())
+ OS << " -";
+ else
+ OS << " +";
+ dumpName(D);
+ dumpType(D->getReturnType());
+
+ if (D->isVariadic())
+ OS << " variadic";
+}
+
+void TextNodeDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) {
+ dumpName(D);
+ switch (D->getVariance()) {
+ case ObjCTypeParamVariance::Invariant:
+ break;
+
+ case ObjCTypeParamVariance::Covariant:
+ OS << " covariant";
+ break;
+
+ case ObjCTypeParamVariance::Contravariant:
+ OS << " contravariant";
+ break;
+ }
+
+ if (D->hasExplicitBound())
+ OS << " bounded";
+ dumpType(D->getUnderlyingType());
+}
+
+void TextNodeDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getClassInterface());
+ dumpDeclRef(D->getImplementation());
+ for (const auto *P : D->protocols())
+ dumpDeclRef(P);
+}
+
+void TextNodeDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getClassInterface());
+ dumpDeclRef(D->getCategoryDecl());
+}
+
+void TextNodeDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
+ dumpName(D);
+
+ for (const auto *Child : D->protocols())
+ dumpDeclRef(Child);
+}
+
+void TextNodeDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getSuperClass(), "super");
+
+ dumpDeclRef(D->getImplementation());
+ for (const auto *Child : D->protocols())
+ dumpDeclRef(Child);
+}
+
+void TextNodeDumper::VisitObjCImplementationDecl(
+ const ObjCImplementationDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getSuperClass(), "super");
+ dumpDeclRef(D->getClassInterface());
+}
+
+void TextNodeDumper::VisitObjCCompatibleAliasDecl(
+ const ObjCCompatibleAliasDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getClassInterface());
+}
+
+void TextNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+
+ if (D->getPropertyImplementation() == ObjCPropertyDecl::Required)
+ OS << " required";
+ else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional)
+ OS << " optional";
+
+ ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes();
+ if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) {
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly)
+ OS << " readonly";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
+ OS << " assign";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite)
+ OS << " readwrite";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_retain)
+ OS << " retain";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_copy)
+ OS << " copy";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic)
+ OS << " nonatomic";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic)
+ OS << " atomic";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_weak)
+ OS << " weak";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_strong)
+ OS << " strong";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained)
+ OS << " unsafe_unretained";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_class)
+ OS << " class";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_getter)
+ dumpDeclRef(D->getGetterMethodDecl(), "getter");
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_setter)
+ dumpDeclRef(D->getSetterMethodDecl(), "setter");
+ }
+}
+
+void TextNodeDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
+ dumpName(D->getPropertyDecl());
+ if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
+ OS << " synthesize";
+ else
+ OS << " dynamic";
+ dumpDeclRef(D->getPropertyDecl());
+ dumpDeclRef(D->getPropertyIvarDecl());
+}
+
+void TextNodeDumper::VisitBlockDecl(const BlockDecl *D) {
+ if (D->isVariadic())
+ OS << " variadic";
+
+ if (D->capturesCXXThis())
+ OS << " captures_this";
+}
+
+void TextNodeDumper::VisitConceptDecl(const ConceptDecl *D) {
+ dumpName(D);
+}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 0dbc88c04521d..ed75a0b5bcd85 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1,9 +1,8 @@
//===- Type.cpp - Type representation and manipulation --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -23,6 +22,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/NonTrivialTypeVisitor.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
@@ -723,25 +723,30 @@ const ObjCObjectPointerType *ObjCObjectPointerType::stripObjCKindOfTypeAndQuals(
return ctx.getObjCObjectPointerType(obj)->castAs<ObjCObjectPointerType>();
}
-template<typename F>
-static QualType simpleTransform(ASTContext &ctx, QualType type, F &&f);
-
namespace {
-/// Visitor used by simpleTransform() to perform the transformation.
-template<typename F>
-struct SimpleTransformVisitor
- : public TypeVisitor<SimpleTransformVisitor<F>, QualType> {
+/// Visitor used to perform a simple type transformation that does not change
+/// the semantics of the type.
+template <typename Derived>
+struct SimpleTransformVisitor : public TypeVisitor<Derived, QualType> {
ASTContext &Ctx;
- F &&TheFunc;
QualType recurse(QualType type) {
- return simpleTransform(Ctx, type, std::move(TheFunc));
+ // Split out the qualifiers from the type.
+ SplitQualType splitType = type.split();
+
+ // Visit the type itself.
+ QualType result = static_cast<Derived *>(this)->Visit(splitType.Ty);
+ if (result.isNull())
+ return result;
+
+ // Reconstruct the transformed type by applying the local qualifiers
+ // from the split type.
+ return Ctx.getQualifiedType(result, splitType.Quals);
}
public:
- SimpleTransformVisitor(ASTContext &ctx, F &&f)
- : Ctx(ctx), TheFunc(std::move(f)) {}
+ explicit SimpleTransformVisitor(ASTContext &ctx) : Ctx(ctx) {}
// None of the clients of this transformation can occur where
// there are dependent types, so skip dependent types.
@@ -752,6 +757,17 @@ public:
#define TRIVIAL_TYPE_CLASS(Class) \
QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); }
+#define SUGARED_TYPE_CLASS(Class) \
+ QualType Visit##Class##Type(const Class##Type *T) { \
+ if (!T->isSugared()) \
+ return QualType(T, 0); \
+ QualType desugaredType = recurse(T->desugar()); \
+ if (desugaredType.isNull()) \
+ return {}; \
+ if (desugaredType.getAsOpaquePtr() == T->desugar().getAsOpaquePtr()) \
+ return QualType(T, 0); \
+ return desugaredType; \
+ }
TRIVIAL_TYPE_CLASS(Builtin)
@@ -955,8 +971,9 @@ public:
return Ctx.getParenType(innerType);
}
- TRIVIAL_TYPE_CLASS(Typedef)
- TRIVIAL_TYPE_CLASS(ObjCTypeParam)
+ SUGARED_TYPE_CLASS(Typedef)
+ SUGARED_TYPE_CLASS(ObjCTypeParam)
+ SUGARED_TYPE_CLASS(MacroQualified)
QualType VisitAdjustedType(const AdjustedType *T) {
QualType originalType = recurse(T->getOriginalType());
@@ -987,15 +1004,15 @@ public:
return Ctx.getDecayedType(originalType);
}
- TRIVIAL_TYPE_CLASS(TypeOfExpr)
- TRIVIAL_TYPE_CLASS(TypeOf)
- TRIVIAL_TYPE_CLASS(Decltype)
- TRIVIAL_TYPE_CLASS(UnaryTransform)
+ SUGARED_TYPE_CLASS(TypeOfExpr)
+ SUGARED_TYPE_CLASS(TypeOf)
+ SUGARED_TYPE_CLASS(Decltype)
+ SUGARED_TYPE_CLASS(UnaryTransform)
TRIVIAL_TYPE_CLASS(Record)
TRIVIAL_TYPE_CLASS(Enum)
// FIXME: Non-trivial to implement, but important for C++
- TRIVIAL_TYPE_CLASS(Elaborated)
+ SUGARED_TYPE_CLASS(Elaborated)
QualType VisitAttributedType(const AttributedType *T) {
QualType modifiedType = recurse(T->getModifiedType());
@@ -1030,7 +1047,7 @@ public:
}
// FIXME: Non-trivial to implement, but important for C++
- TRIVIAL_TYPE_CLASS(TemplateSpecialization)
+ SUGARED_TYPE_CLASS(TemplateSpecialization)
QualType VisitAutoType(const AutoType *T) {
if (!T->isDeduced())
@@ -1049,7 +1066,7 @@ public:
}
// FIXME: Non-trivial to implement, but important for C++
- TRIVIAL_TYPE_CLASS(PackExpansion)
+ SUGARED_TYPE_CLASS(PackExpansion)
QualType VisitObjCObjectType(const ObjCObjectType *T) {
QualType baseType = recurse(T->getBaseType());
@@ -1107,222 +1124,245 @@ public:
}
#undef TRIVIAL_TYPE_CLASS
+#undef SUGARED_TYPE_CLASS
};
-} // namespace
-
-/// Perform a simple type transformation that does not change the
-/// semantics of the type.
-template<typename F>
-static QualType simpleTransform(ASTContext &ctx, QualType type, F &&f) {
- // Transform the type. If it changed, return the transformed result.
- QualType transformed = f(type);
- if (transformed.getAsOpaquePtr() != type.getAsOpaquePtr())
- return transformed;
-
- // Split out the qualifiers from the type.
- SplitQualType splitType = type.split();
-
- // Visit the type itself.
- SimpleTransformVisitor<F> visitor(ctx, std::forward<F>(f));
- QualType result = visitor.Visit(splitType.Ty);
- if (result.isNull())
- return result;
+struct SubstObjCTypeArgsVisitor
+ : public SimpleTransformVisitor<SubstObjCTypeArgsVisitor> {
+ using BaseType = SimpleTransformVisitor<SubstObjCTypeArgsVisitor>;
- // Reconstruct the transformed type by applying the local qualifiers
- // from the split type.
- return ctx.getQualifiedType(result, splitType.Quals);
-}
+ ArrayRef<QualType> TypeArgs;
+ ObjCSubstitutionContext SubstContext;
-/// Substitute the given type arguments for Objective-C type
-/// parameters within the given type, recursively.
-QualType QualType::substObjCTypeArgs(
- ASTContext &ctx,
- ArrayRef<QualType> typeArgs,
- ObjCSubstitutionContext context) const {
- return simpleTransform(ctx, *this,
- [&](QualType type) -> QualType {
- SplitQualType splitType = type.split();
+ SubstObjCTypeArgsVisitor(ASTContext &ctx, ArrayRef<QualType> typeArgs,
+ ObjCSubstitutionContext context)
+ : BaseType(ctx), TypeArgs(typeArgs), SubstContext(context) {}
+ QualType VisitObjCTypeParamType(const ObjCTypeParamType *OTPTy) {
// Replace an Objective-C type parameter reference with the corresponding
// type argument.
- if (const auto *OTPTy = dyn_cast<ObjCTypeParamType>(splitType.Ty)) {
- ObjCTypeParamDecl *typeParam = OTPTy->getDecl();
- // If we have type arguments, use them.
- if (!typeArgs.empty()) {
- QualType argType = typeArgs[typeParam->getIndex()];
- if (OTPTy->qual_empty())
- return ctx.getQualifiedType(argType, splitType.Quals);
-
- // Apply protocol lists if exists.
- bool hasError;
- SmallVector<ObjCProtocolDecl*, 8> protocolsVec;
- protocolsVec.append(OTPTy->qual_begin(),
- OTPTy->qual_end());
- ArrayRef<ObjCProtocolDecl *> protocolsToApply = protocolsVec;
- QualType resultTy = ctx.applyObjCProtocolQualifiers(argType,
- protocolsToApply, hasError, true/*allowOnPointerType*/);
-
- return ctx.getQualifiedType(resultTy, splitType.Quals);
- }
+ ObjCTypeParamDecl *typeParam = OTPTy->getDecl();
+ // If we have type arguments, use them.
+ if (!TypeArgs.empty()) {
+ QualType argType = TypeArgs[typeParam->getIndex()];
+ if (OTPTy->qual_empty())
+ return argType;
+
+ // Apply protocol lists if exists.
+ bool hasError;
+ SmallVector<ObjCProtocolDecl *, 8> protocolsVec;
+ protocolsVec.append(OTPTy->qual_begin(), OTPTy->qual_end());
+ ArrayRef<ObjCProtocolDecl *> protocolsToApply = protocolsVec;
+ return Ctx.applyObjCProtocolQualifiers(
+ argType, protocolsToApply, hasError, true/*allowOnPointerType*/);
+ }
- switch (context) {
- case ObjCSubstitutionContext::Ordinary:
- case ObjCSubstitutionContext::Parameter:
- case ObjCSubstitutionContext::Superclass:
- // Substitute the bound.
- return ctx.getQualifiedType(typeParam->getUnderlyingType(),
- splitType.Quals);
-
- case ObjCSubstitutionContext::Result:
- case ObjCSubstitutionContext::Property: {
- // Substitute the __kindof form of the underlying type.
- const auto *objPtr = typeParam->getUnderlyingType()
- ->castAs<ObjCObjectPointerType>();
-
- // __kindof types, id, and Class don't need an additional
- // __kindof.
- if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType())
- return ctx.getQualifiedType(typeParam->getUnderlyingType(),
- splitType.Quals);
-
- // Add __kindof.
- const auto *obj = objPtr->getObjectType();
- QualType resultTy = ctx.getObjCObjectType(obj->getBaseType(),
- obj->getTypeArgsAsWritten(),
- obj->getProtocols(),
- /*isKindOf=*/true);
-
- // Rebuild object pointer type.
- resultTy = ctx.getObjCObjectPointerType(resultTy);
- return ctx.getQualifiedType(resultTy, splitType.Quals);
- }
- }
+ switch (SubstContext) {
+ case ObjCSubstitutionContext::Ordinary:
+ case ObjCSubstitutionContext::Parameter:
+ case ObjCSubstitutionContext::Superclass:
+ // Substitute the bound.
+ return typeParam->getUnderlyingType();
+
+ case ObjCSubstitutionContext::Result:
+ case ObjCSubstitutionContext::Property: {
+ // Substitute the __kindof form of the underlying type.
+ const auto *objPtr =
+ typeParam->getUnderlyingType()->castAs<ObjCObjectPointerType>();
+
+ // __kindof types, id, and Class don't need an additional
+ // __kindof.
+ if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType())
+ return typeParam->getUnderlyingType();
+
+ // Add __kindof.
+ const auto *obj = objPtr->getObjectType();
+ QualType resultTy = Ctx.getObjCObjectType(
+ obj->getBaseType(), obj->getTypeArgsAsWritten(), obj->getProtocols(),
+ /*isKindOf=*/true);
+
+ // Rebuild object pointer type.
+ return Ctx.getObjCObjectPointerType(resultTy);
+ }
+ }
+ llvm_unreachable("Unexpected ObjCSubstitutionContext!");
+ }
+
+ QualType VisitFunctionType(const FunctionType *funcType) {
+ // If we have a function type, update the substitution context
+ // appropriately.
+
+ //Substitute result type.
+ QualType returnType = funcType->getReturnType().substObjCTypeArgs(
+ Ctx, TypeArgs, ObjCSubstitutionContext::Result);
+ if (returnType.isNull())
+ return {};
+
+ // Handle non-prototyped functions, which only substitute into the result
+ // type.
+ if (isa<FunctionNoProtoType>(funcType)) {
+ // If the return type was unchanged, do nothing.
+ if (returnType.getAsOpaquePtr() ==
+ funcType->getReturnType().getAsOpaquePtr())
+ return BaseType::VisitFunctionType(funcType);
+
+ // Otherwise, build a new type.
+ return Ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo());
}
- // If we have a function type, update the context appropriately.
- if (const auto *funcType = dyn_cast<FunctionType>(splitType.Ty)) {
- // Substitute result type.
- QualType returnType = funcType->getReturnType().substObjCTypeArgs(
- ctx,
- typeArgs,
- ObjCSubstitutionContext::Result);
- if (returnType.isNull())
+ const auto *funcProtoType = cast<FunctionProtoType>(funcType);
+
+ // Transform parameter types.
+ SmallVector<QualType, 4> paramTypes;
+ bool paramChanged = false;
+ for (auto paramType : funcProtoType->getParamTypes()) {
+ QualType newParamType = paramType.substObjCTypeArgs(
+ Ctx, TypeArgs, ObjCSubstitutionContext::Parameter);
+ if (newParamType.isNull())
return {};
- // Handle non-prototyped functions, which only substitute into the result
- // type.
- if (isa<FunctionNoProtoType>(funcType)) {
- // If the return type was unchanged, do nothing.
- if (returnType.getAsOpaquePtr()
- == funcType->getReturnType().getAsOpaquePtr())
- return type;
+ if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr())
+ paramChanged = true;
- // Otherwise, build a new type.
- return ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo());
- }
+ paramTypes.push_back(newParamType);
+ }
- const auto *funcProtoType = cast<FunctionProtoType>(funcType);
-
- // Transform parameter types.
- SmallVector<QualType, 4> paramTypes;
- bool paramChanged = false;
- for (auto paramType : funcProtoType->getParamTypes()) {
- QualType newParamType = paramType.substObjCTypeArgs(
- ctx,
- typeArgs,
- ObjCSubstitutionContext::Parameter);
- if (newParamType.isNull())
+ // Transform extended info.
+ FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo();
+ bool exceptionChanged = false;
+ if (info.ExceptionSpec.Type == EST_Dynamic) {
+ SmallVector<QualType, 4> exceptionTypes;
+ for (auto exceptionType : info.ExceptionSpec.Exceptions) {
+ QualType newExceptionType = exceptionType.substObjCTypeArgs(
+ Ctx, TypeArgs, ObjCSubstitutionContext::Ordinary);
+ if (newExceptionType.isNull())
return {};
- if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr())
- paramChanged = true;
+ if (newExceptionType.getAsOpaquePtr() != exceptionType.getAsOpaquePtr())
+ exceptionChanged = true;
- paramTypes.push_back(newParamType);
+ exceptionTypes.push_back(newExceptionType);
}
- // Transform extended info.
- FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo();
- bool exceptionChanged = false;
- if (info.ExceptionSpec.Type == EST_Dynamic) {
- SmallVector<QualType, 4> exceptionTypes;
- for (auto exceptionType : info.ExceptionSpec.Exceptions) {
- QualType newExceptionType = exceptionType.substObjCTypeArgs(
- ctx,
- typeArgs,
- ObjCSubstitutionContext::Ordinary);
- if (newExceptionType.isNull())
- return {};
-
- if (newExceptionType.getAsOpaquePtr()
- != exceptionType.getAsOpaquePtr())
- exceptionChanged = true;
-
- exceptionTypes.push_back(newExceptionType);
- }
-
- if (exceptionChanged) {
- info.ExceptionSpec.Exceptions =
- llvm::makeArrayRef(exceptionTypes).copy(ctx);
- }
+ if (exceptionChanged) {
+ info.ExceptionSpec.Exceptions =
+ llvm::makeArrayRef(exceptionTypes).copy(Ctx);
}
+ }
- if (returnType.getAsOpaquePtr()
- == funcProtoType->getReturnType().getAsOpaquePtr() &&
- !paramChanged && !exceptionChanged)
- return type;
+ if (returnType.getAsOpaquePtr() ==
+ funcProtoType->getReturnType().getAsOpaquePtr() &&
+ !paramChanged && !exceptionChanged)
+ return BaseType::VisitFunctionType(funcType);
- return ctx.getFunctionType(returnType, paramTypes, info);
- }
+ return Ctx.getFunctionType(returnType, paramTypes, info);
+ }
+ QualType VisitObjCObjectType(const ObjCObjectType *objcObjectType) {
// Substitute into the type arguments of a specialized Objective-C object
// type.
- if (const auto *objcObjectType = dyn_cast<ObjCObjectType>(splitType.Ty)) {
- if (objcObjectType->isSpecializedAsWritten()) {
- SmallVector<QualType, 4> newTypeArgs;
- bool anyChanged = false;
- for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) {
- QualType newTypeArg = typeArg.substObjCTypeArgs(
- ctx, typeArgs,
- ObjCSubstitutionContext::Ordinary);
- if (newTypeArg.isNull())
- return {};
-
- if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) {
- // If we're substituting based on an unspecialized context type,
- // produce an unspecialized type.
- ArrayRef<ObjCProtocolDecl *> protocols(
- objcObjectType->qual_begin(),
- objcObjectType->getNumProtocols());
- if (typeArgs.empty() &&
- context != ObjCSubstitutionContext::Superclass) {
- return ctx.getObjCObjectType(
- objcObjectType->getBaseType(), {},
- protocols,
- objcObjectType->isKindOfTypeAsWritten());
- }
-
- anyChanged = true;
+ if (objcObjectType->isSpecializedAsWritten()) {
+ SmallVector<QualType, 4> newTypeArgs;
+ bool anyChanged = false;
+ for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) {
+ QualType newTypeArg = typeArg.substObjCTypeArgs(
+ Ctx, TypeArgs, ObjCSubstitutionContext::Ordinary);
+ if (newTypeArg.isNull())
+ return {};
+
+ if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) {
+ // If we're substituting based on an unspecialized context type,
+ // produce an unspecialized type.
+ ArrayRef<ObjCProtocolDecl *> protocols(
+ objcObjectType->qual_begin(), objcObjectType->getNumProtocols());
+ if (TypeArgs.empty() &&
+ SubstContext != ObjCSubstitutionContext::Superclass) {
+ return Ctx.getObjCObjectType(
+ objcObjectType->getBaseType(), {}, protocols,
+ objcObjectType->isKindOfTypeAsWritten());
}
- newTypeArgs.push_back(newTypeArg);
+ anyChanged = true;
}
- if (anyChanged) {
- ArrayRef<ObjCProtocolDecl *> protocols(
- objcObjectType->qual_begin(),
- objcObjectType->getNumProtocols());
- return ctx.getObjCObjectType(objcObjectType->getBaseType(),
- newTypeArgs, protocols,
- objcObjectType->isKindOfTypeAsWritten());
- }
+ newTypeArgs.push_back(newTypeArg);
}
- return type;
+ if (anyChanged) {
+ ArrayRef<ObjCProtocolDecl *> protocols(
+ objcObjectType->qual_begin(), objcObjectType->getNumProtocols());
+ return Ctx.getObjCObjectType(objcObjectType->getBaseType(), newTypeArgs,
+ protocols,
+ objcObjectType->isKindOfTypeAsWritten());
+ }
}
- return type;
- });
+ return BaseType::VisitObjCObjectType(objcObjectType);
+ }
+
+ QualType VisitAttributedType(const AttributedType *attrType) {
+ QualType newType = BaseType::VisitAttributedType(attrType);
+ if (newType.isNull())
+ return {};
+
+ const auto *newAttrType = dyn_cast<AttributedType>(newType.getTypePtr());
+ if (!newAttrType || newAttrType->getAttrKind() != attr::ObjCKindOf)
+ return newType;
+
+ // Find out if it's an Objective-C object or object pointer type;
+ QualType newEquivType = newAttrType->getEquivalentType();
+ const ObjCObjectPointerType *ptrType =
+ newEquivType->getAs<ObjCObjectPointerType>();
+ const ObjCObjectType *objType = ptrType
+ ? ptrType->getObjectType()
+ : newEquivType->getAs<ObjCObjectType>();
+ if (!objType)
+ return newType;
+
+ // Rebuild the "equivalent" type, which pushes __kindof down into
+ // the object type.
+ newEquivType = Ctx.getObjCObjectType(
+ objType->getBaseType(), objType->getTypeArgsAsWritten(),
+ objType->getProtocols(),
+ // There is no need to apply kindof on an unqualified id type.
+ /*isKindOf=*/objType->isObjCUnqualifiedId() ? false : true);
+
+ // If we started with an object pointer type, rebuild it.
+ if (ptrType)
+ newEquivType = Ctx.getObjCObjectPointerType(newEquivType);
+
+ // Rebuild the attributed type.
+ return Ctx.getAttributedType(newAttrType->getAttrKind(),
+ newAttrType->getModifiedType(), newEquivType);
+ }
+};
+
+struct StripObjCKindOfTypeVisitor
+ : public SimpleTransformVisitor<StripObjCKindOfTypeVisitor> {
+ using BaseType = SimpleTransformVisitor<StripObjCKindOfTypeVisitor>;
+
+ explicit StripObjCKindOfTypeVisitor(ASTContext &ctx) : BaseType(ctx) {}
+
+ QualType VisitObjCObjectType(const ObjCObjectType *objType) {
+ if (!objType->isKindOfType())
+ return BaseType::VisitObjCObjectType(objType);
+
+ QualType baseType = objType->getBaseType().stripObjCKindOfType(Ctx);
+ return Ctx.getObjCObjectType(baseType, objType->getTypeArgsAsWritten(),
+ objType->getProtocols(),
+ /*isKindOf=*/false);
+ }
+};
+
+} // namespace
+
+/// Substitute the given type arguments for Objective-C type
+/// parameters within the given type, recursively.
+QualType QualType::substObjCTypeArgs(ASTContext &ctx,
+ ArrayRef<QualType> typeArgs,
+ ObjCSubstitutionContext context) const {
+ SubstObjCTypeArgsVisitor visitor(ctx, typeArgs, context);
+ return visitor.recurse(*this);
}
QualType QualType::substObjCMemberType(QualType objectType,
@@ -1337,25 +1377,8 @@ QualType QualType::substObjCMemberType(QualType objectType,
QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const {
// FIXME: Because ASTContext::getAttributedType() is non-const.
auto &ctx = const_cast<ASTContext &>(constCtx);
- return simpleTransform(ctx, *this,
- [&](QualType type) -> QualType {
- SplitQualType splitType = type.split();
- if (auto *objType = splitType.Ty->getAs<ObjCObjectType>()) {
- if (!objType->isKindOfType())
- return type;
-
- QualType baseType
- = objType->getBaseType().stripObjCKindOfType(ctx);
- return ctx.getQualifiedType(
- ctx.getObjCObjectType(baseType,
- objType->getTypeArgsAsWritten(),
- objType->getProtocols(),
- /*isKindOf=*/false),
- splitType.Quals);
- }
-
- return type;
- });
+ StripObjCKindOfTypeVisitor visitor(ctx);
+ return visitor.recurse(*this);
}
QualType QualType::getAtomicUnqualifiedType() const {
@@ -1713,9 +1736,17 @@ namespace {
return Visit(T->getModifiedType());
}
+ Type *VisitMacroQualifiedType(const MacroQualifiedType *T) {
+ return Visit(T->getUnderlyingType());
+ }
+
Type *VisitAdjustedType(const AdjustedType *T) {
return Visit(T->getOriginalType());
}
+
+ Type *VisitPackExpansionType(const PackExpansionType *T) {
+ return Visit(T->getPattern());
+ }
};
} // namespace
@@ -2245,6 +2276,18 @@ bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const {
getObjCLifetime() != Qualifiers::OCL_Weak;
}
+bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD) {
+ return RD->hasNonTrivialToPrimitiveDefaultInitializeCUnion();
+}
+
+bool QualType::hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD) {
+ return RD->hasNonTrivialToPrimitiveDestructCUnion();
+}
+
+bool QualType::hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD) {
+ return RD->hasNonTrivialToPrimitiveCopyCUnion();
+}
+
QualType::PrimitiveDefaultInitializeKind
QualType::isNonTrivialToPrimitiveDefaultInitialize() const {
if (const auto *RT =
@@ -2990,6 +3033,7 @@ CanThrowResult FunctionProtoType::canThrow() const {
case EST_DynamicNone:
case EST_BasicNoexcept:
case EST_NoexceptTrue:
+ case EST_NoThrow:
return CT_Cannot;
case EST_None:
@@ -3082,6 +3126,20 @@ QualType TypedefType::desugar() const {
return getDecl()->getUnderlyingType();
}
+QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); }
+
+QualType MacroQualifiedType::getModifiedType() const {
+ // Step over MacroQualifiedTypes from the same macro to find the type
+ // ultimately qualified by the macro qualifier.
+ QualType Inner = cast<AttributedType>(getUnderlyingType())->getModifiedType();
+ while (auto *InnerMQT = dyn_cast<MacroQualifiedType>(Inner)) {
+ if (InnerMQT->getMacroIdentifier() != getMacroIdentifier())
+ break;
+ Inner = InnerMQT->getModifiedType();
+ }
+ return Inner;
+}
+
TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
: Type(TypeOfExpr, can, E->isTypeDependent(),
E->isInstantiationDependent(),
@@ -3206,6 +3264,7 @@ bool AttributedType::isQualifier() const {
case attr::TypeNullable:
case attr::TypeNullUnspecified:
case attr::LifetimeBound:
+ case attr::AddressSpace:
return true;
// All other type attributes aren't qualifiers; they rewrite the modified
@@ -3831,7 +3890,11 @@ AttributedType::getImmediateNullability() const {
}
Optional<NullabilityKind> AttributedType::stripOuterNullability(QualType &T) {
- if (auto attributed = dyn_cast<AttributedType>(T.getTypePtr())) {
+ QualType AttrTy = T;
+ if (auto MacroTy = dyn_cast<MacroQualifiedType>(T))
+ AttrTy = MacroTy->getUnderlyingType();
+
+ if (auto attributed = dyn_cast<AttributedType>(AttrTy)) {
if (auto nullability = attributed->getImmediateNullability()) {
T = attributed->getModifiedType();
return nullability;
@@ -4016,25 +4079,8 @@ CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const {
void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,
llvm::APSInt Val, unsigned Scale) {
- if (Val.isSigned() && Val.isNegative() && Val != -Val) {
- Val = -Val;
- Str.push_back('-');
- }
-
- llvm::APSInt IntPart = Val >> Scale;
-
- // Add 4 digits to hold the value after multiplying 10 (the radix)
- unsigned Width = Val.getBitWidth() + 4;
- llvm::APInt FractPart = Val.zextOrTrunc(Scale).zext(Width);
- llvm::APInt FractPartMask = llvm::APInt::getAllOnesValue(Scale).zext(Width);
- llvm::APInt RadixInt = llvm::APInt(Width, 10);
-
- IntPart.toString(Str, /*radix=*/10);
- Str.push_back('.');
- do {
- (FractPart * RadixInt)
- .lshr(Scale)
- .toString(Str, /*radix=*/10, Val.isSigned());
- FractPart = (FractPart * RadixInt) & FractPartMask;
- } while (FractPart != 0);
+ FixedPointSemantics FXSema(Val.getBitWidth(), Scale, Val.isSigned(),
+ /*IsSaturated=*/false,
+ /*HasUnsignedPadding=*/false);
+ APFixedPoint(Val, FXSema).toString(Str);
}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index b7b2f188d7160..abe4c4eb25e6f 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -1,9 +1,8 @@
//===- TypeLoc.cpp - Type Source Info Wrapper -----------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 32c75afb43812..8d5c37299e5fb 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -1,9 +1,8 @@
//===- TypePrinter.cpp - Pretty-Print Clang Types -------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -258,11 +257,18 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::FunctionProto:
case Type::FunctionNoProto:
case Type::Paren:
- case Type::Attributed:
case Type::PackExpansion:
case Type::SubstTemplateTypeParm:
+ case Type::MacroQualified:
CanPrefixQualifiers = false;
break;
+
+ case Type::Attributed: {
+ // We still want to print the address_space before the type if it is an
+ // address_space attribute.
+ const auto *AttrTy = cast<AttributedType>(T);
+ CanPrefixQualifiers = AttrTy->getAttrKind() == attr::AddressSpace;
+ }
}
return CanPrefixQualifiers;
@@ -728,6 +734,8 @@ FunctionProtoType::printExceptionSpecification(raw_ostream &OS,
OS << getExceptionType(I).stream(Policy);
}
OS << ')';
+ } else if (EST_NoThrow == getExceptionSpecType()) {
+ OS << " __attribute__((nothrow))";
} else if (isNoexceptExceptionSpec(getExceptionSpecType())) {
OS << " noexcept";
// FIXME:Is it useful to print out the expression for a non-dependent
@@ -810,8 +818,8 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
printFunctionAfter(Info, OS);
- if (!T->getTypeQuals().empty())
- OS << " " << T->getTypeQuals().getAsString();
+ if (!T->getMethodQuals().empty())
+ OS << " " << T->getMethodQuals().getAsString();
switch (T->getRefQualifier()) {
case RQ_None:
@@ -958,6 +966,21 @@ void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) {
printTypeSpec(T->getDecl(), OS);
}
+void TypePrinter::printMacroQualifiedBefore(const MacroQualifiedType *T,
+ raw_ostream &OS) {
+ StringRef MacroName = T->getMacroIdentifier()->getName();
+ OS << MacroName << " ";
+
+ // Since this type is meant to print the macro instead of the whole attribute,
+ // we trim any attributes and go directly to the original modified type.
+ printBefore(T->getModifiedType(), OS);
+}
+
+void TypePrinter::printMacroQualifiedAfter(const MacroQualifiedType *T,
+ raw_ostream &OS) {
+ printAfter(T->getModifiedType(), OS);
+}
+
void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) {}
void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T,
@@ -1212,8 +1235,18 @@ void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T,
raw_ostream &OS) {
if (IdentifierInfo *Id = T->getIdentifier())
OS << Id->getName();
- else
- OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
+ 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();
+ }
+
+ if (IsLambdaAutoParam)
+ OS << "auto";
+ else
+ OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
+ }
spaceBeforePlaceHolder(OS);
}
@@ -1378,7 +1411,10 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
if (T->getAttrKind() == attr::ObjCKindOf)
OS << "__kindof ";
- printBefore(T->getModifiedType(), OS);
+ if (T->getAttrKind() == attr::AddressSpace)
+ printBefore(T->getEquivalentType(), OS);
+ else
+ printBefore(T->getModifiedType(), OS);
if (T->isMSTypeSpec()) {
switch (T->getAttrKind()) {
@@ -1624,6 +1660,19 @@ static const TemplateArgument &getArgument(const TemplateArgumentLoc &A) {
return A.getArgument();
}
+static void printArgument(const TemplateArgument &A, const PrintingPolicy &PP,
+ llvm::raw_ostream &OS) {
+ A.print(PP, OS);
+}
+
+static void printArgument(const TemplateArgumentLoc &A,
+ const PrintingPolicy &PP, llvm::raw_ostream &OS) {
+ const TemplateArgument::ArgKind &Kind = A.getArgument().getKind();
+ if (Kind == TemplateArgument::ArgKind::Type)
+ return A.getTypeSourceInfo()->getType().print(OS, PP);
+ return A.getArgument().print(PP, OS);
+}
+
template<typename TA>
static void printTo(raw_ostream &OS, ArrayRef<TA> Args,
const PrintingPolicy &Policy, bool SkipBrackets) {
@@ -1645,7 +1694,8 @@ static void printTo(raw_ostream &OS, ArrayRef<TA> Args,
} else {
if (!FirstArg)
OS << Comma;
- Argument.print(Policy, ArgOS);
+ // Tries to print the argument with location info if exists.
+ printArgument(Arg, Policy, ArgOS);
}
StringRef ArgString = ArgOS.str();
@@ -1755,17 +1805,19 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
case LangAS::opencl_private:
break;
case LangAS::opencl_constant:
- case LangAS::cuda_constant:
OS << "__constant";
break;
case LangAS::opencl_generic:
OS << "__generic";
break;
case LangAS::cuda_device:
- OS << "__device";
+ OS << "__device__";
+ break;
+ case LangAS::cuda_constant:
+ OS << "__constant__";
break;
case LangAS::cuda_shared:
- OS << "__shared";
+ OS << "__shared__";
break;
default:
OS << "__attribute__((address_space(";
diff --git a/lib/AST/VTTBuilder.cpp b/lib/AST/VTTBuilder.cpp
index a3f3dbdfb4f93..53d0ef09f14c5 100644
--- a/lib/AST/VTTBuilder.cpp
+++ b/lib/AST/VTTBuilder.cpp
@@ -1,9 +1,8 @@
//===- VTTBuilder.cpp - C++ VTT layout builder ----------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 846a6085743e1..0c699571555d5 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -1,9 +1,8 @@
//===--- VTableBuilder.cpp - C++ vtable layout builder --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -480,7 +479,7 @@ static bool HasSameVirtualSignature(const CXXMethodDecl *LHS,
// Force the signatures to match. We can't rely on the overrides
// list here because there isn't necessarily an inheritance
// relationship between the two methods.
- if (LT->getTypeQuals() != RT->getTypeQuals())
+ if (LT->getMethodQuals() != RT->getMethodQuals())
return false;
return LT->getParamTypes() == RT->getParamTypes();
}
@@ -847,6 +846,8 @@ private:
: BaseOffset(CharUnits::Zero()),
BaseOffsetInLayoutClass(CharUnits::Zero()),
VTableIndex(0) { }
+
+ MethodInfo(MethodInfo const&) = default;
};
typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
@@ -1061,8 +1062,7 @@ void ItaniumVTableBuilder::AddThunk(const CXXMethodDecl *MD,
SmallVectorImpl<ThunkInfo> &ThunksVector = Thunks[MD];
// Check if we have this thunk already.
- if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
- ThunksVector.end())
+ if (llvm::find(ThunksVector, Thunk) != ThunksVector.end())
return;
ThunksVector.push_back(Thunk);
@@ -1272,7 +1272,7 @@ ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment(
// We don't have vcall offsets for this virtual base, go ahead and
// build them.
VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass,
- /*FinalOverriders=*/nullptr,
+ /*Overriders=*/nullptr,
BaseSubobject(Offset.VirtualBase,
CharUnits::Zero()),
/*BaseIsVirtual=*/true,
@@ -2245,7 +2245,7 @@ ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
if (I != VirtualBaseClassOffsetOffsets.end())
return I->second;
- VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/nullptr,
+ VCallAndVBaseOffsetBuilder Builder(RD, RD, /*Overriders=*/nullptr,
BaseSubobject(RD, CharUnits::Zero()),
/*BaseIsVirtual=*/false,
/*OffsetInLayoutClass=*/CharUnits::Zero());
@@ -2451,8 +2451,7 @@ private:
SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
// Check if we have this thunk already.
- if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
- ThunksVector.end())
+ if (llvm::find(ThunksVector, Thunk) != ThunksVector.end())
return;
ThunksVector.push_back(Thunk);
@@ -3189,8 +3188,8 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
const CXXMethodDecl *MD = MethodNameAndDecl.second;
ThunkInfoVectorTy ThunksVector = Thunks[MD];
- std::stable_sort(ThunksVector.begin(), ThunksVector.end(),
- [](const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ llvm::stable_sort(ThunksVector, [](const ThunkInfo &LHS,
+ const ThunkInfo &RHS) {
// Keep different thunks with the same adjustments in the order they
// were put into the vector.
return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return);