Update aosp/master clang for rebase to r233350
Change-Id: I12d4823f10bc9e445b8b86e7721b71f98d1df442
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index ddb802e..38ff72a 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -255,11 +255,6 @@
if (!Method->isPropertyAccessor())
return false;
- const ObjCInterfaceDecl *IFace =
- NS.getASTContext().getObjContainingInterface(Method);
- if (!IFace)
- return false;
-
const ObjCPropertyDecl *Prop = Method->findPropertyDecl();
if (!Prop)
return false;
@@ -776,12 +771,12 @@
const TypedefDecl *TypedefDcl,
const NSAPI &NS, edit::Commit &commit,
bool IsNSIntegerType) {
- QualType EnumUnderlyingT = EnumDcl->getPromotionType();
- assert(!EnumUnderlyingT.isNull()
+ QualType DesignatedEnumType = EnumDcl->getIntegerType();
+ assert(!DesignatedEnumType.isNull()
&& "rewriteToNSMacroDecl - underlying enum type is null");
PrintingPolicy Policy(Ctx.getPrintingPolicy());
- std::string TypeString = EnumUnderlyingT.getAsString(Policy);
+ std::string TypeString = DesignatedEnumType.getAsString(Policy);
std::string ClassString = IsNSIntegerType ? "NS_ENUM(" : "NS_OPTIONS(";
ClassString += TypeString;
ClassString += ", ";
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 8a99162..57621a7 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -738,7 +738,8 @@
FILEDecl(nullptr), jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr),
ucontext_tDecl(nullptr), BlockDescriptorType(nullptr),
BlockDescriptorExtendedType(nullptr), cudaConfigureCallDecl(nullptr),
- FirstLocalImport(), LastLocalImport(), SourceMgr(SM), LangOpts(LOpts),
+ FirstLocalImport(), LastLocalImport(), ExternCContext(nullptr),
+ SourceMgr(SM), LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
AddrSpaceMap(nullptr), Target(nullptr), PrintingPolicy(LOpts),
Idents(idents), Selectors(sels), BuiltinInfo(builtins),
@@ -865,6 +866,13 @@
BumpAlloc.PrintStats();
}
+ExternCContextDecl *ASTContext::getExternCContextDecl() const {
+ if (!ExternCContext)
+ ExternCContext = ExternCContextDecl::Create(*this, getTranslationUnitDecl());
+
+ return ExternCContext;
+}
+
RecordDecl *ASTContext::buildImplicitRecord(StringRef Name,
RecordDecl::TagKind TK) const {
SourceLocation Loc;
@@ -3513,9 +3521,9 @@
/// CmpProtocolNames - Comparison predicate for sorting protocols
/// alphabetically.
-static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
- const ObjCProtocolDecl *RHS) {
- return LHS->getDeclName() < RHS->getDeclName();
+static int CmpProtocolNames(ObjCProtocolDecl *const *LHS,
+ ObjCProtocolDecl *const *RHS) {
+ return DeclarationName::compare((*LHS)->getDeclName(), (*RHS)->getDeclName());
}
static bool areSortedAndUniqued(ObjCProtocolDecl * const *Protocols,
@@ -3526,7 +3534,7 @@
return false;
for (unsigned i = 1; i != NumProtocols; ++i)
- if (!CmpProtocolNames(Protocols[i-1], Protocols[i]) ||
+ if (CmpProtocolNames(&Protocols[i - 1], &Protocols[i]) >= 0 ||
Protocols[i]->getCanonicalDecl() != Protocols[i])
return false;
return true;
@@ -3537,7 +3545,7 @@
ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols;
// Sort protocols, keyed by name.
- std::sort(Protocols, Protocols+NumProtocols, CmpProtocolNames);
+ llvm::array_pod_sort(Protocols, ProtocolsEnd, CmpProtocolNames);
// Canonicalize.
for (unsigned I = 0, N = NumProtocols; I != N; ++I)
@@ -4338,6 +4346,19 @@
return T.getUnqualifiedType();
}
+QualType ASTContext::getExceptionObjectType(QualType T) const {
+ // C++ [except.throw]p3:
+ // A throw-expression initializes a temporary object, called the exception
+ // object, the type of which is determined by removing any top-level
+ // cv-qualifiers from the static type of the operand of throw and adjusting
+ // the type from "array of T" or "function returning T" to "pointer to T"
+ // or "pointer to function returning T", [...]
+ T = getVariableArrayDecayedType(T);
+ if (T->isArrayType() || T->isFunctionType())
+ T = getDecayedType(T);
+ return T.getUnqualifiedType();
+}
+
/// getArrayDecayedType - Return the properly qualified result of decaying the
/// specified array type to a pointer. This operation is non-trivial when
/// handling typedefs etc. The canonical type of "T" must be an array type,
@@ -7819,6 +7840,9 @@
ArgTypes.push_back(Ty);
}
+ if (Id == Builtin::BI__GetExceptionInfo)
+ return QualType();
+
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
"'.' should only occur at end of builtin type list!");
@@ -7887,7 +7911,7 @@
// Functions specified with extern and inline in -fms-compatibility mode
// forcibly get emitted. While the body of the function cannot be later
// replaced, the function definition cannot be discarded.
- if (FD->getMostRecentDecl()->isMSExternInline())
+ if (FD->isMSExternInline())
return GVA_StrongODR;
return GVA_DiscardableODR;
@@ -7922,7 +7946,7 @@
while (LexicalContext && !isa<FunctionDecl>(LexicalContext))
LexicalContext = LexicalContext->getLexicalParent();
- // Let the static local variable inherit it's linkage from the nearest
+ // Let the static local variable inherit its linkage from the nearest
// enclosing function.
if (LexicalContext)
StaticLocalLinkage =
@@ -8176,6 +8200,31 @@
return ABI->createMangleNumberingContext();
}
+const CXXConstructorDecl *
+ASTContext::getCopyConstructorForExceptionObject(CXXRecordDecl *RD) {
+ return ABI->getCopyConstructorForExceptionObject(
+ cast<CXXRecordDecl>(RD->getFirstDecl()));
+}
+
+void ASTContext::addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
+ CXXConstructorDecl *CD) {
+ return ABI->addCopyConstructorForExceptionObject(
+ cast<CXXRecordDecl>(RD->getFirstDecl()),
+ cast<CXXConstructorDecl>(CD->getFirstDecl()));
+}
+
+void ASTContext::addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
+ unsigned ParmIdx, Expr *DAE) {
+ ABI->addDefaultArgExprForConstructor(
+ cast<CXXConstructorDecl>(CD->getFirstDecl()), ParmIdx, DAE);
+}
+
+Expr *ASTContext::getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
+ unsigned ParmIdx) {
+ return ABI->getDefaultArgExprForConstructor(
+ cast<CXXConstructorDecl>(CD->getFirstDecl()), ParmIdx);
+}
+
void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) {
ParamIndices[D] = index;
}
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 3a9aee6..711c329 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -508,6 +508,8 @@
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);
void VisitCXXConstructExpr(const CXXConstructExpr *Node);
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);
+ void VisitCXXNewExpr(const CXXNewExpr *Node);
+ void VisitCXXDeleteExpr(const CXXDeleteExpr *Node);
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node);
void VisitExprWithCleanups(const ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
@@ -1917,6 +1919,32 @@
dumpCXXTemporary(Node->getTemporary());
}
+void ASTDumper::VisitCXXNewExpr(const CXXNewExpr *Node) {
+ VisitExpr(Node);
+ if (Node->isGlobalNew())
+ OS << " global";
+ if (Node->isArray())
+ OS << " array";
+ if (Node->getOperatorNew()) {
+ OS << ' ';
+ dumpBareDeclRef(Node->getOperatorNew());
+ }
+ // We could dump the deallocation function used in case of error, but it's
+ // usually not that interesting.
+}
+
+void ASTDumper::VisitCXXDeleteExpr(const CXXDeleteExpr *Node) {
+ VisitExpr(Node);
+ if (Node->isGlobalDelete())
+ OS << " global";
+ if (Node->isArrayForm())
+ OS << " array";
+ if (Node->getOperatorDelete()) {
+ OS << ' ';
+ dumpBareDeclRef(Node->getOperatorDelete());
+ }
+}
+
void
ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) {
VisitExpr(Node);
@@ -2266,6 +2294,11 @@
P.dumpStmt(this);
}
+LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS) const {
+ ASTDumper P(OS, nullptr, nullptr);
+ P.dumpStmt(this);
+}
+
LLVM_DUMP_METHOD void Stmt::dump() const {
ASTDumper P(llvm::errs(), nullptr, nullptr);
P.dumpStmt(this);
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index 0bf6bcd..cb60870 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file contains out-of-line virtual methods for Attr classes.
+// This file contains out-of-line methods for Attr classes.
//
//===----------------------------------------------------------------------===//
@@ -18,10 +18,4 @@
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
-Attr::~Attr() { }
-
-void InheritableAttr::anchor() { }
-
-void InheritableParamAttr::anchor() { }
-
#include "clang/AST/AttrImpl.inc"
diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h
index 8e9e358..dad2264 100644
--- a/lib/AST/CXXABI.h
+++ b/lib/AST/CXXABI.h
@@ -20,6 +20,8 @@
namespace clang {
class ASTContext;
+class CXXConstructorDecl;
+class Expr;
class MemberPointerType;
class MangleNumberingContext;
@@ -41,6 +43,20 @@
/// Returns a new mangling number context for this C++ ABI.
virtual MangleNumberingContext *createMangleNumberingContext() const = 0;
+
+ /// Adds a mapping from class to copy constructor for this C++ ABI.
+ virtual void addCopyConstructorForExceptionObject(CXXRecordDecl *,
+ CXXConstructorDecl *) = 0;
+
+ /// Retrieves the mapping from class to copy constructor for this C++ ABI.
+ virtual const CXXConstructorDecl *
+ getCopyConstructorForExceptionObject(CXXRecordDecl *) = 0;
+
+ virtual void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
+ unsigned ParmIdx, Expr *DAE) = 0;
+
+ virtual Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
+ unsigned ParmIdx) = 0;
};
/// Creates an instance of a C++ ABI class.
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index e7e9941..ba6fd2e 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1489,6 +1489,11 @@
bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const {
assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
+ // Never replace one imported declaration with another; we need both results
+ // when re-exporting.
+ if (OldD->isFromASTFile() && isFromASTFile())
+ return false;
+
if (!isKindReplaceableBy(OldD->getKind(), getKind()))
return false;
@@ -2508,39 +2513,6 @@
return RD && isNamed(RD, "nothrow_t") && RD->isInStdNamespace();
}
-FunctionDecl *
-FunctionDecl::getCorrespondingUnsizedGlobalDeallocationFunction() const {
- ASTContext &Ctx = getASTContext();
- if (!Ctx.getLangOpts().SizedDeallocation)
- return nullptr;
-
- if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
- return nullptr;
- if (getDeclName().getCXXOverloadedOperator() != OO_Delete &&
- getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
- return nullptr;
- if (isa<CXXRecordDecl>(getDeclContext()))
- return nullptr;
-
- if (!getDeclContext()->getRedeclContext()->isTranslationUnit())
- return nullptr;
-
- if (getNumParams() != 2 || isVariadic() ||
- !Ctx.hasSameType(getType()->castAs<FunctionProtoType>()->getParamType(1),
- Ctx.getSizeType()))
- return nullptr;
-
- // This is a sized deallocation function. Find the corresponding unsized
- // deallocation function.
- lookup_result R = getDeclContext()->lookup(getDeclName());
- for (lookup_result::iterator RI = R.begin(), RE = R.end(); RI != RE;
- ++RI)
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*RI))
- if (FD->getNumParams() == 1 && !FD->isVariadic())
- return FD;
- return nullptr;
-}
-
LanguageLinkage FunctionDecl::getLanguageLinkage() const {
return getDeclLanguageLinkage(*this);
}
@@ -2629,7 +2601,14 @@
// extern "C".
// FIXME: A recognised library function may not be directly in an extern "C"
// declaration, for instance "extern "C" { namespace std { decl } }".
- if (!LinkageDecl || LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c)
+ if (!LinkageDecl) {
+ if (BuiltinID == Builtin::BI__GetExceptionInfo &&
+ Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ isInStdNamespace())
+ return Builtin::BI__GetExceptionInfo;
+ return 0;
+ }
+ if (LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c)
return 0;
}
@@ -2722,7 +2701,8 @@
if (!Context.getLangOpts().MSVCCompat && !hasAttr<DLLExportAttr>())
return false;
- for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDecl())
+ for (const FunctionDecl *FD = getMostRecentDecl(); FD;
+ FD = FD->getPreviousDecl())
if (FD->getStorageClass() == SC_Extern)
return true;
@@ -3794,6 +3774,13 @@
return new (C, (DeclContext *)nullptr) TranslationUnitDecl(C);
}
+void ExternCContextDecl::anchor() { }
+
+ExternCContextDecl *ExternCContextDecl::Create(const ASTContext &C,
+ TranslationUnitDecl *DC) {
+ return new (C, DC) ExternCContextDecl(DC);
+}
+
void LabelDecl::anchor() { }
LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC,
@@ -3932,6 +3919,14 @@
void TypedefNameDecl::anchor() { }
+TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName() const {
+ if (auto *TT = getTypeSourceInfo()->getType()->getAs<TagType>())
+ if (TT->getDecl()->getTypedefNameForAnonDecl() == this)
+ return TT->getDecl();
+
+ return nullptr;
+}
+
TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) TypedefDecl(C, nullptr, SourceLocation(), SourceLocation(),
nullptr, nullptr);
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 75a219a..2f0fffea 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -336,20 +336,34 @@
static AvailabilityResult CheckAvailability(ASTContext &Context,
const AvailabilityAttr *A,
std::string *Message) {
- StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
- StringRef PrettyPlatformName
- = AvailabilityAttr::getPrettyPlatformName(TargetPlatform);
- if (PrettyPlatformName.empty())
- PrettyPlatformName = TargetPlatform;
+ VersionTuple TargetMinVersion =
+ Context.getTargetInfo().getPlatformMinVersion();
- VersionTuple TargetMinVersion = Context.getTargetInfo().getPlatformMinVersion();
if (TargetMinVersion.empty())
return AR_Available;
+ // Check if this is an App Extension "platform", and if so chop off
+ // the suffix for matching with the actual platform.
+ StringRef ActualPlatform = A->getPlatform()->getName();
+ StringRef RealizedPlatform = ActualPlatform;
+ if (Context.getLangOpts().AppExt) {
+ size_t suffix = RealizedPlatform.rfind("_app_extension");
+ if (suffix != StringRef::npos)
+ RealizedPlatform = RealizedPlatform.slice(0, suffix);
+ }
+
+ StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
+
// Match the platform name.
- if (A->getPlatform()->getName() != TargetPlatform)
+ if (RealizedPlatform != TargetPlatform)
return AR_Available;
-
+
+ StringRef PrettyPlatformName
+ = AvailabilityAttr::getPrettyPlatformName(ActualPlatform);
+
+ if (PrettyPlatformName.empty())
+ PrettyPlatformName = ActualPlatform;
+
std::string HintMessage;
if (!A->getMessage().empty()) {
HintMessage = " - ";
@@ -583,6 +597,7 @@
case Block:
case Captured:
case TranslationUnit:
+ case ExternCContext:
case UsingDirective:
case ClassTemplateSpecialization:
@@ -893,6 +908,7 @@
DeclContext *DeclContext::getPrimaryContext() {
switch (DeclKind) {
case Decl::TranslationUnit:
+ case Decl::ExternCContext:
case Decl::LinkageSpec:
case Decl::Block:
case Decl::Captured:
@@ -995,23 +1011,24 @@
/// built a lookup map. For every name in the map, pull in the new names from
/// the external storage.
void DeclContext::reconcileExternalVisibleStorage() const {
- assert(NeedToReconcileExternalVisibleStorage && LookupPtr.getPointer());
+ assert(NeedToReconcileExternalVisibleStorage && LookupPtr);
NeedToReconcileExternalVisibleStorage = false;
- for (auto &Lookup : *LookupPtr.getPointer())
+ for (auto &Lookup : *LookupPtr)
Lookup.second.setHasExternalDecls();
}
/// \brief Load the declarations within this lexical storage from an
/// external source.
-void
+/// \return \c true if any declarations were added.
+bool
DeclContext::LoadLexicalDeclsFromExternalStorage() const {
ExternalASTSource *Source = getParentASTContext().getExternalSource();
assert(hasExternalLexicalStorage() && Source && "No external storage?");
// Notify that we have a DeclContext that is initializing.
ExternalASTSource::Deserializing ADeclContext(Source);
-
+
// Load the external declarations, if any.
SmallVector<Decl*, 64> Decls;
ExternalLexicalStorage = false;
@@ -1021,11 +1038,11 @@
case ELR_Failure:
case ELR_AlreadyLoaded:
- return;
+ return false;
}
if (Decls.empty())
- return;
+ return false;
// We may have already loaded just the fields of this record, in which case
// we need to ignore them.
@@ -1042,6 +1059,7 @@
FirstDecl = ExternalFirst;
if (!LastDecl)
LastDecl = ExternalLast;
+ return true;
}
DeclContext::lookup_result
@@ -1049,7 +1067,7 @@
DeclarationName Name) {
ASTContext &Context = DC->getParentASTContext();
StoredDeclsMap *Map;
- if (!(Map = DC->LookupPtr.getPointer()))
+ if (!(Map = DC->LookupPtr))
Map = DC->CreateStoredDeclsMap(Context);
if (DC->NeedToReconcileExternalVisibleStorage)
DC->reconcileExternalVisibleStorage();
@@ -1065,7 +1083,7 @@
ArrayRef<NamedDecl*> Decls) {
ASTContext &Context = DC->getParentASTContext();
StoredDeclsMap *Map;
- if (!(Map = DC->LookupPtr.getPointer()))
+ if (!(Map = DC->LookupPtr))
Map = DC->CreateStoredDeclsMap(Context);
if (DC->NeedToReconcileExternalVisibleStorage)
DC->reconcileExternalVisibleStorage();
@@ -1159,7 +1177,7 @@
// Remove only decls that have a name
if (!ND->getDeclName()) return;
- StoredDeclsMap *Map = getPrimaryContext()->LookupPtr.getPointer();
+ StoredDeclsMap *Map = getPrimaryContext()->LookupPtr;
if (!Map) return;
StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
@@ -1247,32 +1265,38 @@
StoredDeclsMap *DeclContext::buildLookup() {
assert(this == getPrimaryContext() && "buildLookup called on non-primary DC");
- // FIXME: Should we keep going if hasExternalVisibleStorage?
- if (!LookupPtr.getInt())
- return LookupPtr.getPointer();
+ if (!HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups)
+ return LookupPtr;
SmallVector<DeclContext *, 2> Contexts;
collectAllContexts(Contexts);
- for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
- buildLookupImpl<&DeclContext::decls_begin,
- &DeclContext::decls_end>(Contexts[I], false);
+
+ if (HasLazyExternalLexicalLookups) {
+ HasLazyExternalLexicalLookups = false;
+ for (auto *DC : Contexts) {
+ if (DC->hasExternalLexicalStorage())
+ HasLazyLocalLexicalLookups |=
+ DC->LoadLexicalDeclsFromExternalStorage();
+ }
+
+ if (!HasLazyLocalLexicalLookups)
+ return LookupPtr;
+ }
+
+ for (auto *DC : Contexts)
+ buildLookupImpl(DC, hasExternalVisibleStorage());
// We no longer have any lazy decls.
- LookupPtr.setInt(false);
- return LookupPtr.getPointer();
+ HasLazyLocalLexicalLookups = false;
+ return LookupPtr;
}
/// buildLookupImpl - Build part of the lookup data structure for the
/// declarations contained within DCtx, which will either be this
/// DeclContext, a DeclContext linked to it, or a transparent context
/// nested within it.
-template<DeclContext::decl_iterator (DeclContext::*Begin)() const,
- DeclContext::decl_iterator (DeclContext::*End)() const>
void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) {
- for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)();
- I != E; ++I) {
- Decl *D = *I;
-
+ for (Decl *D : DCtx->noload_decls()) {
// Insert this declaration into the lookup structure, but only if
// it's semantically within its decl context. Any other decls which
// should be found in this context are added eagerly.
@@ -1293,7 +1317,7 @@
// context (recursively).
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D))
if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
- buildLookupImpl<Begin, End>(InnerCtx, Internal);
+ buildLookupImpl(InnerCtx, Internal);
}
}
@@ -1321,9 +1345,9 @@
if (NeedToReconcileExternalVisibleStorage)
reconcileExternalVisibleStorage();
- StoredDeclsMap *Map = LookupPtr.getPointer();
+ StoredDeclsMap *Map = LookupPtr;
- if (LookupPtr.getInt())
+ if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups)
// FIXME: Make buildLookup const?
Map = const_cast<DeclContext*>(this)->buildLookup();
@@ -1337,7 +1361,7 @@
return R.first->second.getLookupResult();
if (Source->FindExternalVisibleDeclsByName(this, Name) || !R.second) {
- if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
+ if (StoredDeclsMap *Map = LookupPtr) {
StoredDeclsMap::iterator I = Map->find(Name);
if (I != Map->end())
return I->second.getLookupResult();
@@ -1347,8 +1371,8 @@
return lookup_result();
}
- StoredDeclsMap *Map = LookupPtr.getPointer();
- if (LookupPtr.getInt())
+ StoredDeclsMap *Map = LookupPtr;
+ if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups)
Map = const_cast<DeclContext*>(this)->buildLookup();
if (!Map)
@@ -1365,33 +1389,23 @@
DeclContext::noload_lookup(DeclarationName Name) {
assert(DeclKind != Decl::LinkageSpec &&
"Should not perform lookups into linkage specs!");
- if (!hasExternalVisibleStorage())
- return lookup(Name);
DeclContext *PrimaryContext = getPrimaryContext();
if (PrimaryContext != this)
return PrimaryContext->noload_lookup(Name);
- StoredDeclsMap *Map = LookupPtr.getPointer();
- if (LookupPtr.getInt()) {
- // Carefully build the lookup map, without deserializing anything.
+ // If we have any lazy lexical declarations not in our lookup map, add them
+ // now. Don't import any external declarations, not even if we know we have
+ // some missing from the external visible lookups.
+ if (HasLazyLocalLexicalLookups) {
SmallVector<DeclContext *, 2> Contexts;
collectAllContexts(Contexts);
for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
- buildLookupImpl<&DeclContext::noload_decls_begin,
- &DeclContext::noload_decls_end>(Contexts[I], true);
-
- // We no longer have any lazy decls.
- LookupPtr.setInt(false);
-
- // There may now be names for which we have local decls but are
- // missing the external decls. FIXME: Just set the hasExternalDecls
- // flag on those names that have external decls.
- NeedToReconcileExternalVisibleStorage = true;
-
- Map = LookupPtr.getPointer();
+ buildLookupImpl(Contexts[I], hasExternalVisibleStorage());
+ HasLazyLocalLexicalLookups = false;
}
+ StoredDeclsMap *Map = LookupPtr;
if (!Map)
return lookup_result();
@@ -1413,8 +1427,9 @@
}
// If we have a lookup table, check there first. Maybe we'll get lucky.
- if (Name && !LookupPtr.getInt()) {
- if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
+ // FIXME: Should we be checking these flags on the primary context?
+ if (Name && !HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups) {
+ if (StoredDeclsMap *Map = LookupPtr) {
StoredDeclsMap::iterator Pos = Map->find(Name);
if (Pos != Map->end()) {
Results.insert(Results.end(),
@@ -1427,6 +1442,8 @@
// Slow case: grovel through the declarations in our chain looking for
// matches.
+ // FIXME: If we have lazy external declarations, this will not find them!
+ // FIXME: Should we CollectAllContexts and walk them all here?
for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
if (ND->getDeclName() == Name)
@@ -1507,7 +1524,7 @@
// FIXME: As a performance hack, don't add such decls into the translation
// unit unless we're in C++, since qualified lookup into the TU is never
// performed.
- if (LookupPtr.getPointer() || hasExternalVisibleStorage() ||
+ if (LookupPtr || hasExternalVisibleStorage() ||
((!Recoverable || D->getDeclContext() != D->getLexicalDeclContext()) &&
(getParentASTContext().getLangOpts().CPlusPlus ||
!isTranslationUnit()))) {
@@ -1517,7 +1534,7 @@
buildLookup();
makeDeclVisibleInContextImpl(D, Internal);
} else {
- LookupPtr.setInt(true);
+ HasLazyLocalLexicalLookups = true;
}
// If we are a transparent context or inline namespace, insert into our
@@ -1535,7 +1552,7 @@
void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) {
// Find or create the stored declaration map.
- StoredDeclsMap *Map = LookupPtr.getPointer();
+ StoredDeclsMap *Map = LookupPtr;
if (!Map) {
ASTContext *C = &getParentASTContext();
Map = CreateStoredDeclsMap(*C);
@@ -1597,7 +1614,7 @@
//===----------------------------------------------------------------------===//
StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const {
- assert(!LookupPtr.getPointer() && "context already has a decls map");
+ assert(!LookupPtr && "context already has a decls map");
assert(getPrimaryContext() == this &&
"creating decls map on non-primary context");
@@ -1609,7 +1626,7 @@
M = new StoredDeclsMap();
M->Previous = C.LastSDM;
C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent);
- LookupPtr.setPointer(M);
+ LookupPtr = M;
return M;
}
@@ -1641,11 +1658,11 @@
assert(Parent->isDependentContext()
&& "cannot iterate dependent diagnostics of non-dependent context");
Parent = Parent->getPrimaryContext();
- if (!Parent->LookupPtr.getPointer())
+ if (!Parent->LookupPtr)
Parent->CreateStoredDeclsMap(C);
- DependentStoredDeclsMap *Map
- = static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr.getPointer());
+ DependentStoredDeclsMap *Map =
+ static_cast<DependentStoredDeclsMap *>(Parent->LookupPtr);
// Allocate the copy of the PartialDiagnostic via the ASTContext's
// BumpPtrAllocator, rather than the ASTContext itself.
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 87a0634..8dc62dd 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1739,6 +1739,10 @@
isImplicitlyDeclared, isConstexpr);
}
+CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
+ return CtorInitializers.get(getASTContext().getExternalSource());
+}
+
CXXConstructorDecl *CXXConstructorDecl::getTargetConstructor() const {
assert(isDelegatingConstructor() && "Not a delegating constructor!");
Expr *E = (*init_begin())->getInit()->IgnoreImplicit();
@@ -1886,6 +1890,15 @@
isInline, isImplicitlyDeclared);
}
+void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD) {
+ auto *First = cast<CXXDestructorDecl>(getFirstDecl());
+ if (OD && !First->OperatorDelete) {
+ First->OperatorDelete = OD;
+ if (auto *L = getASTMutationListener())
+ L->ResolvedOperatorDelete(First, OD);
+ }
+}
+
void CXXConversionDecl::anchor() { }
CXXConversionDecl *
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 6e74784..a63ba7e 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -616,8 +616,7 @@
// Look through local category implementations associated with the class.
if (!Method)
- Method = Instance ? getCategoryInstanceMethod(Sel)
- : getCategoryClassMethod(Sel);
+ Method = getCategoryMethod(Sel, Instance);
// Before we give up, check if the selector is an instance method.
// But only in the root. This matches gcc's behavior and what the
@@ -1821,6 +1820,11 @@
}
}
+ObjCImplementationDecl::init_const_iterator
+ObjCImplementationDecl::init_begin() const {
+ return IvarInitializers.get(getASTContext().getExternalSource());
+}
+
raw_ostream &clang::operator<<(raw_ostream &OS,
const ObjCImplementationDecl &ID) {
OS << ID.getName();
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index ae80790..d13a11c 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1141,40 +1141,13 @@
RParenLoc = rparenloc;
}
-CallExpr::CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
+CallExpr::CallExpr(const ASTContext &C, Expr *fn, ArrayRef<Expr *> args,
QualType t, ExprValueKind VK, SourceLocation rparenloc)
- : Expr(CallExprClass, t, VK, OK_Ordinary,
- fn->isTypeDependent(),
- fn->isValueDependent(),
- fn->isInstantiationDependent(),
- fn->containsUnexpandedParameterPack()),
- NumArgs(args.size()) {
-
- SubExprs = new (C) Stmt*[args.size()+PREARGS_START];
- SubExprs[FN] = fn;
- for (unsigned i = 0; i != args.size(); ++i) {
- if (args[i]->isTypeDependent())
- ExprBits.TypeDependent = true;
- if (args[i]->isValueDependent())
- ExprBits.ValueDependent = true;
- if (args[i]->isInstantiationDependent())
- ExprBits.InstantiationDependent = true;
- if (args[i]->containsUnexpandedParameterPack())
- ExprBits.ContainsUnexpandedParameterPack = true;
-
- SubExprs[i+PREARGS_START] = args[i];
- }
-
- CallExprBits.NumPreArgs = 0;
- RParenLoc = rparenloc;
+ : CallExpr(C, CallExprClass, fn, /*NumPreArgs=*/0, args, t, VK, rparenloc) {
}
CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty)
- : Expr(SC, Empty), SubExprs(nullptr), NumArgs(0) {
- // FIXME: Why do we allocate this?
- SubExprs = new (C) Stmt*[PREARGS_START];
- CallExprBits.NumPreArgs = 0;
-}
+ : CallExpr(C, SC, /*NumPreArgs=*/0, Empty) {}
CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
EmptyShell Empty)
@@ -1403,16 +1376,12 @@
}
}
-MemberExpr *MemberExpr::Create(const ASTContext &C, Expr *base, bool isarrow,
- NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc,
- ValueDecl *memberdecl,
- DeclAccessPair founddecl,
- DeclarationNameInfo nameinfo,
- const TemplateArgumentListInfo *targs,
- QualType ty,
- ExprValueKind vk,
- ExprObjectKind ok) {
+MemberExpr *MemberExpr::Create(
+ 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) {
std::size_t Size = sizeof(MemberExpr);
bool hasQualOrFound = (QualifierLoc ||
@@ -1427,8 +1396,8 @@
Size += ASTTemplateKWAndArgsInfo::sizeFor(0);
void *Mem = C.Allocate(Size, llvm::alignOf<MemberExpr>());
- MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, nameinfo,
- ty, vk, ok);
+ MemberExpr *E = new (Mem)
+ MemberExpr(base, isarrow, OperatorLoc, memberdecl, nameinfo, ty, vk, ok);
if (hasQualOrFound) {
// FIXME: Wrong. We should be looking at the member declaration we found.
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 083572b..280ba57 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1406,7 +1406,7 @@
return true;
}
-const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
+static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
return LVal.Base.dyn_cast<const ValueDecl*>();
}
@@ -2502,8 +2502,9 @@
}
/// Find the complete object to which an LValue refers.
-CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
- const LValue &LVal, QualType LValType) {
+static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
+ AccessKinds AK, const LValue &LVal,
+ QualType LValType) {
if (!LVal.Base) {
Info.Diag(E, diag::note_constexpr_access_null) << AK;
return CompleteObject();
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index 8894107..730842a 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/lib/AST/ExternalASTSource.cpp
@@ -66,6 +66,11 @@
return nullptr;
}
+CXXCtorInitializer **
+ExternalASTSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
+ return nullptr;
+}
+
CXXBaseSpecifier *
ExternalASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
return nullptr;
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index eb3020c..0b82da1 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -22,11 +22,9 @@
#include "llvm/Support/raw_ostream.h"
#include <map>
#include <set>
+using namespace clang;
-using namespace llvm;
-
-namespace clang {
-
+namespace {
/// InheritanceHierarchyWriter - Helper class that writes out a
/// GraphViz file that diagrams the inheritance hierarchy starting at
/// a given C++ class type. Note that we do not use LLVM's
@@ -44,7 +42,8 @@
: Context(Context), Out(Out) { }
void WriteGraph(QualType Type) {
- Out << "digraph \"" << DOT::EscapeString(Type.getAsString()) << "\" {\n";
+ Out << "digraph \"" << llvm::DOT::EscapeString(Type.getAsString())
+ << "\" {\n";
WriteNode(Type, false);
Out << "}\n";
}
@@ -59,6 +58,7 @@
/// (only) virtual base.
raw_ostream& WriteNodeReference(QualType Type, bool FromVirtual);
};
+} // namespace
void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
QualType CanonType = Context.getCanonicalType(Type);
@@ -78,7 +78,7 @@
// Give the node a label based on the name of the class.
std::string TypeName = Type.getAsString();
- Out << " [ shape=\"box\", label=\"" << DOT::EscapeString(TypeName);
+ Out << " [ shape=\"box\", label=\"" << llvm::DOT::EscapeString(TypeName);
// If the name of the class was a typedef or something different
// from the "real" class name, show the real class name in
@@ -139,9 +139,8 @@
int FD;
SmallString<128> Filename;
- std::error_code EC =
- sys::fs::createTemporaryFile(Self.getAsString(), "dot", FD, Filename);
- if (EC) {
+ if (std::error_code EC = llvm::sys::fs::createTemporaryFile(
+ Self.getAsString(), "dot", FD, Filename)) {
llvm::errs() << "Error: " << EC.message() << "\n";
return;
}
@@ -159,5 +158,3 @@
// Display the graph
DisplayGraph(Filename);
}
-
-}
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index 378121c..7420782 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -133,6 +133,22 @@
return Layout.getNonVirtualSize() == PointerSize;
}
+ const CXXConstructorDecl *
+ getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {
+ return nullptr;
+ }
+
+ void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
+ CXXConstructorDecl *CD) override {}
+
+ void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
+ unsigned ParmIdx, Expr *DAE) override {}
+
+ Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
+ unsigned ParmIdx) override {
+ return nullptr;
+ }
+
MangleNumberingContext *createMangleNumberingContext() const override {
return new ItaniumNumberingContext();
}
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index b2a1b24..f890719 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -1034,7 +1034,7 @@
Str += llvm::utostr(AnonStructId);
Out << Str.size();
- Out << Str.str();
+ Out << Str;
break;
}
@@ -2673,7 +2673,6 @@
// These all can only appear in local or variable-initialization
// contexts and so should never appear in a mangling.
case Expr::AddrLabelExprClass:
- case Expr::DesignatedInitExprClass:
case Expr::ImplicitValueInitExprClass:
case Expr::ParenListExprClass:
case Expr::LambdaExprClass:
@@ -2685,6 +2684,7 @@
case Expr::BlockExprClass:
case Expr::ChooseExprClass:
case Expr::CompoundLiteralExprClass:
+ case Expr::DesignatedInitExprClass:
case Expr::ExtVectorElementExprClass:
case Expr::GenericSelectionExprClass:
case Expr::ObjCEncodeExprClass:
@@ -3442,6 +3442,9 @@
case Ctor_Comdat:
Out << "C5";
break;
+ case Ctor_DefaultClosure:
+ case Ctor_CopyingClosure:
+ llvm_unreachable("closure constructors don't exist for the Itanium ABI!");
}
}
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 0603d3b..fb3beff 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -63,6 +63,10 @@
class MicrosoftCXXABI : public CXXABI {
ASTContext &Context;
+ llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> RecordToCopyCtor;
+ llvm::SmallDenseMap<std::pair<const CXXConstructorDecl *, unsigned>, Expr *>
+ CtorToDefaultArgExpr;
+
public:
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
@@ -82,13 +86,36 @@
return false;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
+
// In the Microsoft ABI, classes can have one or two vtable pointers.
- CharUnits PointerSize =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ CharUnits PointerSize =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
return Layout.getNonVirtualSize() == PointerSize ||
Layout.getNonVirtualSize() == PointerSize * 2;
- }
+ }
+
+ void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
+ unsigned ParmIdx, Expr *DAE) override {
+ CtorToDefaultArgExpr[std::make_pair(CD, ParmIdx)] = DAE;
+ }
+
+ Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
+ unsigned ParmIdx) override {
+ return CtorToDefaultArgExpr[std::make_pair(CD, ParmIdx)];
+ }
+
+ const CXXConstructorDecl *
+ getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {
+ return RecordToCopyCtor[RD];
+ }
+
+ void
+ addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
+ CXXConstructorDecl *CD) override {
+ assert(CD != nullptr);
+ assert(RecordToCopyCtor[RD] == nullptr || RecordToCopyCtor[RD] == CD);
+ RecordToCopyCtor[RD] = CD;
+ }
MangleNumberingContext *createMangleNumberingContext() const override {
return new MicrosoftNumberingContext();
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 9dbbe5b..563ea7f 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -67,11 +67,15 @@
return getEffectiveDeclContext(cast<Decl>(DC));
}
-static const FunctionDecl *getStructor(const FunctionDecl *fn) {
- if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
- return ftd->getTemplatedDecl();
+static const FunctionDecl *getStructor(const NamedDecl *ND) {
+ if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(ND))
+ return FTD->getTemplatedDecl();
- return fn;
+ const auto *FD = cast<FunctionDecl>(ND);
+ if (const auto *FTD = FD->getPrimaryTemplate())
+ return FTD->getTemplatedDecl();
+
+ return FD;
}
static bool isLambda(const NamedDecl *ND) {
@@ -110,6 +114,16 @@
void mangleCXXVBTable(const CXXRecordDecl *Derived,
ArrayRef<const CXXRecordDecl *> BasePath,
raw_ostream &Out) override;
+ void mangleCXXThrowInfo(QualType T, bool IsConst, bool IsVolatile,
+ uint32_t NumEntries, raw_ostream &Out) override;
+ void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries,
+ raw_ostream &Out) override;
+ void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD,
+ CXXCtorType CT, uint32_t Size, uint32_t NVOffset,
+ int32_t VBPtrOffset, uint32_t VBIndex,
+ raw_ostream &Out) override;
+ void mangleCXXHandlerMapEntry(QualType T, bool IsConst, bool IsVolatile,
+ bool IsReference, raw_ostream &Out) override;
void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
@@ -216,6 +230,12 @@
64) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
+ const CXXConstructorDecl *D, CXXCtorType Type)
+ : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
+ 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),
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
@@ -276,6 +296,7 @@
void mangleDecayedArrayType(const ArrayType *T);
void mangleArrayType(const ArrayType *T);
void mangleFunctionClass(const FunctionDecl *FD);
+ void mangleCallingConvention(CallingConv CC);
void mangleCallingConvention(const FunctionType *T);
void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
void mangleExpression(const Expr *E);
@@ -564,7 +585,7 @@
Out << "$B";
mangleNumber(OffsetInVFTable);
Out << 'A';
- Out << (PointersAre64Bit ? 'A' : 'E');
+ mangleCallingConvention(MD->getType()->getAs<FunctionProtoType>());
}
void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
@@ -762,12 +783,18 @@
llvm_unreachable("Can't mangle Objective-C selector names here!");
case DeclarationName::CXXConstructorName:
- if (ND == Structor) {
- assert(StructorType == Ctor_Complete &&
- "Should never be asked to mangle a ctor other than complete");
+ if (Structor == getStructor(ND)) {
+ if (StructorType == Ctor_CopyingClosure) {
+ Out << "?_O";
+ return;
+ }
+ if (StructorType == Ctor_DefaultClosure) {
+ Out << "?_F";
+ return;
+ }
}
Out << "?0";
- break;
+ return;
case DeclarationName::CXXDestructorName:
if (ND == Structor)
@@ -1176,7 +1203,11 @@
if (TemplateArgs.empty()) {
if (isa<TemplateTypeParmDecl>(Parm) ||
isa<TemplateTemplateParmDecl>(Parm))
- Out << "$$V";
+ // MSVC 2015 changed the mangling for empty expanded template packs,
+ // use the old mangling for link compatibility for old versions.
+ Out << (Context.getASTContext().getLangOpts().isCompatibleWithMSVC(19)
+ ? "$$V"
+ : "$$$V");
else if (isa<NonTypeTemplateParmDecl>(Parm))
Out << "$S";
else
@@ -1558,12 +1589,22 @@
SourceRange Range;
if (D) Range = D->getSourceRange();
- bool IsStructor = false, HasThisQuals = ForceThisQuals;
+ bool IsStructor = false, HasThisQuals = ForceThisQuals, IsCtorClosure = false;
+ CallingConv CC = T->getCallConv();
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(D)) {
if (MD->isInstance())
HasThisQuals = true;
- if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
+ if (isa<CXXDestructorDecl>(MD)) {
IsStructor = true;
+ } else if (isa<CXXConstructorDecl>(MD)) {
+ IsStructor = true;
+ IsCtorClosure = (StructorType == Ctor_CopyingClosure ||
+ StructorType == Ctor_DefaultClosure) &&
+ getStructor(MD) == Structor;
+ if (IsCtorClosure)
+ CC = getASTContext().getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/true);
+ }
}
// If this is a C++ instance method, mangle the CVR qualifiers for the
@@ -1575,7 +1616,7 @@
mangleQualifiers(Quals, /*IsMember=*/false);
}
- mangleCallingConvention(T);
+ mangleCallingConvention(CC);
// <return-type> ::= <type>
// ::= @ # structors (they have no declared return type)
@@ -1589,6 +1630,29 @@
Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z");
return;
}
+ if (IsCtorClosure) {
+ // Default constructor closure and copy constructor closure both return
+ // void.
+ Out << 'X';
+
+ if (StructorType == Ctor_DefaultClosure) {
+ // Default constructor closure always has no arguments.
+ 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);
+ Out << '@';
+ } else {
+ llvm_unreachable("unexpected constructor closure!");
+ }
+ Out << 'Z';
+ return;
+ }
Out << '@';
} else {
QualType ResultType = Proto->getReturnType();
@@ -1681,7 +1745,7 @@
} else
Out << 'Y';
}
-void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) {
+void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) {
// <calling-convention> ::= A # __cdecl
// ::= B # __export __cdecl
// ::= C # __pascal
@@ -1698,7 +1762,7 @@
// that keyword. (It didn't actually export them, it just made them so
// that they could be in a DLL and somebody from another module could call
// them.)
- CallingConv CC = T->getCallConv();
+
switch (CC) {
default:
llvm_unreachable("Unsupported CC for mangling");
@@ -1712,6 +1776,9 @@
case CC_X86VectorCall: Out << 'Q'; break;
}
}
+void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) {
+ mangleCallingConvention(T->getCallConv());
+}
void MicrosoftCXXNameMangler::mangleThrowSpecification(
const FunctionProtoType *FT) {
// <throw-spec> ::= Z # throw(...) (default)
@@ -2278,6 +2345,81 @@
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
}
+void MicrosoftMangleContextImpl::mangleCXXHandlerMapEntry(QualType T,
+ bool IsConst,
+ bool IsVolatile,
+ bool IsReference,
+ raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "llvm.eh.handlermapentry.";
+ if (IsConst)
+ Mangler.getStream() << "const.";
+ if (IsVolatile)
+ Mangler.getStream() << "volatile.";
+ if (IsReference)
+ Mangler.getStream() << "reference.";
+ Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
+}
+
+void MicrosoftMangleContextImpl::mangleCXXThrowInfo(QualType T,
+ bool IsConst,
+ bool IsVolatile,
+ uint32_t NumEntries,
+ raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_TI";
+ if (IsConst)
+ Mangler.getStream() << 'C';
+ if (IsVolatile)
+ Mangler.getStream() << 'V';
+ Mangler.getStream() << NumEntries;
+ Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
+}
+
+void MicrosoftMangleContextImpl::mangleCXXCatchableTypeArray(
+ QualType T, uint32_t NumEntries, raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_CTA";
+ Mangler.getStream() << NumEntries;
+ Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
+}
+
+void MicrosoftMangleContextImpl::mangleCXXCatchableType(
+ QualType T, const CXXConstructorDecl *CD, CXXCtorType CT, uint32_t Size,
+ uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBIndex,
+ raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_CT";
+
+ llvm::SmallString<64> RTTIMangling;
+ {
+ llvm::raw_svector_ostream Stream(RTTIMangling);
+ mangleCXXRTTI(T, Stream);
+ }
+ Mangler.getStream() << RTTIMangling.substr(1);
+
+ // 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.
+ // TODO: Revisit this when VS2015 gets released.
+ llvm::SmallString<64> CopyCtorMangling;
+ if (CD) {
+ llvm::raw_svector_ostream Stream(CopyCtorMangling);
+ mangleCXXCtor(CD, CT, Stream);
+ }
+ Mangler.getStream() << CopyCtorMangling.substr(1);
+
+ Mangler.getStream() << Size;
+ if (VBPtrOffset == -1) {
+ if (NVOffset) {
+ Mangler.getStream() << NVOffset;
+ }
+ } else {
+ Mangler.getStream() << NVOffset;
+ Mangler.getStream() << VBPtrOffset;
+ Mangler.getStream() << VBIndex;
+ }
+}
+
void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassDescriptor(
const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,
uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) {
@@ -2345,7 +2487,7 @@
void MicrosoftMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D,
CXXCtorType Type,
raw_ostream &Out) {
- MicrosoftCXXNameMangler mangler(*this, Out);
+ MicrosoftCXXNameMangler mangler(*this, Out, D, Type);
mangler.mangle(D);
}
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index 3dc750a..033a87b 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -27,7 +27,10 @@
"NSMutableArray",
"NSDictionary",
"NSMutableDictionary",
- "NSNumber"
+ "NSNumber",
+ "NSMutableSet",
+ "NSCountedSet",
+ "NSMutableOrderedSet"
};
if (!ClassIds[K])
@@ -124,6 +127,25 @@
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
+ case NSMutableArr_addObject:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));
+ break;
+ case NSMutableArr_insertObjectAtIndex: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("insertObject"),
+ &Ctx.Idents.get("atIndex")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSMutableArr_setObjectAtIndexedSubscript: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("setObject"),
+ &Ctx.Idents.get("atIndexedSubscript")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
}
return (NSArraySelectors[MK] = Sel);
}
@@ -209,6 +231,22 @@
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
+ case NSMutableDict_setObjectForKeyedSubscript: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("setObject"),
+ &Ctx.Idents.get("forKeyedSubscript")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSMutableDict_setValueForKey: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("setValue"),
+ &Ctx.Idents.get("forKey")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
}
return (NSDictionarySelectors[MK] = Sel);
}
@@ -227,6 +265,63 @@
return None;
}
+Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const {
+ if (NSSetSelectors[MK].isNull()) {
+ Selector Sel;
+ switch (MK) {
+ case NSMutableSet_addObject:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));
+ break;
+ case NSOrderedSet_insertObjectAtIndex: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("insertObject"),
+ &Ctx.Idents.get("atIndex")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSOrderedSet_setObjectAtIndex: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("setObject"),
+ &Ctx.Idents.get("atIndex")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSOrderedSet_setObjectAtIndexedSubscript: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("setObject"),
+ &Ctx.Idents.get("atIndexedSubscript")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSOrderedSet_replaceObjectAtIndexWithObject: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("replaceObjectAtIndex"),
+ &Ctx.Idents.get("withObject")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ }
+ return (NSSetSelectors[MK] = Sel);
+ }
+
+ return NSSetSelectors[MK];
+}
+
+Optional<NSAPI::NSSetMethodKind>
+NSAPI::getNSSetMethodKind(Selector Sel) {
+ for (unsigned i = 0; i != NumNSSetMethods; ++i) {
+ NSSetMethodKind MK = NSSetMethodKind(i);
+ if (Sel == getNSSetSelector(MK))
+ return MK;
+ }
+
+ return None;
+}
+
Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
bool Instance) const {
static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 3753d27..ba92587 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -1872,14 +1872,14 @@
return;
if (NewAlignment > Alignment) {
- assert(llvm::isPowerOf2_32(NewAlignment.getQuantity() &&
- "Alignment not a power of 2"));
+ assert(llvm::isPowerOf2_64(NewAlignment.getQuantity()) &&
+ "Alignment not a power of 2");
Alignment = NewAlignment;
}
if (UnpackedNewAlignment > UnpackedAlignment) {
- assert(llvm::isPowerOf2_32(UnpackedNewAlignment.getQuantity() &&
- "Alignment not a power of 2"));
+ assert(llvm::isPowerOf2_64(UnpackedNewAlignment.getQuantity()) &&
+ "Alignment not a power of 2");
UnpackedAlignment = UnpackedNewAlignment;
}
}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 64b1897..8c76009 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -1291,27 +1291,56 @@
return new (Mem) OMPSharedClause(N);
}
-OMPLinearClause *OMPLinearClause::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation ColonLoc,
- SourceLocation EndLoc,
- ArrayRef<Expr *> VL, Expr *Step) {
+void OMPLinearClause::setInits(ArrayRef<Expr *> IL) {
+ assert(IL.size() == varlist_size() &&
+ "Number of inits is not the same as the preallocated buffer");
+ std::copy(IL.begin(), IL.end(), varlist_end());
+}
+
+void OMPLinearClause::setUpdates(ArrayRef<Expr *> UL) {
+ assert(UL.size() == varlist_size() &&
+ "Number of updates is not the same as the preallocated buffer");
+ std::copy(UL.begin(), UL.end(), getInits().end());
+}
+
+void OMPLinearClause::setFinals(ArrayRef<Expr *> FL) {
+ assert(FL.size() == varlist_size() &&
+ "Number of final updates is not the same as the preallocated buffer");
+ std::copy(FL.begin(), FL.end(), getUpdates().end());
+}
+
+OMPLinearClause *
+OMPLinearClause::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation ColonLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL,
+ ArrayRef<Expr *> IL, Expr *Step, Expr *CalcStep) {
+ // Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions
+ // (Step and CalcStep).
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * (VL.size() + 1));
+ (4 * VL.size() + 2) * sizeof(Expr *));
OMPLinearClause *Clause = new (Mem)
OMPLinearClause(StartLoc, LParenLoc, ColonLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
+ Clause->setInits(IL);
+ // Fill update and final expressions with zeroes, they are provided later,
+ // after the directive construction.
+ std::fill(Clause->getInits().end(), Clause->getInits().end() + VL.size(),
+ nullptr);
+ std::fill(Clause->getUpdates().end(), Clause->getUpdates().end() + VL.size(),
+ nullptr);
Clause->setStep(Step);
+ Clause->setCalcStep(CalcStep);
return Clause;
}
OMPLinearClause *OMPLinearClause::CreateEmpty(const ASTContext &C,
unsigned NumVars) {
+ // Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions
+ // (Step and CalcStep).
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * (NumVars + 1));
+ (4 * NumVars + 2) * sizeof(Expr *));
return new (Mem) OMPLinearClause(NumVars);
}
@@ -1359,17 +1388,41 @@
return new (Mem) OMPCopyinClause(N);
}
-OMPCopyprivateClause *OMPCopyprivateClause::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc,
- ArrayRef<Expr *> VL) {
+void OMPCopyprivateClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) {
+ assert(SrcExprs.size() == varlist_size() && "Number of source expressions is "
+ "not the same as the "
+ "preallocated buffer");
+ std::copy(SrcExprs.begin(), SrcExprs.end(), varlist_end());
+}
+
+void OMPCopyprivateClause::setDestinationExprs(ArrayRef<Expr *> DstExprs) {
+ assert(DstExprs.size() == varlist_size() && "Number of destination "
+ "expressions is not the same as "
+ "the preallocated buffer");
+ std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end());
+}
+
+void OMPCopyprivateClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) {
+ assert(AssignmentOps.size() == varlist_size() &&
+ "Number of assignment expressions is not the same as the preallocated "
+ "buffer");
+ std::copy(AssignmentOps.begin(), AssignmentOps.end(),
+ getDestinationExprs().end());
+}
+
+OMPCopyprivateClause *OMPCopyprivateClause::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
+ ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
+ 4 * sizeof(Expr *) * VL.size());
OMPCopyprivateClause *Clause =
new (Mem) OMPCopyprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
+ Clause->setSourceExprs(SrcExprs);
+ Clause->setDestinationExprs(DstExprs);
+ Clause->setAssignmentOps(AssignmentOps);
return Clause;
}
@@ -1377,7 +1430,7 @@
unsigned N) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ 4 * sizeof(Expr *) * N);
return new (Mem) OMPCopyprivateClause(N);
}
@@ -1957,16 +2010,19 @@
OMPAtomicDirective *
OMPAtomicDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses,
- Stmt *AssociatedStmt, Expr *X, Expr *V, Expr *E) {
+ Stmt *AssociatedStmt, BinaryOperatorKind OpKind,
+ Expr *X, Expr *XRVal, Expr *V, Expr *E) {
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective),
llvm::alignOf<OMPClause *>());
void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
- 4 * sizeof(Stmt *));
+ 5 * sizeof(Stmt *));
OMPAtomicDirective *Dir =
new (Mem) OMPAtomicDirective(StartLoc, EndLoc, Clauses.size());
+ Dir->setOpKind(OpKind);
Dir->setClauses(Clauses);
Dir->setAssociatedStmt(AssociatedStmt);
Dir->setX(X);
+ Dir->setXRVal(X);
Dir->setV(V);
Dir->setExpr(E);
return Dir;
@@ -1978,7 +2034,7 @@
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective),
llvm::alignOf<OMPClause *>());
void *Mem =
- C.Allocate(Size + sizeof(OMPClause *) * NumClauses + 4 * sizeof(Stmt *));
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + 5 * sizeof(Stmt *));
return new (Mem) OMPAtomicDirective(NumClauses);
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index d6e0deb..8f0edd0 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1069,7 +1069,8 @@
// Emit suffixes. Integer literals are always a builtin integer type.
switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for integer literal!");
- case BuiltinType::SChar: OS << "i8"; break;
+ case BuiltinType::Char_S:
+ case BuiltinType::Char_U: OS << "i8"; break;
case BuiltinType::UChar: OS << "Ui8"; break;
case BuiltinType::Short: OS << "i16"; break;
case BuiltinType::UShort: OS << "Ui16"; break;
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index d1f25d6..f29f6a8 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -359,7 +359,17 @@
}
void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->inits()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->updates()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->finals()) {
+ Profiler->VisitStmt(E);
+ }
Profiler->VisitStmt(C->getStep());
+ Profiler->VisitStmt(C->getCalcStep());
}
void OMPClauseProfiler::VisitOMPAlignedClause(const OMPAlignedClause *C) {
VisitOMPClauseList(C);
@@ -371,6 +381,15 @@
void
OMPClauseProfiler::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->source_exprs()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->destination_exprs()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->assignment_ops()) {
+ Profiler->VisitStmt(E);
+ }
}
void OMPClauseProfiler::VisitOMPFlushClause(const OMPFlushClause *C) {
VisitOMPClauseList(C);
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index ace5fc3..0e8b1e8 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -170,15 +170,7 @@
VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType,
VectorKind vecKind)
- : Type(Vector, canonType, vecType->isDependentType(),
- vecType->isInstantiationDependentType(),
- vecType->isVariablyModifiedType(),
- vecType->containsUnexpandedParameterPack()),
- ElementType(vecType)
-{
- VectorTypeBits.VecKind = vecKind;
- VectorTypeBits.NumElements = nElements;
-}
+ : VectorType(Vector, vecType, nElements, canonType, vecKind) {}
VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements,
QualType canonType, VectorKind vecKind)
@@ -640,12 +632,13 @@
bool Type::isIntegralType(ASTContext &Ctx) const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
- BT->getKind() <= BuiltinType::Int128;
-
+ BT->getKind() <= BuiltinType::Int128;
+
+ // Complete enum types are integral in C.
if (!Ctx.getLangOpts().CPlusPlus)
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
- return ET->getDecl()->isComplete(); // Complete enum types are integral in C.
-
+ return ET->getDecl()->isComplete();
+
return false;
}
@@ -1721,7 +1714,7 @@
if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
return true;
- if (EST == EST_Dynamic && ResultIfDependent == true) {
+ if (EST == EST_Dynamic && ResultIfDependent) {
// A dynamic exception specification is throwing unless every exception
// type is an (unexpanded) pack expansion type.
for (unsigned I = 0, N = NumExceptions; I != N; ++I)
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 0f6a2a8..3928fe8 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -110,7 +110,7 @@
};
}
-static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals) {
+static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals, bool C99) {
bool appendSpace = false;
if (TypeQuals & Qualifiers::Const) {
OS << "const";
@@ -123,7 +123,11 @@
}
if (TypeQuals & Qualifiers::Restrict) {
if (appendSpace) OS << ' ';
- OS << "restrict";
+ if (C99) {
+ OS << "restrict";
+ } else {
+ OS << "__restrict";
+ }
}
}
@@ -432,7 +436,7 @@
raw_ostream &OS) {
OS << '[';
if (T->getIndexTypeQualifiers().hasQualifiers()) {
- AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers());
+ AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), Policy.LangOpts.C99);
OS << ' ';
}
@@ -465,7 +469,7 @@
raw_ostream &OS) {
OS << '[';
if (T->getIndexTypeQualifiers().hasQualifiers()) {
- AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers());
+ AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), Policy.LangOpts.C99);
OS << ' ';
}
@@ -709,7 +713,7 @@
if (unsigned quals = T->getTypeQuals()) {
OS << ' ';
- AppendTypeQualList(OS, quals);
+ AppendTypeQualList(OS, quals, Policy.LangOpts.C99);
}
switch (T->getRefQualifier()) {
@@ -1473,7 +1477,7 @@
unsigned quals = getCVRQualifiers();
if (quals) {
- AppendTypeQualList(OS, quals);
+ AppendTypeQualList(OS, quals, Policy.LangOpts.C99);
addSpace = true;
}
if (unsigned addrspace = getAddressSpace()) {
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 4e7715d..9a768a9 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -2589,7 +2589,9 @@
// Only include the RTTI component if we know that we will provide a
// definition of the vftable.
HasRTTIComponent = Context.getLangOpts().RTTIData &&
- !MostDerivedClass->hasAttr<DLLImportAttr>();
+ !MostDerivedClass->hasAttr<DLLImportAttr>() &&
+ MostDerivedClass->getTemplateSpecializationKind() !=
+ TSK_ExplicitInstantiationDeclaration;
LayoutVFTable();
@@ -2629,8 +2631,6 @@
void dumpLayout(raw_ostream &);
};
-} // end namespace
-
/// InitialOverriddenDefinitionCollector - Finds the set of least derived bases
/// that define the given method.
struct InitialOverriddenDefinitionCollector {
@@ -2645,6 +2645,8 @@
}
};
+} // end namespace
+
static bool BaseInSet(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, void *BasesSet) {
BasesSetVectorTy *Bases = (BasesSetVectorTy *)BasesSet;
diff --git a/lib/ASTMatchers/CMakeLists.txt b/lib/ASTMatchers/CMakeLists.txt
index 8a8e8c3..b49528e 100644
--- a/lib/ASTMatchers/CMakeLists.txt
+++ b/lib/ASTMatchers/CMakeLists.txt
@@ -8,4 +8,5 @@
LINK_LIBS
clangAST
+ clangBasic
)
diff --git a/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
index b0abdc7..f6d3449 100644
--- a/lib/ASTMatchers/Dynamic/Diagnostics.cpp
+++ b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
@@ -12,7 +12,6 @@
namespace clang {
namespace ast_matchers {
namespace dynamic {
-
Diagnostics::ArgStream Diagnostics::pushContextFrame(ContextType Type,
SourceRange Range) {
ContextStack.push_back(ContextFrame());
@@ -75,7 +74,7 @@
return ArgStream(&Last.Messages.back().Args);
}
-StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {
+static StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {
switch (Type) {
case Diagnostics::CT_MatcherConstruct:
return "Error building matcher $0.";
@@ -85,7 +84,7 @@
llvm_unreachable("Unknown ContextType value.");
}
-StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
+static StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
switch (Type) {
case Diagnostics::ET_RegistryMatcherNotFound:
return "Matcher not found: $0";
@@ -130,8 +129,9 @@
llvm_unreachable("Unknown ErrorType value.");
}
-void formatErrorString(StringRef FormatString, ArrayRef<std::string> Args,
- llvm::raw_ostream &OS) {
+static void formatErrorString(StringRef FormatString,
+ ArrayRef<std::string> Args,
+ llvm::raw_ostream &OS) {
while (!FormatString.empty()) {
std::pair<StringRef, StringRef> Pieces = FormatString.split("$");
OS << Pieces.first.str();
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index c074279..e46e6da 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -198,6 +198,7 @@
REGISTER_MATCHER(hasIncrement);
REGISTER_MATCHER(hasIndex);
REGISTER_MATCHER(hasInitializer);
+ REGISTER_MATCHER(hasKeywordSelector);
REGISTER_MATCHER(hasLHS);
REGISTER_MATCHER(hasLocalQualifiers);
REGISTER_MATCHER(hasLocalStorage);
@@ -205,6 +206,7 @@
REGISTER_MATCHER(hasLoopVariable);
REGISTER_MATCHER(hasMethod);
REGISTER_MATCHER(hasName);
+ REGISTER_MATCHER(hasNullSelector);
REGISTER_MATCHER(hasObjectExpression);
REGISTER_MATCHER(hasOperatorName);
REGISTER_MATCHER(hasOverloadedOperatorName);
@@ -212,7 +214,9 @@
REGISTER_MATCHER(hasParent);
REGISTER_MATCHER(hasQualifier);
REGISTER_MATCHER(hasRangeInit);
+ REGISTER_MATCHER(hasReceiverType);
REGISTER_MATCHER(hasRHS);
+ REGISTER_MATCHER(hasSelector);
REGISTER_MATCHER(hasSingleDecl);
REGISTER_MATCHER(hasSize);
REGISTER_MATCHER(hasSizeExpr);
@@ -223,6 +227,7 @@
REGISTER_MATCHER(hasTrueExpression);
REGISTER_MATCHER(hasTypeLoc);
REGISTER_MATCHER(hasUnaryOperand);
+ REGISTER_MATCHER(hasUnarySelector);
REGISTER_MATCHER(hasValueType);
REGISTER_MATCHER(ifStmt);
REGISTER_MATCHER(ignoringImpCasts);
@@ -262,6 +267,7 @@
REGISTER_MATCHER(lambdaExpr);
REGISTER_MATCHER(lValueReferenceType);
REGISTER_MATCHER(matchesName);
+ REGISTER_MATCHER(matchesSelector);
REGISTER_MATCHER(materializeTemporaryExpr);
REGISTER_MATCHER(member);
REGISTER_MATCHER(memberCallExpr);
@@ -276,7 +282,9 @@
REGISTER_MATCHER(newExpr);
REGISTER_MATCHER(nullPtrLiteralExpr);
REGISTER_MATCHER(nullStmt);
+ REGISTER_MATCHER(numSelectorArgs);
REGISTER_MATCHER(ofClass);
+ REGISTER_MATCHER(objcMessageExpr);
REGISTER_MATCHER(on);
REGISTER_MATCHER(onImplicitObjectArgument);
REGISTER_MATCHER(operatorCallExpr);
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 5d06634..169f1df 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -841,12 +841,12 @@
// must be false.
llvm::APSInt IntVal;
if (Bop->getLHS()->EvaluateAsInt(IntVal, *Context)) {
- if (IntVal.getBoolValue() == false) {
+ if (!IntVal.getBoolValue()) {
return TryResult(false);
}
}
if (Bop->getRHS()->EvaluateAsInt(IntVal, *Context)) {
- if (IntVal.getBoolValue() == false) {
+ if (!IntVal.getBoolValue()) {
return TryResult(false);
}
}
diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp
index 2b2da2c..967f3e1 100644
--- a/lib/Analysis/Consumed.cpp
+++ b/lib/Analysis/Consumed.cpp
@@ -946,10 +946,9 @@
namespace clang {
namespace consumed {
-void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
- ConsumedStateMap *ThenStates,
- ConsumedStateMap *ElseStates) {
-
+static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test,
+ ConsumedStateMap *ThenStates,
+ ConsumedStateMap *ElseStates) {
ConsumedState VarState = ThenStates->getState(Test.Var);
if (VarState == CS_Unknown) {
@@ -964,9 +963,9 @@
}
}
-void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
- ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
-
+static void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
+ ConsumedStateMap *ThenStates,
+ ConsumedStateMap *ElseStates) {
const VarTestResult <est = PInfo.getLTest(),
&RTest = PInfo.getRTest();
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index 662166c..1b60894 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -256,16 +256,17 @@
// Methods on ArgType.
//===----------------------------------------------------------------------===//
-bool ArgType::matchesType(ASTContext &C, QualType argTy) const {
+clang::analyze_format_string::ArgType::MatchKind
+ArgType::matchesType(ASTContext &C, QualType argTy) const {
if (Ptr) {
// It has to be a pointer.
const PointerType *PT = argTy->getAs<PointerType>();
if (!PT)
- return false;
+ return NoMatch;
// We cannot write through a const qualified pointer.
if (PT->getPointeeType().isConstQualified())
- return false;
+ return NoMatch;
argTy = PT->getPointeeType();
}
@@ -275,8 +276,8 @@
llvm_unreachable("ArgType must be valid");
case UnknownTy:
- return true;
-
+ return Match;
+
case AnyCharTy: {
if (const EnumType *ETy = argTy->getAs<EnumType>())
argTy = ETy->getDecl()->getIntegerType();
@@ -289,18 +290,18 @@
case BuiltinType::SChar:
case BuiltinType::UChar:
case BuiltinType::Char_U:
- return true;
+ return Match;
}
- return false;
+ return NoMatch;
}
-
+
case SpecificTy: {
if (const EnumType *ETy = argTy->getAs<EnumType>())
argTy = ETy->getDecl()->getIntegerType();
argTy = C.getCanonicalType(argTy).getUnqualifiedType();
if (T == argTy)
- return true;
+ return Match;
// Check for "compatible types".
if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
switch (BT->getKind()) {
@@ -309,32 +310,33 @@
case BuiltinType::Char_S:
case BuiltinType::SChar:
case BuiltinType::Char_U:
- case BuiltinType::UChar:
- return T == C.UnsignedCharTy || T == C.SignedCharTy;
+ case BuiltinType::UChar:
+ return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
+ : NoMatch;
case BuiltinType::Short:
- return T == C.UnsignedShortTy;
+ return T == C.UnsignedShortTy ? Match : NoMatch;
case BuiltinType::UShort:
- return T == C.ShortTy;
+ return T == C.ShortTy ? Match : NoMatch;
case BuiltinType::Int:
- return T == C.UnsignedIntTy;
+ return T == C.UnsignedIntTy ? Match : NoMatch;
case BuiltinType::UInt:
- return T == C.IntTy;
+ return T == C.IntTy ? Match : NoMatch;
case BuiltinType::Long:
- return T == C.UnsignedLongTy;
+ return T == C.UnsignedLongTy ? Match : NoMatch;
case BuiltinType::ULong:
- return T == C.LongTy;
+ return T == C.LongTy ? Match : NoMatch;
case BuiltinType::LongLong:
- return T == C.UnsignedLongLongTy;
+ return T == C.UnsignedLongLongTy ? Match : NoMatch;
case BuiltinType::ULongLong:
- return T == C.LongLongTy;
+ return T == C.LongLongTy ? Match : NoMatch;
}
- return false;
+ return NoMatch;
}
case CStrTy: {
const PointerType *PT = argTy->getAs<PointerType>();
if (!PT)
- return false;
+ return NoMatch;
QualType pointeeTy = PT->getPointeeType();
if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
switch (BT->getKind()) {
@@ -343,50 +345,56 @@
case BuiltinType::UChar:
case BuiltinType::Char_S:
case BuiltinType::SChar:
- return true;
+ return Match;
default:
break;
}
- return false;
+ return NoMatch;
}
case WCStrTy: {
const PointerType *PT = argTy->getAs<PointerType>();
if (!PT)
- return false;
+ return NoMatch;
QualType pointeeTy =
C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
- return pointeeTy == C.getWideCharType();
+ return pointeeTy == C.getWideCharType() ? Match : NoMatch;
}
-
+
case WIntTy: {
-
+
QualType PromoArg =
argTy->isPromotableIntegerType()
? C.getPromotedIntegerType(argTy) : argTy;
-
+
QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();
PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
-
+
// If the promoted argument is the corresponding signed type of the
// wint_t type, then it should match.
if (PromoArg->hasSignedIntegerRepresentation() &&
C.getCorrespondingUnsignedType(PromoArg) == WInt)
- return true;
+ return Match;
- return WInt == PromoArg;
+ return WInt == PromoArg ? Match : NoMatch;
}
case CPointerTy:
- return argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
- argTy->isBlockPointerType() || argTy->isNullPtrType();
+ if (argTy->isVoidPointerType()) {
+ return Match;
+ } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
+ argTy->isBlockPointerType() || argTy->isNullPtrType()) {
+ return NoMatchPedantic;
+ } else {
+ return NoMatch;
+ }
case ObjCPointerTy: {
if (argTy->getAs<ObjCObjectPointerType>() ||
argTy->getAs<BlockPointerType>())
- return true;
-
+ return Match;
+
// Handle implicit toll-free bridging.
if (const PointerType *PT = argTy->getAs<PointerType>()) {
// Things such as CFTypeRef are really just opaque pointers
@@ -395,9 +403,9 @@
// structs can be toll-free bridged, we just accept them all.
QualType pointee = PT->getPointeeType();
if (pointee->getAsStructureType() || pointee->isVoidType())
- return true;
+ return Match;
}
- return false;
+ return NoMatch;
}
}
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 37819a7..e2c6ab5 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -44,14 +44,13 @@
#include <sstream>
#include <utility>
#include <vector>
-
-
-namespace clang {
-namespace threadSafety {
+using namespace clang;
+using namespace threadSafety;
// Key method definition
ThreadSafetyHandler::~ThreadSafetyHandler() {}
+namespace {
class TILPrinter :
public til::PrettyPrinter<TILPrinter, llvm::raw_ostream> {};
@@ -69,7 +68,6 @@
Handler.handleInvalidLockExp(Kind, Loc);
}
-
/// \brief A set of CapabilityInfo objects, which are compiled from the
/// requires attributes on a function.
class CapExprSet : public SmallVector<CapabilityExpr, 4> {
@@ -250,10 +248,11 @@
}
};
-
class ThreadSafetyAnalyzer;
+} // namespace
-
+namespace clang {
+namespace threadSafety {
class BeforeSet {
private:
typedef SmallVector<const ValueDecl*, 4> BeforeVect;
@@ -286,9 +285,10 @@
BeforeMap BMap;
CycleMap CycMap;
};
+} // end namespace threadSafety
+} // end namespace clang
-
-
+namespace {
typedef llvm::ImmutableMap<const NamedDecl*, unsigned> LocalVarContext;
class LocalVariableMap;
@@ -903,7 +903,7 @@
/// \brief Class which implements the core thread safety analysis routines.
class ThreadSafetyAnalyzer {
friend class BuildLockset;
- friend class BeforeSet;
+ friend class threadSafety::BeforeSet;
llvm::BumpPtrAllocator Bpa;
threadSafety::til::MemRegionRef Arena;
@@ -959,8 +959,7 @@
void runAnalysis(AnalysisDeclContext &AC);
};
-
-
+} // namespace
/// Process acquired_before and acquired_after attributes on Vd.
BeforeSet::BeforeInfo* BeforeSet::insertAttrExprs(const ValueDecl* Vd,
@@ -1103,6 +1102,7 @@
return nullptr;
}
+namespace {
template <typename Ty>
class has_arg_iterator_range {
typedef char yes[1];
@@ -1117,6 +1117,7 @@
public:
static const bool value = sizeof(test<Ty>(nullptr)) == sizeof(yes);
};
+} // namespace
static StringRef ClassifyDiagnostic(const CapabilityAttr *A) {
return A->getName();
@@ -1307,8 +1308,7 @@
}
}
-
-bool getStaticBooleanValue(Expr* E, bool& TCond) {
+static bool getStaticBooleanValue(Expr *E, bool &TCond) {
if (isa<CXXNullPtrLiteralExpr>(E) || isa<GNUNullExpr>(E)) {
TCond = false;
return true;
@@ -1453,6 +1453,7 @@
CapDiagKind);
}
+namespace {
/// \brief We use this class to visit different types of expressions in
/// CFGBlocks, and build up the lockset.
/// An expression may cause us to add or remove locks from the lockset, or else
@@ -1496,7 +1497,7 @@
void VisitCXXConstructExpr(CXXConstructExpr *Exp);
void VisitDeclStmt(DeclStmt *S);
};
-
+} // namespace
/// \brief Warn if the LSet does not contain a lock sufficient to protect access
/// of at least the passed in AccessKind.
@@ -2059,7 +2060,7 @@
// Return true if block B never continues to its successors.
-inline bool neverReturns(const CFGBlock* B) {
+static bool neverReturns(const CFGBlock *B) {
if (B->hasNoReturnElement())
return true;
if (B->empty())
@@ -2305,8 +2306,8 @@
// Create a dummy expression,
VarDecl *VD = const_cast<VarDecl*>(AD.getVarDecl());
- DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue,
- AD.getTriggerStmt()->getLocEnd());
+ DeclRefExpr DRE(VD, false, VD->getType().getNonReferenceType(),
+ VK_LValue, AD.getTriggerStmt()->getLocEnd());
LocksetBuilder.handleCall(&DRE, DD);
break;
}
@@ -2376,24 +2377,20 @@
/// We traverse the blocks in the CFG, compute the set of mutexes that are held
/// at the end of each block, and issue warnings for thread safety violations.
/// Each block in the CFG is traversed exactly once.
-void runThreadSafetyAnalysis(AnalysisDeclContext &AC,
- ThreadSafetyHandler &Handler,
- BeforeSet **BSet) {
+void threadSafety::runThreadSafetyAnalysis(AnalysisDeclContext &AC,
+ ThreadSafetyHandler &Handler,
+ BeforeSet **BSet) {
if (!*BSet)
*BSet = new BeforeSet;
ThreadSafetyAnalyzer Analyzer(Handler, *BSet);
Analyzer.runAnalysis(AC);
}
-
-void threadSafetyCleanup(BeforeSet* Cache) {
- delete Cache;
-}
-
+void threadSafety::threadSafetyCleanup(BeforeSet *Cache) { delete Cache; }
/// \brief Helper function that returns a LockKind required for the given level
/// of access.
-LockKind getLockKindFromAccessKind(AccessKind AK) {
+LockKind threadSafety::getLockKindFromAccessKind(AccessKind AK) {
switch (AK) {
case AK_Read :
return LK_Shared;
@@ -2402,5 +2399,3 @@
}
llvm_unreachable("Unknown AccessKind");
}
-
-}} // end namespace clang::threadSafety
diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp
index 563e059..d4b1ce2 100644
--- a/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/lib/Analysis/ThreadSafetyCommon.cpp
@@ -31,13 +31,11 @@
#include <algorithm>
#include <climits>
#include <vector>
-
-
-namespace clang {
-namespace threadSafety {
+using namespace clang;
+using namespace threadSafety;
// From ThreadSafetyUtil.h
-std::string getSourceLiteralString(const clang::Expr *CE) {
+std::string threadSafety::getSourceLiteralString(const clang::Expr *CE) {
switch (CE->getStmtClass()) {
case Stmt::IntegerLiteralClass:
return cast<IntegerLiteral>(CE)->getValue().toString(10, true);
@@ -59,18 +57,13 @@
}
}
-namespace til {
-
// Return true if E is a variable that points to an incomplete Phi node.
-static bool isIncompletePhi(const SExpr *E) {
- if (const auto *Ph = dyn_cast<Phi>(E))
- return Ph->status() == Phi::PH_Incomplete;
+static bool isIncompletePhi(const til::SExpr *E) {
+ if (const auto *Ph = dyn_cast<til::Phi>(E))
+ return Ph->status() == til::Phi::PH_Incomplete;
return false;
}
-} // end namespace til
-
-
typedef SExprBuilder::CallingContext CallingContext;
@@ -87,9 +80,7 @@
return Scfg;
}
-
-
-inline bool isCalleeArrow(const Expr *E) {
+static bool isCalleeArrow(const Expr *E) {
const MemberExpr *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts());
return ME ? ME->isArrow() : false;
}
@@ -313,8 +304,7 @@
return SelfVar;
}
-
-const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) {
+static const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) {
if (auto *V = dyn_cast<til::Variable>(E))
return V->clangDecl();
if (auto *Ph = dyn_cast<til::Phi>(E))
@@ -326,7 +316,7 @@
return 0;
}
-bool hasCppPointerType(const til::SExpr *E) {
+static bool hasCppPointerType(const til::SExpr *E) {
auto *VD = getValueDeclFromSExpr(E);
if (VD && VD->getType()->isPointerType())
return true;
@@ -336,9 +326,8 @@
return false;
}
-
// Grab the very first declaration of virtual method D
-const CXXMethodDecl* getFirstVirtualDecl(const CXXMethodDecl *D) {
+static const CXXMethodDecl *getFirstVirtualDecl(const CXXMethodDecl *D) {
while (true) {
D = D->getCanonicalDecl();
CXXMethodDecl::method_iterator I = D->begin_overridden_methods(),
@@ -663,7 +652,7 @@
// if E is a til::Variable, update its clangDecl.
-inline void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) {
+static void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) {
if (!E)
return;
if (til::Variable *V = dyn_cast<til::Variable>(E)) {
@@ -986,8 +975,3 @@
TILPrinter::print(Scfg, llvm::errs());
}
*/
-
-
-} // end namespace threadSafety
-
-} // end namespace clang
diff --git a/lib/Analysis/ThreadSafetyTIL.cpp b/lib/Analysis/ThreadSafetyTIL.cpp
index ebe374e..2923f7e 100644
--- a/lib/Analysis/ThreadSafetyTIL.cpp
+++ b/lib/Analysis/ThreadSafetyTIL.cpp
@@ -9,13 +9,11 @@
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
+using namespace clang;
+using namespace threadSafety;
+using namespace til;
-namespace clang {
-namespace threadSafety {
-namespace til {
-
-
-StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op) {
+StringRef til::getUnaryOpcodeString(TIL_UnaryOpcode Op) {
switch (Op) {
case UOP_Minus: return "-";
case UOP_BitNot: return "~";
@@ -24,8 +22,7 @@
return "";
}
-
-StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op) {
+StringRef til::getBinaryOpcodeString(TIL_BinaryOpcode Op) {
switch (Op) {
case BOP_Mul: return "*";
case BOP_Div: return "/";
@@ -82,7 +79,7 @@
// If E is a variable, then trace back through any aliases or redundant
// Phi nodes to find the canonical definition.
-const SExpr *getCanonicalVal(const SExpr *E) {
+const SExpr *til::getCanonicalVal(const SExpr *E) {
while (true) {
if (auto *V = dyn_cast<Variable>(E)) {
if (V->kind() == Variable::VK_Let) {
@@ -105,7 +102,7 @@
// If E is a variable, then trace back through any aliases or redundant
// Phi nodes to find the canonical definition.
// The non-const version will simplify incomplete Phi nodes.
-SExpr *simplifyToCanonicalVal(SExpr *E) {
+SExpr *til::simplifyToCanonicalVal(SExpr *E) {
while (true) {
if (auto *V = dyn_cast<Variable>(E)) {
if (V->kind() != Variable::VK_Let)
@@ -135,7 +132,7 @@
// Trace the arguments of an incomplete Phi node to see if they have the same
// canonical definition. If so, mark the Phi node as redundant.
// getCanonicalVal() will recursively call simplifyIncompletePhi().
-void simplifyIncompleteArg(til::Phi *Ph) {
+void til::simplifyIncompleteArg(til::Phi *Ph) {
assert(Ph && Ph->status() == Phi::PH_Incomplete);
// eliminate infinite recursion -- assume that this node is not redundant.
@@ -337,7 +334,3 @@
computeNodeID(Block, &BasicBlock::PostDominatorNode);
}
}
-
-} // end namespace til
-} // end namespace threadSafety
-} // end namespace clang
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 61a2592..8a6870f 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
@@ -37,7 +38,7 @@
!vd->isExceptionVariable() && !vd->isInitCapture() &&
vd->getDeclContext() == dc) {
QualType ty = vd->getType();
- return ty->isScalarType() || ty->isVectorType();
+ return ty->isScalarType() || ty->isVectorType() || ty->isRecordType();
}
return false;
}
@@ -347,6 +348,7 @@
}
static const DeclRefExpr *getSelfInitExpr(VarDecl *VD) {
+ if (VD->getType()->isRecordType()) return nullptr;
if (Expr *Init = VD->getInit()) {
const DeclRefExpr *DRE
= dyn_cast<DeclRefExpr>(stripCasts(VD->getASTContext(), Init));
@@ -376,12 +378,28 @@
return;
}
- if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
- if (BO->getOpcode() == BO_Comma)
- classify(BO->getRHS(), C);
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
+ if (!VD->isStaticDataMember())
+ classify(ME->getBase(), C);
+ }
return;
}
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ switch (BO->getOpcode()) {
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ classify(BO->getLHS(), C);
+ return;
+ case BO_Comma:
+ classify(BO->getRHS(), C);
+ return;
+ default:
+ return;
+ }
+ }
+
FindVarResult Var = findVar(E, DC);
if (const DeclRefExpr *DRE = Var.getDeclRefExpr())
Classification[DRE] = std::max(Classification[DRE], C);
@@ -404,7 +422,7 @@
// use.
if (BO->isCompoundAssignmentOp())
classify(BO->getLHS(), Use);
- else if (BO->getOpcode() == BO_Assign)
+ else if (BO->getOpcode() == BO_Assign || BO->getOpcode() == BO_Comma)
classify(BO->getLHS(), Ignore);
}
@@ -415,25 +433,40 @@
classify(UO->getSubExpr(), Use);
}
+static bool isPointerToConst(const QualType &QT) {
+ return QT->isAnyPointerType() && QT->getPointeeType().isConstQualified();
+}
+
void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
// Classify arguments to std::move as used.
if (CE->getNumArgs() == 1) {
if (FunctionDecl *FD = CE->getDirectCallee()) {
if (FD->isInStdNamespace() && FD->getIdentifier() &&
FD->getIdentifier()->isStr("move")) {
- classify(CE->getArg(0), Use);
+ // RecordTypes are handled in SemaDeclCXX.cpp.
+ if (!CE->getArg(0)->getType()->isRecordType())
+ classify(CE->getArg(0), Use);
return;
}
}
}
- // If a value is passed by const reference to a function, we should not assume
- // that it is initialized by the call, and we conservatively do not assume
- // that it is used.
+ // If a value is passed by const pointer or by const reference to a function,
+ // we should not assume that it is initialized by the call, and we
+ // conservatively do not assume that it is used.
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
- I != E; ++I)
- if ((*I)->getType().isConstQualified() && (*I)->isGLValue())
- classify(*I, Ignore);
+ I != E; ++I) {
+ if ((*I)->isGLValue()) {
+ if ((*I)->getType().isConstQualified())
+ classify((*I), Ignore);
+ } else if (isPointerToConst((*I)->getType())) {
+ const Expr *Ex = stripCasts(DC->getParentASTContext(), *I);
+ const UnaryOperator *UO = dyn_cast<UnaryOperator>(Ex);
+ if (UO && UO->getOpcode() == UO_AddrOf)
+ Ex = UO->getSubExpr();
+ classify(Ex, Ignore);
+ }
+ }
}
void ClassifyRefs::VisitCastExpr(CastExpr *CE) {
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 1c68375..643503b 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -528,7 +528,7 @@
// An empty group is considered to be a warning group: we have empty groups
// for GCC compatibility, and GCC does not have remarks.
if (!Group->Members && !Group->SubGroups)
- return Flavor == diag::Flavor::Remark ? true : false;
+ return Flavor == diag::Flavor::Remark;
bool NotFound = true;
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 214e0f3..c46e2c7 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -430,7 +430,7 @@
SmallString<128> FilePath(Entry->getName());
FixupRelativePath(FilePath);
- return FS->getBufferForFile(FilePath.str(), FileSize,
+ return FS->getBufferForFile(FilePath, FileSize,
/*RequiresNullTerminator=*/true, isVolatile);
}
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 613b43f..bd2840d 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -105,10 +105,12 @@
KEYOPENCL = 0x200,
KEYC11 = 0x400,
KEYARC = 0x800,
- KEYNOMS = 0x01000,
- WCHARSUPPORT = 0x02000,
- HALFSUPPORT = 0x04000,
- KEYALL = (0xffff & ~KEYNOMS) // Because KEYNOMS is used to exclude.
+ KEYNOMS18 = 0x01000,
+ KEYNOOPENCL = 0x02000,
+ WCHARSUPPORT = 0x04000,
+ HALFSUPPORT = 0x08000,
+ KEYALL = (0xffff & ~KEYNOMS18 &
+ ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude.
};
/// \brief How a keyword is treated in the selected standard.
@@ -154,8 +156,14 @@
KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags);
// Don't add this keyword under MSVCCompat.
- if (LangOpts.MSVCCompat && (Flags & KEYNOMS))
- return;
+ if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&
+ !LangOpts.isCompatibleWithMSVC(19))
+ return;
+
+ // Don't add this keyword under OpenCL.
+ if (LangOpts.OpenCL && (Flags & KEYNOOPENCL))
+ return;
+
// Don't add this keyword if disabled in this language.
if (AddResult == KS_Disabled) return;
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index e7e37ce..5fad1a9 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -158,6 +158,19 @@
return llvm::makeArrayRef(TopHeaders.begin(), TopHeaders.end());
}
+bool Module::directlyUses(const Module *Requested) const {
+ auto *Top = getTopLevelModule();
+
+ // A top-level module implicitly uses itself.
+ if (Requested->isSubModuleOf(Top))
+ return true;
+
+ for (auto *Use : Top->DirectUses)
+ if (Requested->isSubModuleOf(Use))
+ return true;
+ return false;
+}
+
void Module::addRequirement(StringRef Feature, bool RequiredState,
const LangOptions &LangOpts,
const TargetInfo &Target) {
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 305dcd4..118e3f3 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -2076,22 +2076,33 @@
return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
}
- // This can happen if a location is in a built-ins buffer.
- // But see PR5662.
+ // If we arrived here, the location is either in a built-ins buffer or
+ // associated with global inline asm. PR5662 and PR22576 are examples.
+
// Clear the lookup cache, it depends on a common location.
IsBeforeInTUCache.clear();
- bool LIsBuiltins = strcmp("<built-in>",
- getBuffer(LOffs.first)->getBufferIdentifier()) == 0;
- bool RIsBuiltins = strcmp("<built-in>",
- getBuffer(ROffs.first)->getBufferIdentifier()) == 0;
- // built-in is before non-built-in
- if (LIsBuiltins != RIsBuiltins)
- return LIsBuiltins;
- assert(LIsBuiltins && RIsBuiltins &&
- "Non-built-in locations must be rooted in the main file");
- // Both are in built-in buffers, but from different files. We just claim that
- // lower IDs come first.
- return LOffs.first < ROffs.first;
+ llvm::MemoryBuffer *LBuf = getBuffer(LOffs.first);
+ llvm::MemoryBuffer *RBuf = getBuffer(ROffs.first);
+ bool LIsBuiltins = strcmp("<built-in>", LBuf->getBufferIdentifier()) == 0;
+ bool RIsBuiltins = strcmp("<built-in>", RBuf->getBufferIdentifier()) == 0;
+ // Sort built-in before non-built-in.
+ if (LIsBuiltins || RIsBuiltins) {
+ if (LIsBuiltins != RIsBuiltins)
+ return LIsBuiltins;
+ // Both are in built-in buffers, but from different files. We just claim that
+ // lower IDs come first.
+ return LOffs.first < ROffs.first;
+ }
+ bool LIsAsm = strcmp("<inline asm>", LBuf->getBufferIdentifier()) == 0;
+ bool RIsAsm = strcmp("<inline asm>", RBuf->getBufferIdentifier()) == 0;
+ // Sort assembler after built-ins, but before the rest.
+ if (LIsAsm || RIsAsm) {
+ if (LIsAsm != RIsAsm)
+ return RIsAsm;
+ assert(LOffs.first == ROffs.first);
+ return false;
+ }
+ llvm_unreachable("Unsortable locations found");
}
void SourceManager::PrintStats() const {
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 063a9be..fb73231 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -184,6 +184,28 @@
}
namespace {
+// CloudABI Target
+template <typename Target>
+class CloudABITargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__CloudABI__");
+ Builder.defineMacro("__ELF__");
+
+ // CloudABI uses ISO/IEC 10646:2012 for wchar_t, char16_t and char32_t.
+ Builder.defineMacro("__STDC_ISO_10646__", "201206L");
+ Builder.defineMacro("__STDC_UTF_16__");
+ Builder.defineMacro("__STDC_UTF_32__");
+ }
+
+public:
+ CloudABITargetInfo(const llvm::Triple &Triple)
+ : OSTargetInfo<Target>(Triple) {
+ this->UserLabelPrefix = "";
+ }
+};
+
template<typename Target>
class DarwinTargetInfo : public OSTargetInfo<Target> {
protected:
@@ -363,8 +385,13 @@
DefineStd(Builder, "linux", Opts);
Builder.defineMacro("__gnu_linux__");
Builder.defineMacro("__ELF__");
- if (Triple.getEnvironment() == llvm::Triple::Android)
+ if (Triple.getEnvironment() == llvm::Triple::Android) {
Builder.defineMacro("__ANDROID__", "1");
+ unsigned Maj, Min, Rev;
+ Triple.getOSVersion(Maj, Min, Rev);
+ this->PlatformName = "android";
+ this->PlatformMinVersion = VersionTuple(Maj, Min, Rev);
+ }
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
if (Opts.CPlusPlus)
@@ -471,6 +498,17 @@
Builder.defineMacro("__ELF__");
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
+
+ switch (Triple.getArch()) {
+ default:
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ Builder.defineMacro("__ARM_DWARF_EH__");
+ break;
+ }
}
public:
BitrigTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
@@ -617,6 +655,9 @@
Builder.defineMacro("_MSC_FULL_VER", Twine(Opts.MSCompatibilityVersion));
// FIXME We cannot encode the revision information into 32-bits
Builder.defineMacro("_MSC_BUILD", Twine(1));
+
+ if (Opts.CPlusPlus11 && Opts.isCompatibleWithMSVC(19))
+ Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1));
}
if (Opts.MicrosoftExt) {
@@ -686,13 +727,11 @@
}
}
};
-} // end anonymous namespace.
//===----------------------------------------------------------------------===//
// Specific target implementations.
//===----------------------------------------------------------------------===//
-namespace {
// PPC abstract base class
class PPCTargetInfo : public TargetInfo {
static const Builtin::Info BuiltinInfo[];
@@ -703,13 +742,17 @@
// Target cpu features.
bool HasVSX;
bool HasP8Vector;
+ bool HasP8Crypto;
+ bool HasQPX;
+ bool HasHTM;
protected:
std::string ABI;
public:
PPCTargetInfo(const llvm::Triple &Triple)
- : TargetInfo(Triple), HasVSX(false), HasP8Vector(false) {
+ : TargetInfo(Triple), HasVSX(false), HasP8Vector(false),
+ HasP8Crypto(false), HasQPX(false), HasHTM(false) {
BigEndian = (Triple.getArch() != llvm::Triple::ppc64le);
LongDoubleWidth = LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble;
@@ -940,6 +983,10 @@
if (RegNo == 1) return 4;
return -1;
}
+
+ bool hasSjLjLowering() const override {
+ return true;
+ }
};
const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
@@ -970,6 +1017,21 @@
continue;
}
+ if (Feature == "crypto") {
+ HasP8Crypto = true;
+ continue;
+ }
+
+ if (Feature == "qpx") {
+ HasQPX = true;
+ continue;
+ }
+
+ if (Feature == "htm") {
+ HasHTM = true;
+ continue;
+ }
+
// TODO: Finish this list and add an assert that we've handled them
// all.
}
@@ -1004,7 +1066,7 @@
}
// ABI options.
- if (ABI == "elfv1")
+ if (ABI == "elfv1" || ABI == "elfv1-qpx")
Builder.defineMacro("_CALL_ELF", "1");
if (ABI == "elfv2")
Builder.defineMacro("_CALL_ELF", "2");
@@ -1122,6 +1184,10 @@
Builder.defineMacro("__VSX__");
if (HasP8Vector)
Builder.defineMacro("__POWER8_VECTOR__");
+ if (HasP8Crypto)
+ Builder.defineMacro("__CRYPTO__");
+ if (HasHTM)
+ Builder.defineMacro("__HTM__");
// FIXME: The following are not yet generated here by Clang, but are
// generated by GCC:
@@ -1160,6 +1226,14 @@
.Default(false);
Features["qpx"] = (CPU == "a2q");
+ Features["crypto"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr8", true)
+ .Default(false);
+ Features["power8-vector"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr8", true)
+ .Default(false);
}
bool PPCTargetInfo::hasFeature(StringRef Feature) const {
@@ -1167,6 +1241,9 @@
.Case("powerpc", true)
.Case("vsx", HasVSX)
.Case("power8-vector", HasP8Vector)
+ .Case("crypto", HasP8Crypto)
+ .Case("qpx", HasQPX)
+ .Case("htm", HasHTM)
.Default(false);
}
@@ -1272,9 +1349,7 @@
Aliases = GCCRegAliases;
NumAliases = llvm::array_lengthof(GCCRegAliases);
}
-} // end anonymous namespace.
-namespace {
class PPC32TargetInfo : public PPCTargetInfo {
public:
PPC32TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) {
@@ -1306,11 +1381,9 @@
return TargetInfo::PowerABIBuiltinVaList;
}
};
-} // end anonymous namespace.
// Note: ABI differences may eventually require us to have a separate
// TargetInfo for little endian.
-namespace {
class PPC64TargetInfo : public PPCTargetInfo {
public:
PPC64TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) {
@@ -1347,17 +1420,14 @@
}
// PPC64 Linux-specifc ABI options.
bool setABI(const std::string &Name) override {
- if (Name == "elfv1" || Name == "elfv2") {
+ if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") {
ABI = Name;
return true;
}
return false;
}
};
-} // end anonymous namespace.
-
-namespace {
class DarwinPPC32TargetInfo :
public DarwinTargetInfo<PPC32TargetInfo> {
public:
@@ -1385,9 +1455,7 @@
DescriptionString = "E-m:o-i64:64-n32:64";
}
};
-} // end anonymous namespace.
-namespace {
static const unsigned NVPTXAddrSpaceMap[] = {
1, // opencl_global
3, // opencl_local
@@ -1538,9 +1606,6 @@
DescriptionString = "e-i64:64-v16:16-v32:32-n16:32:64";
}
};
-}
-
-namespace {
static const unsigned R600AddrSpaceMap[] = {
1, // opencl_global
@@ -1645,6 +1710,8 @@
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
Builder.defineMacro("__R600__");
+ if (GPU >= GK_SOUTHERN_ISLANDS && Opts.OpenCL)
+ Builder.defineMacro("cl_khr_fp64");
}
BuiltinVaListKind getBuiltinVaListKind() const override {
@@ -1725,9 +1792,6 @@
#include "clang/Basic/BuiltinsR600.def"
};
-} // end anonymous namespace
-
-namespace {
// Namespace for x86 abstract base class
const Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
@@ -2206,6 +2270,10 @@
CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
return MT == CCMT_Member ? CC_X86ThisCall : CC_C;
}
+
+ bool hasSjLjLowering() const override {
+ return true;
+ }
};
bool X86TargetInfo::setFPMath(StringRef Name) {
@@ -2512,11 +2580,6 @@
void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features,
StringRef Name, bool Enabled) {
- // FIXME: This *really* should not be here. We need some way of translating
- // options into llvm subtarget features.
- if (Name == "sse4")
- Name = "sse4.2";
-
Features[Name] = Enabled;
if (Name == "mmx") {
@@ -3252,9 +3315,7 @@
return std::string(1, *Constraint);
}
}
-} // end anonymous namespace
-namespace {
// X86-32 generic target
class X86_32TargetInfo : public X86TargetInfo {
public:
@@ -3309,9 +3370,7 @@
return X86TargetInfo::validateOperandSize(Constraint, Size);
}
};
-} // end anonymous namespace
-namespace {
class NetBSDI386TargetInfo : public NetBSDTargetInfo<X86_32TargetInfo> {
public:
NetBSDI386TargetInfo(const llvm::Triple &Triple)
@@ -3327,9 +3386,7 @@
return 1;
}
};
-} // end anonymous namespace
-namespace {
class OpenBSDI386TargetInfo : public OpenBSDTargetInfo<X86_32TargetInfo> {
public:
OpenBSDI386TargetInfo(const llvm::Triple &Triple)
@@ -3339,9 +3396,7 @@
PtrDiffType = SignedLong;
}
};
-} // end anonymous namespace
-namespace {
class BitrigI386TargetInfo : public BitrigTargetInfo<X86_32TargetInfo> {
public:
BitrigI386TargetInfo(const llvm::Triple &Triple)
@@ -3351,9 +3406,7 @@
PtrDiffType = SignedLong;
}
};
-} // end anonymous namespace
-namespace {
class DarwinI386TargetInfo : public DarwinTargetInfo<X86_32TargetInfo> {
public:
DarwinI386TargetInfo(const llvm::Triple &Triple)
@@ -3369,9 +3422,7 @@
}
};
-} // end anonymous namespace
-namespace {
// x86-32 Windows target
class WindowsX86_32TargetInfo : public WindowsTargetInfo<X86_32TargetInfo> {
public:
@@ -3379,7 +3430,7 @@
: WindowsTargetInfo<X86_32TargetInfo>(Triple) {
WCharType = UnsignedShort;
DoubleAlign = LongLongAlign = 64;
- DescriptionString = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32";
+ DescriptionString = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-S32";
}
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
@@ -3449,9 +3500,7 @@
addMinGWDefines(Opts, Builder);
}
};
-} // end anonymous namespace
-namespace {
// x86-32 Cygwin target
class CygwinX86_32TargetInfo : public X86_32TargetInfo {
public:
@@ -3460,7 +3509,7 @@
TLSSupported = false;
WCharType = UnsignedShort;
DoubleAlign = LongLongAlign = 64;
- DescriptionString = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32";
+ DescriptionString = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-S32";
}
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
@@ -3473,9 +3522,7 @@
Builder.defineMacro("_GNU_SOURCE");
}
};
-} // end anonymous namespace
-namespace {
// x86-32 Haiku target
class HaikuX86_32TargetInfo : public X86_32TargetInfo {
public:
@@ -3494,7 +3541,6 @@
Builder.defineMacro("__HAIKU__");
}
};
-} // end anonymous namespace
// RTEMS Target
template<typename Target>
@@ -3531,7 +3577,6 @@
}
};
-namespace {
// x86-32 RTEMS target
class RTEMSX86_32TargetInfo : public X86_32TargetInfo {
public:
@@ -3548,14 +3593,14 @@
Builder.defineMacro("__rtems__");
}
};
-} // end anonymous namespace
-namespace {
// x86-64 generic target
class X86_64TargetInfo : public X86TargetInfo {
public:
X86_64TargetInfo(const llvm::Triple &Triple) : X86TargetInfo(Triple) {
const bool IsX32 = getTriple().getEnvironment() == llvm::Triple::GNUX32;
+ bool IsWinCOFF =
+ getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64;
LongDoubleWidth = 128;
LongDoubleAlign = 128;
@@ -3570,9 +3615,10 @@
RegParmMax = 6;
// Pointers are 32-bit in x32.
- DescriptionString = (IsX32)
- ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128"
- : "e-m:e-i64:64-f80:128-n8:16:32:64-S128";
+ DescriptionString = IsX32 ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128"
+ : IsWinCOFF
+ ? "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+ : "e-m:e-i64:64-f80:128-n8:16:32:64-S128";
// Use fpret only for long double.
RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
@@ -3608,9 +3654,7 @@
// for x32 we need it here explicitly
bool hasInt128Type() const override { return true; }
};
-} // end anonymous namespace
-namespace {
// x86-64 Windows target
class WindowsX86_64TargetInfo : public WindowsTargetInfo<X86_64TargetInfo> {
public:
@@ -3653,9 +3697,7 @@
}
}
};
-} // end anonymous namespace
-namespace {
// x86-64 Windows Visual Studio target
class MicrosoftX86_64TargetInfo : public WindowsX86_64TargetInfo {
public:
@@ -3672,9 +3714,7 @@
Builder.defineMacro("_M_AMD64");
}
};
-} // end anonymous namespace
-namespace {
// x86-64 MinGW target
class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo {
public:
@@ -3692,9 +3732,7 @@
Builder.defineMacro("__SEH__");
}
};
-} // end anonymous namespace
-namespace {
class DarwinX86_64TargetInfo : public DarwinTargetInfo<X86_64TargetInfo> {
public:
DarwinX86_64TargetInfo(const llvm::Triple &Triple)
@@ -3708,9 +3746,7 @@
DescriptionString = "e-m:o-i64:64-f80:128-n8:16:32:64-S128";
}
};
-} // end anonymous namespace
-namespace {
class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo<X86_64TargetInfo> {
public:
OpenBSDX86_64TargetInfo(const llvm::Triple &Triple)
@@ -3719,9 +3755,7 @@
Int64Type = SignedLongLong;
}
};
-} // end anonymous namespace
-namespace {
class BitrigX86_64TargetInfo : public BitrigTargetInfo<X86_64TargetInfo> {
public:
BitrigX86_64TargetInfo(const llvm::Triple &Triple)
@@ -3730,10 +3764,7 @@
Int64Type = SignedLongLong;
}
};
-}
-
-namespace {
class ARMTargetInfo : public TargetInfo {
// Possible FPU choices.
enum FPUMode {
@@ -3825,8 +3856,9 @@
DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64;
const llvm::Triple &T = getTriple();
- // size_t is unsigned long on MachO-derived environments and NetBSD.
- if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD)
+ // size_t is unsigned long on MachO-derived environments, NetBSD and Bitrig.
+ if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD ||
+ T.getOS() == llvm::Triple::Bitrig)
SizeType = UnsignedLong;
else
SizeType = UnsignedInt;
@@ -3856,10 +3888,9 @@
BigEndian ? "E-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
: "e-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64";
} else if (T.isOSWindows()) {
- // FIXME: this is invalid for WindowsCE
assert(!BigEndian && "Windows on ARM does not support big endian");
DescriptionString = "e"
- "-m:e"
+ "-m:w"
"-p:32:32"
"-i64:64"
"-v128:64:128"
@@ -4143,8 +4174,9 @@
.Cases("arm10e", "arm1020e", "arm1022e", "5TE")
.Cases("xscale", "iwmmxt", "5TE")
.Case("arm1136j-s", "6J")
- .Cases("arm1176jz-s", "arm1176jzf-s", "6ZK")
- .Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
+ .Case("arm1136jf-s", "6")
+ .Cases("mpcorenovfp", "mpcore", "6K")
+ .Cases("arm1176jz-s", "arm1176jzf-s", "6K")
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
.Cases("cortex-a5", "cortex-a7", "cortex-a8", "7A")
.Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait",
@@ -4546,9 +4578,7 @@
ARMTargetInfo::getTargetDefines(Opts, Builder);
}
};
-} // end anonymous namespace.
-namespace {
class WindowsARMTargetInfo : public WindowsTargetInfo<ARMleTargetInfo> {
const llvm::Triple Triple;
public:
@@ -4614,10 +4644,7 @@
WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder);
}
};
-}
-
-namespace {
class DarwinARMTargetInfo :
public DarwinTargetInfo<ARMleTargetInfo> {
protected:
@@ -4639,10 +4666,7 @@
TheCXXABI.set(TargetCXXABI::iOS);
}
};
-} // end anonymous namespace.
-
-namespace {
class AArch64TargetInfo : public TargetInfo {
virtual void setDescriptionString() = 0;
static const TargetInfo::GCCRegAlias GCCRegAliases[];
@@ -4999,9 +5023,7 @@
AArch64TargetInfo::getTargetDefines(Opts, Builder);
}
};
-} // end anonymous namespace.
-namespace {
class DarwinAArch64TargetInfo : public DarwinTargetInfo<AArch64leTargetInfo> {
protected:
void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
@@ -5034,9 +5056,7 @@
return TargetInfo::CharPtrBuiltinVaList;
}
};
-} // end anonymous namespace
-namespace {
// Hexagon abstract base class
class HexagonTargetInfo : public TargetInfo {
static const Builtin::Info BuiltinInfo[];
@@ -5185,10 +5205,7 @@
ALL_LANGUAGES },
#include "clang/Basic/BuiltinsHexagon.def"
};
-}
-
-namespace {
// Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit).
class SparcTargetInfo : public TargetInfo {
static const TargetInfo::GCCRegAlias GCCRegAliases[];
@@ -5375,9 +5392,6 @@
}
};
-} // end anonymous namespace.
-
-namespace {
class SolarisSparcV8TargetInfo : public SolarisTargetInfo<SparcV8TargetInfo> {
public:
SolarisSparcV8TargetInfo(const llvm::Triple &Triple)
@@ -5386,9 +5400,7 @@
PtrDiffType = SignedInt;
}
};
-} // end anonymous namespace.
-namespace {
class SystemZTargetInfo : public TargetInfo {
static const char *const GCCRegNames[];
@@ -5490,9 +5502,7 @@
return true;
}
}
-}
-namespace {
class MSP430TargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
public:
@@ -5567,9 +5577,6 @@
Names = GCCRegNames;
NumNames = llvm::array_lengthof(GCCRegNames);
}
-}
-
-namespace {
// LLVM and Clang cannot be used directly to output native binaries for
// target, but is used to compile C code to llvm bitcode with correct
@@ -5647,9 +5654,7 @@
void getGCCRegAliases(const GCCRegAlias *&Aliases,
unsigned &NumAliases) const override {}
};
-}
-namespace {
class MipsTargetInfoBase : public TargetInfo {
virtual void setDescriptionString() = 0;
@@ -6229,9 +6234,7 @@
Mips64TargetInfoBase::getTargetDefines(Opts, Builder);
}
};
-} // end anonymous namespace.
-namespace {
class PNaClTargetInfo : public TargetInfo {
public:
PNaClTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
@@ -6296,9 +6299,7 @@
Aliases = nullptr;
NumAliases = 0;
}
-} // end anonymous namespace.
-namespace {
class Le64TargetInfo : public TargetInfo {
static const Builtin::Info BuiltinInfo[];
@@ -6445,9 +6446,7 @@
DefineStd(Builder, "SPIR64", Opts);
}
};
-}
-namespace {
class XCoreTargetInfo : public TargetInfo {
static const Builtin::Info BuiltinInfo[];
public:
@@ -6513,6 +6512,30 @@
};
} // end anonymous namespace.
+namespace {
+// x86_32 Android target
+class AndroidX86_32TargetInfo : public LinuxTargetInfo<X86_32TargetInfo> {
+public:
+ AndroidX86_32TargetInfo(const llvm::Triple &Triple)
+ : LinuxTargetInfo<X86_32TargetInfo>(Triple) {
+ SuitableAlign = 32;
+ LongDoubleWidth = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble;
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86_64 Android target
+class AndroidX86_64TargetInfo : public LinuxTargetInfo<X86_64TargetInfo> {
+public:
+ AndroidX86_64TargetInfo(const llvm::Triple &Triple)
+ : LinuxTargetInfo<X86_64TargetInfo>(Triple) {
+ LongDoubleFormat = &llvm::APFloat::IEEEquad;
+ }
+};
+} // end anonymous namespace
+
//===----------------------------------------------------------------------===//
// Driver code
@@ -6790,8 +6813,14 @@
return new DarwinI386TargetInfo(Triple);
switch (os) {
- case llvm::Triple::Linux:
- return new LinuxTargetInfo<X86_32TargetInfo>(Triple);
+ case llvm::Triple::Linux: {
+ switch (Triple.getEnvironment()) {
+ default:
+ return new LinuxTargetInfo<X86_32TargetInfo>(Triple);
+ case llvm::Triple::Android:
+ return new AndroidX86_32TargetInfo(Triple);
+ }
+ }
case llvm::Triple::DragonFly:
return new DragonFlyBSDTargetInfo<X86_32TargetInfo>(Triple);
case llvm::Triple::NetBSD:
@@ -6836,8 +6865,16 @@
return new DarwinX86_64TargetInfo(Triple);
switch (os) {
- case llvm::Triple::Linux:
- return new LinuxTargetInfo<X86_64TargetInfo>(Triple);
+ case llvm::Triple::CloudABI:
+ return new CloudABITargetInfo<X86_64TargetInfo>(Triple);
+ case llvm::Triple::Linux: {
+ switch (Triple.getEnvironment()) {
+ default:
+ return new LinuxTargetInfo<X86_64TargetInfo>(Triple);
+ case llvm::Triple::Android:
+ return new AndroidX86_64TargetInfo(Triple);
+ }
+ }
case llvm::Triple::DragonFly:
return new DragonFlyBSDTargetInfo<X86_64TargetInfo>(Triple);
case llvm::Triple::NetBSD:
diff --git a/lib/Basic/VersionTuple.cpp b/lib/Basic/VersionTuple.cpp
index aa43ae2..9c73fd9 100644
--- a/lib/Basic/VersionTuple.cpp
+++ b/lib/Basic/VersionTuple.cpp
@@ -32,6 +32,8 @@
Out << (V.usesUnderscores() ? '_' : '.') << *Minor;
if (Optional<unsigned> Subminor = V.getSubminor())
Out << (V.usesUnderscores() ? '_' : '.') << *Subminor;
+ if (Optional<unsigned> Build = V.getBuild())
+ Out << (V.usesUnderscores() ? '_' : '.') << *Build;
return Out;
}
@@ -55,7 +57,7 @@
}
bool VersionTuple::tryParse(StringRef input) {
- unsigned major = 0, minor = 0, micro = 0;
+ unsigned major = 0, minor = 0, micro = 0, build = 0;
// Parse the major version, [0-9]+
if (parseInt(input, major)) return true;
@@ -80,9 +82,19 @@
input = input.substr(1);
if (parseInt(input, micro)) return true;
+ if (input.empty()) {
+ *this = VersionTuple(major, minor, micro);
+ return false;
+ }
+
+ // If we're not done, parse the micro version, \.[0-9]+
+ if (input[0] != '.') return true;
+ input = input.substr(1);
+ if (parseInt(input, build)) return true;
+
// If we have characters left over, it's an error.
if (!input.empty()) return true;
- *this = VersionTuple(major, minor, micro);
+ *this = VersionTuple(major, minor, micro, build);
return false;
}
diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp
index c89195e..5164bcf 100644
--- a/lib/Basic/VirtualFileSystem.cpp
+++ b/lib/Basic/VirtualFileSystem.cpp
@@ -1134,7 +1134,7 @@
if (Current != End) {
SmallString<128> PathStr(Dir);
llvm::sys::path::append(PathStr, (*Current)->getName());
- llvm::ErrorOr<vfs::Status> S = FS.status(PathStr.str());
+ llvm::ErrorOr<vfs::Status> S = FS.status(PathStr);
if (S)
CurrentEntry = *S;
else
@@ -1147,7 +1147,7 @@
if (++Current != End) {
SmallString<128> PathStr(Dir);
llvm::sys::path::append(PathStr, (*Current)->getName());
- llvm::ErrorOr<vfs::Status> S = FS.status(PathStr.str());
+ llvm::ErrorOr<vfs::Status> S = FS.status(PathStr);
if (!S)
return S.getError();
CurrentEntry = *S;
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index da3e5ce..bdab637 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -71,7 +71,6 @@
legacy::PassManager *getCodeGenPasses() const {
if (!CodeGenPasses) {
CodeGenPasses = new legacy::PassManager();
- CodeGenPasses->add(new DataLayoutPass());
CodeGenPasses->add(
createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
}
@@ -81,7 +80,6 @@
legacy::PassManager *getPerModulePasses() const {
if (!PerModulePasses) {
PerModulePasses = new legacy::PassManager();
- PerModulePasses->add(new DataLayoutPass());
PerModulePasses->add(
createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
}
@@ -91,7 +89,6 @@
legacy::FunctionPassManager *getPerFunctionPasses() const {
if (!PerFunctionPasses) {
PerFunctionPasses = new legacy::FunctionPassManager(TheModule);
- PerFunctionPasses->add(new DataLayoutPass());
PerFunctionPasses->add(
createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
}
@@ -240,6 +237,14 @@
TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(TargetTriple);
if (!CodeGenOpts.SimplifyLibCalls)
TLII->disableAllFunctions();
+
+ switch (CodeGenOpts.getVecLib()) {
+ case CodeGenOptions::Accelerate:
+ TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::Accelerate);
+ break;
+ default:
+ break;
+ }
return TLII;
}
@@ -368,8 +373,6 @@
legacy::PassManager *MPM = getPerModulePasses();
if (!CodeGenOpts.RewriteMapFiles.empty())
addSymbolRewriterPass(CodeGenOpts, MPM);
- if (CodeGenOpts.VerifyModule)
- MPM->add(createDebugInfoVerifierPass());
if (!CodeGenOpts.DisableGCov &&
(CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes)) {
@@ -383,6 +386,7 @@
Options.NoRedZone = CodeGenOpts.DisableRedZone;
Options.FunctionNamesInData =
!CodeGenOpts.CoverageNoFunctionNamesInData;
+ Options.ExitBlockBeforeBody = CodeGenOpts.CoverageExitBlockBeforeBody;
MPM->add(createGCOVProfilerPass(Options));
if (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo)
MPM->add(createStripSymbolsPass(true));
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
index 2af2264..b7222fc 100644
--- a/lib/CodeGen/CGAtomic.cpp
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -73,6 +73,8 @@
LVal = lvalue;
} else if (lvalue.isBitField()) {
+ ValueTy = lvalue.getType();
+ ValueSizeInBits = C.getTypeSize(ValueTy);
auto &OrigBFI = lvalue.getBitFieldInfo();
auto Offset = OrigBFI.Offset % C.toBits(lvalue.getAlignment());
AtomicSizeInBits = C.toBits(
@@ -93,12 +95,34 @@
BFI.StorageSize = AtomicSizeInBits;
LVal = LValue::MakeBitfield(Addr, BFI, lvalue.getType(),
lvalue.getAlignment());
+ LVal.setTBAAInfo(lvalue.getTBAAInfo());
+ AtomicTy = C.getIntTypeForBitwidth(AtomicSizeInBits, OrigBFI.IsSigned);
+ if (AtomicTy.isNull()) {
+ llvm::APInt Size(
+ /*numBits=*/32,
+ C.toCharUnitsFromBits(AtomicSizeInBits).getQuantity());
+ AtomicTy = C.getConstantArrayType(C.CharTy, Size, ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
+ }
+ AtomicAlign = ValueAlign = lvalue.getAlignment();
} else if (lvalue.isVectorElt()) {
- AtomicSizeInBits = C.getTypeSize(lvalue.getType());
+ ValueTy = lvalue.getType()->getAs<VectorType>()->getElementType();
+ ValueSizeInBits = C.getTypeSize(ValueTy);
+ AtomicTy = lvalue.getType();
+ AtomicSizeInBits = C.getTypeSize(AtomicTy);
+ AtomicAlign = ValueAlign = lvalue.getAlignment();
LVal = lvalue;
} else {
assert(lvalue.isExtVectorElt());
- AtomicSizeInBits = C.getTypeSize(lvalue.getType());
+ ValueTy = lvalue.getType();
+ ValueSizeInBits = C.getTypeSize(ValueTy);
+ AtomicTy = ValueTy = CGF.getContext().getExtVectorType(
+ lvalue.getType(), lvalue.getExtVectorAddr()
+ ->getType()
+ ->getPointerElementType()
+ ->getVectorNumElements());
+ AtomicSizeInBits = C.getTypeSize(AtomicTy);
+ AtomicAlign = ValueAlign = lvalue.getAlignment();
LVal = lvalue;
}
UseLibcall = !C.getTargetInfo().hasBuiltinAtomic(
@@ -114,6 +138,16 @@
TypeEvaluationKind getEvaluationKind() const { return EvaluationKind; }
bool shouldUseLibcall() const { return UseLibcall; }
const LValue &getAtomicLValue() const { return LVal; }
+ llvm::Value *getAtomicAddress() const {
+ if (LVal.isSimple())
+ return LVal.getAddress();
+ else if (LVal.isBitField())
+ return LVal.getBitFieldAddr();
+ else if (LVal.isVectorElt())
+ return LVal.getVectorAddr();
+ assert(LVal.isExtVectorElt());
+ return LVal.getExtVectorAddr();
+ }
/// Is the atomic size larger than the underlying value type?
///
@@ -137,15 +171,15 @@
llvm::Value *emitCastToAtomicIntPointer(llvm::Value *addr) const;
/// Turn an atomic-layout object into an r-value.
- RValue convertTempToRValue(llvm::Value *addr,
- AggValueSlot resultSlot,
- SourceLocation loc) const;
+ RValue convertTempToRValue(llvm::Value *addr, AggValueSlot resultSlot,
+ SourceLocation loc, bool AsValue) const;
/// \brief Converts a rvalue to integer value.
llvm::Value *convertRValueToInt(RValue RVal) const;
- RValue convertIntToValue(llvm::Value *IntVal, AggValueSlot ResultSlot,
- SourceLocation Loc) const;
+ RValue ConvertIntToValueOrAtomic(llvm::Value *IntVal,
+ AggValueSlot ResultSlot,
+ SourceLocation Loc, bool AsValue) const;
/// Copy an atomic r-value into atomic-layout memory.
void emitCopyIntoMemory(RValue rvalue) const;
@@ -153,7 +187,7 @@
/// Project an l-value down to the value field.
LValue projectValue() const {
assert(LVal.isSimple());
- llvm::Value *addr = LVal.getAddress();
+ llvm::Value *addr = getAtomicAddress();
if (hasPadding())
addr = CGF.Builder.CreateStructGEP(addr, 0);
@@ -161,14 +195,91 @@
CGF.getContext(), LVal.getTBAAInfo());
}
+ /// \brief Emits atomic load.
+ /// \returns Loaded value.
+ RValue EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc,
+ bool AsValue, llvm::AtomicOrdering AO,
+ bool IsVolatile);
+
+ /// \brief Emits atomic compare-and-exchange sequence.
+ /// \param Expected Expected value.
+ /// \param Desired Desired value.
+ /// \param Success Atomic ordering for success operation.
+ /// \param Failure Atomic ordering for failed operation.
+ /// \param IsWeak true if atomic operation is weak, false otherwise.
+ /// \returns Pair of values: previous value from storage (value type) and
+ /// boolean flag (i1 type) with true if success and false otherwise.
+ std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchange(
+ RValue Expected, RValue Desired,
+ llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
+ llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent,
+ bool IsWeak = false);
+
/// Materialize an atomic r-value in atomic-layout memory.
llvm::Value *materializeRValue(RValue rvalue) const;
+ /// \brief Translates LLVM atomic ordering to GNU atomic ordering for
+ /// libcalls.
+ static AtomicExpr::AtomicOrderingKind
+ translateAtomicOrdering(const llvm::AtomicOrdering AO);
+
private:
bool requiresMemSetZero(llvm::Type *type) const;
+
+ /// \brief Creates temp alloca for intermediate operations on atomic value.
+ llvm::Value *CreateTempAlloca() const;
+
+ /// \brief Emits atomic load as a libcall.
+ void EmitAtomicLoadLibcall(llvm::Value *AddForLoaded,
+ llvm::AtomicOrdering AO, bool IsVolatile);
+ /// \brief Emits atomic load as LLVM instruction.
+ llvm::Value *EmitAtomicLoadOp(llvm::AtomicOrdering AO, bool IsVolatile);
+ /// \brief Emits atomic compare-and-exchange op as a libcall.
+ std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeLibcall(
+ llvm::Value *ExpectedAddr, llvm::Value *DesiredAddr,
+ llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
+ llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent);
+ /// \brief Emits atomic compare-and-exchange op as LLVM instruction.
+ std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeOp(
+ llvm::Value *Expected, llvm::Value *Desired,
+ llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
+ llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent,
+ bool IsWeak = false);
};
}
+AtomicExpr::AtomicOrderingKind
+AtomicInfo::translateAtomicOrdering(const llvm::AtomicOrdering AO) {
+ switch (AO) {
+ case llvm::Unordered:
+ case llvm::NotAtomic:
+ case llvm::Monotonic:
+ return AtomicExpr::AO_ABI_memory_order_relaxed;
+ case llvm::Acquire:
+ return AtomicExpr::AO_ABI_memory_order_acquire;
+ case llvm::Release:
+ return AtomicExpr::AO_ABI_memory_order_release;
+ case llvm::AcquireRelease:
+ return AtomicExpr::AO_ABI_memory_order_acq_rel;
+ case llvm::SequentiallyConsistent:
+ return AtomicExpr::AO_ABI_memory_order_seq_cst;
+ }
+ llvm_unreachable("Unhandled AtomicOrdering");
+}
+
+llvm::Value *AtomicInfo::CreateTempAlloca() const {
+ auto *TempAlloca = CGF.CreateMemTemp(
+ (LVal.isBitField() && ValueSizeInBits > AtomicSizeInBits) ? ValueTy
+ : AtomicTy,
+ "atomic-temp");
+ TempAlloca->setAlignment(getAtomicAlignment().getQuantity());
+ // Cast to pointer to value type for bitfields.
+ if (LVal.isBitField())
+ return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ TempAlloca, getAtomicAddress()->getType());
+ return TempAlloca;
+}
+
static RValue emitAtomicLibcall(CodeGenFunction &CGF,
StringRef fnName,
QualType resultType,
@@ -217,9 +328,10 @@
if (!requiresMemSetZero(addr->getType()->getPointerElementType()))
return false;
- CGF.Builder.CreateMemSet(addr, llvm::ConstantInt::get(CGF.Int8Ty, 0),
- AtomicSizeInBits / 8,
- LVal.getAlignment().getQuantity());
+ CGF.Builder.CreateMemSet(
+ addr, llvm::ConstantInt::get(CGF.Int8Ty, 0),
+ CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(),
+ LVal.getAlignment().getQuantity());
return true;
}
@@ -941,7 +1053,7 @@
RValue AtomicInfo::convertTempToRValue(llvm::Value *addr,
AggValueSlot resultSlot,
- SourceLocation loc) const {
+ SourceLocation loc, bool AsValue) const {
if (LVal.isSimple()) {
if (EvaluationKind == TEK_Aggregate)
return resultSlot.asRValue();
@@ -953,7 +1065,11 @@
// Otherwise, just convert the temporary to an r-value using the
// normal conversion routine.
return CGF.convertTempToRValue(addr, getValueType(), loc);
- } else if (LVal.isBitField())
+ } else if (!AsValue)
+ // Get RValue from temp memory as atomic for non-simple lvalues
+ return RValue::get(
+ CGF.Builder.CreateAlignedLoad(addr, AtomicAlign.getQuantity()));
+ else if (LVal.isBitField())
return CGF.EmitLoadOfBitfieldLValue(LValue::MakeBitfield(
addr, LVal.getBitFieldInfo(), LVal.getType(), LVal.getAlignment()));
else if (LVal.isVectorElt())
@@ -966,14 +1082,20 @@
addr, LVal.getExtVectorElts(), LVal.getType(), LVal.getAlignment()));
}
-RValue AtomicInfo::convertIntToValue(llvm::Value *IntVal,
- AggValueSlot ResultSlot,
- SourceLocation Loc) const {
- assert(LVal.isSimple());
+RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal,
+ AggValueSlot ResultSlot,
+ SourceLocation Loc,
+ bool AsValue) const {
// Try not to in some easy cases.
assert(IntVal->getType()->isIntegerTy() && "Expected integer value");
- if (getEvaluationKind() == TEK_Scalar && !hasPadding()) {
- auto *ValTy = CGF.ConvertTypeForMem(ValueTy);
+ if (getEvaluationKind() == TEK_Scalar &&
+ (((!LVal.isBitField() ||
+ LVal.getBitFieldInfo().Size == ValueSizeInBits) &&
+ !hasPadding()) ||
+ !AsValue)) {
+ auto *ValTy = AsValue
+ ? CGF.ConvertTypeForMem(ValueTy)
+ : getAtomicAddress()->getType()->getPointerElementType();
if (ValTy->isIntegerTy()) {
assert(IntVal->getType() == ValTy && "Different integer types.");
return RValue::get(CGF.EmitFromMemory(IntVal, ValueTy));
@@ -988,13 +1110,13 @@
llvm::Value *Temp;
bool TempIsVolatile = false;
CharUnits TempAlignment;
- if (getEvaluationKind() == TEK_Aggregate) {
+ if (AsValue && getEvaluationKind() == TEK_Aggregate) {
assert(!ResultSlot.isIgnored());
Temp = ResultSlot.getAddr();
TempAlignment = getValueAlignment();
TempIsVolatile = ResultSlot.isVolatile();
} else {
- Temp = CGF.CreateMemTemp(getAtomicType(), "atomic-temp");
+ Temp = CreateTempAlloca();
TempAlignment = getAtomicAlignment();
}
@@ -1003,7 +1125,38 @@
CGF.Builder.CreateAlignedStore(IntVal, CastTemp, TempAlignment.getQuantity())
->setVolatile(TempIsVolatile);
- return convertTempToRValue(Temp, ResultSlot, Loc);
+ return convertTempToRValue(Temp, ResultSlot, Loc, AsValue);
+}
+
+void AtomicInfo::EmitAtomicLoadLibcall(llvm::Value *AddForLoaded,
+ llvm::AtomicOrdering AO, bool) {
+ // void __atomic_load(size_t size, void *mem, void *return, int order);
+ CallArgList Args;
+ Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType());
+ Args.add(RValue::get(CGF.EmitCastToVoidPtr(getAtomicAddress())),
+ CGF.getContext().VoidPtrTy);
+ Args.add(RValue::get(CGF.EmitCastToVoidPtr(AddForLoaded)),
+ CGF.getContext().VoidPtrTy);
+ Args.add(RValue::get(
+ llvm::ConstantInt::get(CGF.IntTy, translateAtomicOrdering(AO))),
+ CGF.getContext().IntTy);
+ emitAtomicLibcall(CGF, "__atomic_load", CGF.getContext().VoidTy, Args);
+}
+
+llvm::Value *AtomicInfo::EmitAtomicLoadOp(llvm::AtomicOrdering AO,
+ bool IsVolatile) {
+ // Okay, we're doing this natively.
+ llvm::Value *Addr = emitCastToAtomicIntPointer(getAtomicAddress());
+ llvm::LoadInst *Load = CGF.Builder.CreateLoad(Addr, "atomic-load");
+ Load->setAtomic(AO);
+
+ // Other decoration.
+ Load->setAlignment(getAtomicAlignment().getQuantity());
+ if (IsVolatile)
+ Load->setVolatile(true);
+ if (LVal.getTBAAInfo())
+ CGF.CGM.DecorateInstruction(Load, LVal.getTBAAInfo());
+ return Load;
}
/// An LValue is a candidate for having its loads and stores be made atomic if
@@ -1041,85 +1194,47 @@
return EmitAtomicLoad(LV, SL, AO, IsVolatile, Slot);
}
+RValue AtomicInfo::EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc,
+ bool AsValue, llvm::AtomicOrdering AO,
+ bool IsVolatile) {
+ // Check whether we should use a library call.
+ if (shouldUseLibcall()) {
+ llvm::Value *TempAddr;
+ if (LVal.isSimple() && !ResultSlot.isIgnored()) {
+ assert(getEvaluationKind() == TEK_Aggregate);
+ TempAddr = ResultSlot.getAddr();
+ } else
+ TempAddr = CreateTempAlloca();
+
+ EmitAtomicLoadLibcall(TempAddr, AO, IsVolatile);
+
+ // Okay, turn that back into the original value or whole atomic (for
+ // non-simple lvalues) type.
+ return convertTempToRValue(TempAddr, ResultSlot, Loc, AsValue);
+ }
+
+ // Okay, we're doing this natively.
+ auto *Load = EmitAtomicLoadOp(AO, IsVolatile);
+
+ // If we're ignoring an aggregate return, don't do anything.
+ if (getEvaluationKind() == TEK_Aggregate && ResultSlot.isIgnored())
+ return RValue::getAggregate(nullptr, false);
+
+ // Okay, turn that back into the original value or atomic (for non-simple
+ // lvalues) type.
+ return ConvertIntToValueOrAtomic(Load, ResultSlot, Loc, AsValue);
+}
+
/// Emit a load from an l-value of atomic type. Note that the r-value
/// we produce is an r-value of the atomic *value* type.
RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc,
llvm::AtomicOrdering AO, bool IsVolatile,
AggValueSlot resultSlot) {
- AtomicInfo atomics(*this, src);
- LValue LVal = atomics.getAtomicLValue();
- llvm::Value *SrcAddr = nullptr;
- llvm::AllocaInst *NonSimpleTempAlloca = nullptr;
- if (LVal.isSimple())
- SrcAddr = LVal.getAddress();
- else {
- if (LVal.isBitField())
- SrcAddr = LVal.getBitFieldAddr();
- else if (LVal.isVectorElt())
- SrcAddr = LVal.getVectorAddr();
- else {
- assert(LVal.isExtVectorElt());
- SrcAddr = LVal.getExtVectorAddr();
- }
- NonSimpleTempAlloca = CreateTempAlloca(
- SrcAddr->getType()->getPointerElementType(), "atomic-load-temp");
- NonSimpleTempAlloca->setAlignment(getContext().toBits(src.getAlignment()));
- }
-
- // Check whether we should use a library call.
- if (atomics.shouldUseLibcall()) {
- llvm::Value *tempAddr;
- if (LVal.isSimple()) {
- if (!resultSlot.isIgnored()) {
- assert(atomics.getEvaluationKind() == TEK_Aggregate);
- tempAddr = resultSlot.getAddr();
- } else
- tempAddr = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp");
- } else
- tempAddr = NonSimpleTempAlloca;
-
- // void __atomic_load(size_t size, void *mem, void *return, int order);
- CallArgList args;
- args.add(RValue::get(atomics.getAtomicSizeValue()),
- getContext().getSizeType());
- args.add(RValue::get(EmitCastToVoidPtr(SrcAddr)), getContext().VoidPtrTy);
- args.add(RValue::get(EmitCastToVoidPtr(tempAddr)), getContext().VoidPtrTy);
- args.add(RValue::get(llvm::ConstantInt::get(
- IntTy, AtomicExpr::AO_ABI_memory_order_seq_cst)),
- getContext().IntTy);
- emitAtomicLibcall(*this, "__atomic_load", getContext().VoidTy, args);
-
- // Produce the r-value.
- return atomics.convertTempToRValue(tempAddr, resultSlot, loc);
- }
-
- // Okay, we're doing this natively.
- llvm::Value *addr = atomics.emitCastToAtomicIntPointer(SrcAddr);
- llvm::LoadInst *load = Builder.CreateLoad(addr, "atomic-load");
- load->setAtomic(AO);
-
- // Other decoration.
- load->setAlignment(src.getAlignment().getQuantity());
- if (IsVolatile)
- load->setVolatile(true);
- if (src.getTBAAInfo())
- CGM.DecorateInstruction(load, src.getTBAAInfo());
-
- // If we're ignoring an aggregate return, don't do anything.
- if (atomics.getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored())
- return RValue::getAggregate(nullptr, false);
-
- // Okay, turn that back into the original value type.
- if (src.isSimple())
- return atomics.convertIntToValue(load, resultSlot, loc);
-
- auto *IntAddr = atomics.emitCastToAtomicIntPointer(NonSimpleTempAlloca);
- Builder.CreateAlignedStore(load, IntAddr, src.getAlignment().getQuantity());
- return atomics.convertTempToRValue(NonSimpleTempAlloca, resultSlot, loc);
+ AtomicInfo Atomics(*this, src);
+ return Atomics.EmitAtomicLoad(resultSlot, loc, /*AsValue=*/true, AO,
+ IsVolatile);
}
-
-
/// Copy an r-value into memory as part of storing to an atomic type.
/// This needs to create a bit-pattern suitable for atomic operations.
void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
@@ -1128,7 +1243,7 @@
// which means that the caller is responsible for having zeroed
// any padding. Just do an aggregate copy of that type.
if (rvalue.isAggregate()) {
- CGF.EmitAggregateCopy(LVal.getAddress(),
+ CGF.EmitAggregateCopy(getAtomicAddress(),
rvalue.getAggregateAddr(),
getAtomicType(),
(rvalue.isVolatileQualified()
@@ -1163,24 +1278,24 @@
return rvalue.getAggregateAddr();
// Otherwise, make a temporary and materialize into it.
- llvm::Value *temp = CGF.CreateMemTemp(getAtomicType(), "atomic-store-temp");
- LValue tempLV =
- CGF.MakeAddrLValue(temp, getAtomicType(), getAtomicAlignment());
- AtomicInfo Atomics(CGF, tempLV);
+ LValue TempLV = CGF.MakeAddrLValue(CreateTempAlloca(), getAtomicType(),
+ getAtomicAlignment());
+ AtomicInfo Atomics(CGF, TempLV);
Atomics.emitCopyIntoMemory(rvalue);
- return temp;
+ return TempLV.getAddress();
}
llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const {
// If we've got a scalar value of the right size, try to avoid going
// through memory.
- if (RVal.isScalar() && !hasPadding()) {
+ if (RVal.isScalar() && (!hasPadding() || !LVal.isSimple())) {
llvm::Value *Value = RVal.getScalarVal();
if (isa<llvm::IntegerType>(Value->getType()))
return Value;
else {
- llvm::IntegerType *InputIntTy =
- llvm::IntegerType::get(CGF.getLLVMContext(), getValueSizeInBits());
+ llvm::IntegerType *InputIntTy = llvm::IntegerType::get(
+ CGF.getLLVMContext(),
+ LVal.isSimple() ? getValueSizeInBits() : getAtomicSizeInBits());
if (isa<llvm::PointerType>(Value->getType()))
return CGF.Builder.CreatePtrToInt(Value, InputIntTy);
else if (llvm::BitCastInst::isBitCastable(Value->getType(), InputIntTy))
@@ -1197,6 +1312,76 @@
getAtomicAlignment().getQuantity());
}
+std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchangeOp(
+ llvm::Value *Expected, llvm::Value *Desired, llvm::AtomicOrdering Success,
+ llvm::AtomicOrdering Failure, bool IsWeak) {
+ // Do the atomic store.
+ auto *Addr = emitCastToAtomicIntPointer(getAtomicAddress());
+ auto *Inst = CGF.Builder.CreateAtomicCmpXchg(Addr, Expected, Desired, Success,
+ Failure);
+ // Other decoration.
+ Inst->setVolatile(LVal.isVolatileQualified());
+ Inst->setWeak(IsWeak);
+
+ // Okay, turn that back into the original value type.
+ auto *PreviousVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/0);
+ auto *SuccessFailureVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/1);
+ return std::make_pair(PreviousVal, SuccessFailureVal);
+}
+
+std::pair<llvm::Value *, llvm::Value *>
+AtomicInfo::EmitAtomicCompareExchangeLibcall(llvm::Value *ExpectedAddr,
+ llvm::Value *DesiredAddr,
+ llvm::AtomicOrdering Success,
+ llvm::AtomicOrdering Failure) {
+ // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
+ // void *desired, int success, int failure);
+ CallArgList Args;
+ Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType());
+ Args.add(RValue::get(CGF.EmitCastToVoidPtr(getAtomicAddress())),
+ CGF.getContext().VoidPtrTy);
+ Args.add(RValue::get(CGF.EmitCastToVoidPtr(ExpectedAddr)),
+ CGF.getContext().VoidPtrTy);
+ Args.add(RValue::get(CGF.EmitCastToVoidPtr(DesiredAddr)),
+ CGF.getContext().VoidPtrTy);
+ Args.add(RValue::get(llvm::ConstantInt::get(
+ CGF.IntTy, translateAtomicOrdering(Success))),
+ CGF.getContext().IntTy);
+ Args.add(RValue::get(llvm::ConstantInt::get(
+ CGF.IntTy, translateAtomicOrdering(Failure))),
+ CGF.getContext().IntTy);
+ auto SuccessFailureRVal = emitAtomicLibcall(CGF, "__atomic_compare_exchange",
+ CGF.getContext().BoolTy, Args);
+ auto *PreviousVal = CGF.Builder.CreateAlignedLoad(
+ ExpectedAddr, getValueAlignment().getQuantity());
+ return std::make_pair(PreviousVal, SuccessFailureRVal.getScalarVal());
+}
+
+std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchange(
+ RValue Expected, RValue Desired, llvm::AtomicOrdering Success,
+ llvm::AtomicOrdering Failure, bool IsWeak) {
+ if (Failure >= Success)
+ // Don't assert on undefined behavior.
+ Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(Success);
+
+ // Check whether we should use a library call.
+ if (shouldUseLibcall()) {
+ auto *ExpectedAddr = materializeRValue(Expected);
+ // Produce a source address.
+ auto *DesiredAddr = materializeRValue(Desired);
+ return EmitAtomicCompareExchangeLibcall(ExpectedAddr, DesiredAddr, Success,
+ Failure);
+ }
+
+ // If we've got a scalar value of the right size, try to avoid going
+ // through memory.
+ auto *ExpectedIntVal = convertRValueToInt(Expected);
+ auto *DesiredIntVal = convertRValueToInt(Desired);
+
+ return EmitAtomicCompareExchangeOp(ExpectedIntVal, DesiredIntVal, Success,
+ Failure, IsWeak);
+}
+
void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue lvalue,
bool isInit) {
bool IsVolatile = lvalue.isVolatileQualified();
@@ -1225,49 +1410,103 @@
== dest.getAddress()->getType()->getPointerElementType());
AtomicInfo atomics(*this, dest);
+ LValue LVal = atomics.getAtomicLValue();
// If this is an initialization, just put the value there normally.
- if (isInit) {
- atomics.emitCopyIntoMemory(rvalue);
+ if (LVal.isSimple()) {
+ if (isInit) {
+ atomics.emitCopyIntoMemory(rvalue);
+ return;
+ }
+
+ // Check whether we should use a library call.
+ if (atomics.shouldUseLibcall()) {
+ // Produce a source address.
+ llvm::Value *srcAddr = atomics.materializeRValue(rvalue);
+
+ // void __atomic_store(size_t size, void *mem, void *val, int order)
+ CallArgList args;
+ args.add(RValue::get(atomics.getAtomicSizeValue()),
+ getContext().getSizeType());
+ args.add(RValue::get(EmitCastToVoidPtr(atomics.getAtomicAddress())),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(EmitCastToVoidPtr(srcAddr)), getContext().VoidPtrTy);
+ args.add(RValue::get(llvm::ConstantInt::get(
+ IntTy, AtomicInfo::translateAtomicOrdering(AO))),
+ getContext().IntTy);
+ emitAtomicLibcall(*this, "__atomic_store", getContext().VoidTy, args);
+ return;
+ }
+
+ // Okay, we're doing this natively.
+ llvm::Value *intValue = atomics.convertRValueToInt(rvalue);
+
+ // Do the atomic store.
+ llvm::Value *addr =
+ atomics.emitCastToAtomicIntPointer(atomics.getAtomicAddress());
+ intValue = Builder.CreateIntCast(
+ intValue, addr->getType()->getPointerElementType(), /*isSigned=*/false);
+ llvm::StoreInst *store = Builder.CreateStore(intValue, addr);
+
+ // Initializations don't need to be atomic.
+ if (!isInit)
+ store->setAtomic(AO);
+
+ // Other decoration.
+ store->setAlignment(dest.getAlignment().getQuantity());
+ if (IsVolatile)
+ store->setVolatile(true);
+ if (dest.getTBAAInfo())
+ CGM.DecorateInstruction(store, dest.getTBAAInfo());
return;
}
- // Check whether we should use a library call.
- if (atomics.shouldUseLibcall()) {
- // Produce a source address.
- llvm::Value *srcAddr = atomics.materializeRValue(rvalue);
-
- // void __atomic_store(size_t size, void *mem, void *val, int order)
- CallArgList args;
- args.add(RValue::get(atomics.getAtomicSizeValue()),
- getContext().getSizeType());
- args.add(RValue::get(EmitCastToVoidPtr(dest.getAddress())),
- getContext().VoidPtrTy);
- args.add(RValue::get(EmitCastToVoidPtr(srcAddr)),
- getContext().VoidPtrTy);
- args.add(RValue::get(llvm::ConstantInt::get(
- IntTy, AtomicExpr::AO_ABI_memory_order_seq_cst)),
- getContext().IntTy);
- emitAtomicLibcall(*this, "__atomic_store", getContext().VoidTy, args);
- return;
+ // Atomic load of prev value.
+ RValue OldRVal =
+ atomics.EmitAtomicLoad(AggValueSlot::ignored(), SourceLocation(),
+ /*AsValue=*/false, AO, IsVolatile);
+ // For non-simple lvalues perform compare-and-swap procedure.
+ auto *ContBB = createBasicBlock("atomic_cont");
+ auto *ExitBB = createBasicBlock("atomic_exit");
+ auto *CurBB = Builder.GetInsertBlock();
+ EmitBlock(ContBB);
+ llvm::PHINode *PHI = Builder.CreatePHI(OldRVal.getScalarVal()->getType(),
+ /*NumReservedValues=*/2);
+ PHI->addIncoming(OldRVal.getScalarVal(), CurBB);
+ RValue OriginalRValue = RValue::get(PHI);
+ // Build new lvalue for temp address
+ auto *Ptr = atomics.materializeRValue(OriginalRValue);
+ // Build new lvalue for temp address
+ LValue UpdateLVal;
+ if (LVal.isBitField())
+ UpdateLVal = LValue::MakeBitfield(Ptr, LVal.getBitFieldInfo(),
+ LVal.getType(), LVal.getAlignment());
+ else if (LVal.isVectorElt())
+ UpdateLVal = LValue::MakeVectorElt(Ptr, LVal.getVectorIdx(), LVal.getType(),
+ LVal.getAlignment());
+ else {
+ assert(LVal.isExtVectorElt());
+ UpdateLVal = LValue::MakeExtVectorElt(Ptr, LVal.getExtVectorElts(),
+ LVal.getType(), LVal.getAlignment());
}
-
- // Okay, we're doing this natively.
- llvm::Value *intValue = atomics.convertRValueToInt(rvalue);
-
- // Do the atomic store.
- llvm::Value *addr = atomics.emitCastToAtomicIntPointer(dest.getAddress());
- llvm::StoreInst *store = Builder.CreateStore(intValue, addr);
-
- // Initializations don't need to be atomic.
- if (!isInit) store->setAtomic(AO);
-
- // Other decoration.
- store->setAlignment(dest.getAlignment().getQuantity());
- if (IsVolatile)
- store->setVolatile(true);
- if (dest.getTBAAInfo())
- CGM.DecorateInstruction(store, dest.getTBAAInfo());
+ UpdateLVal.setTBAAInfo(LVal.getTBAAInfo());
+ // Store new value in the corresponding memory area
+ EmitStoreThroughLValue(rvalue, UpdateLVal);
+ // Load new value
+ RValue NewRValue = RValue::get(EmitLoadOfScalar(
+ Ptr, LVal.isVolatile(), atomics.getAtomicAlignment().getQuantity(),
+ atomics.getAtomicType(), SourceLocation()));
+ // Try to write new value using cmpxchg operation
+ auto Pair = atomics.EmitAtomicCompareExchange(OriginalRValue, NewRValue, AO);
+ llvm::Value *OldValue = Pair.first;
+ if (!atomics.shouldUseLibcall())
+ // Convert integer value to original atomic type
+ OldValue = atomics.ConvertIntToValueOrAtomic(
+ OldValue, AggValueSlot::ignored(), SourceLocation(),
+ /*AsValue=*/false).getScalarVal();
+ PHI->addIncoming(OldValue, ContBB);
+ Builder.CreateCondBr(Pair.second, ExitBB, ContBB);
+ EmitBlock(ExitBB, /*IsFinished=*/true);
}
/// Emit a compare-and-exchange op for atomic type.
@@ -1286,56 +1525,13 @@
Obj.getAddress()->getType()->getPointerElementType());
AtomicInfo Atomics(*this, Obj);
- if (Failure >= Success)
- // Don't assert on undefined behavior.
- Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(Success);
-
- auto Alignment = Atomics.getValueAlignment();
- // Check whether we should use a library call.
- if (Atomics.shouldUseLibcall()) {
- auto *ExpectedAddr = Atomics.materializeRValue(Expected);
- // Produce a source address.
- auto *DesiredAddr = Atomics.materializeRValue(Desired);
- // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
- // void *desired, int success, int failure);
- CallArgList Args;
- Args.add(RValue::get(Atomics.getAtomicSizeValue()),
- getContext().getSizeType());
- Args.add(RValue::get(EmitCastToVoidPtr(Obj.getAddress())),
- getContext().VoidPtrTy);
- Args.add(RValue::get(EmitCastToVoidPtr(ExpectedAddr)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(EmitCastToVoidPtr(DesiredAddr)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(llvm::ConstantInt::get(IntTy, Success)),
- getContext().IntTy);
- Args.add(RValue::get(llvm::ConstantInt::get(IntTy, Failure)),
- getContext().IntTy);
- auto SuccessFailureRVal = emitAtomicLibcall(
- *this, "__atomic_compare_exchange", getContext().BoolTy, Args);
- auto *PreviousVal =
- Builder.CreateAlignedLoad(ExpectedAddr, Alignment.getQuantity());
- return std::make_pair(RValue::get(PreviousVal), SuccessFailureRVal);
- }
-
- // If we've got a scalar value of the right size, try to avoid going
- // through memory.
- auto *ExpectedIntVal = Atomics.convertRValueToInt(Expected);
- auto *DesiredIntVal = Atomics.convertRValueToInt(Desired);
-
- // Do the atomic store.
- auto *Addr = Atomics.emitCastToAtomicIntPointer(Obj.getAddress());
- auto *Inst = Builder.CreateAtomicCmpXchg(Addr, ExpectedIntVal, DesiredIntVal,
- Success, Failure);
- // Other decoration.
- Inst->setVolatile(Obj.isVolatileQualified());
- Inst->setWeak(IsWeak);
-
- // Okay, turn that back into the original value type.
- auto *PreviousVal = Builder.CreateExtractValue(Inst, /*Idxs=*/0);
- auto *SuccessFailureVal = Builder.CreateExtractValue(Inst, /*Idxs=*/1);
- return std::make_pair(Atomics.convertIntToValue(PreviousVal, Slot, Loc),
- RValue::get(SuccessFailureVal));
+ auto Pair = Atomics.EmitAtomicCompareExchange(Expected, Desired, Success,
+ Failure, IsWeak);
+ return std::make_pair(Atomics.shouldUseLibcall()
+ ? RValue::get(Pair.first)
+ : Atomics.ConvertIntToValueOrAtomic(
+ Pair.first, Slot, Loc, /*AsValue=*/true),
+ RValue::get(Pair.second));
}
void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index bf7d86f..35597fe 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
+#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
@@ -25,6 +26,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
+#include <sstream>
using namespace clang;
using namespace CodeGen;
@@ -157,6 +159,27 @@
return Call;
}
+/// Emit the computation of the sign bit for a floating point value. Returns
+/// the i1 sign bit value.
+static Value *EmitSignBit(CodeGenFunction &CGF, Value *V) {
+ LLVMContext &C = CGF.CGM.getLLVMContext();
+
+ llvm::Type *Ty = V->getType();
+ int Width = Ty->getPrimitiveSizeInBits();
+ llvm::Type *IntTy = llvm::IntegerType::get(C, Width);
+ V = CGF.Builder.CreateBitCast(V, IntTy);
+ if (Ty->isPPC_FP128Ty()) {
+ // The higher-order double comes first, and so we need to truncate the
+ // pair to extract the overall sign. The order of the pair is the same
+ // in both little- and big-Endian modes.
+ Width >>= 1;
+ IntTy = llvm::IntegerType::get(C, Width);
+ V = CGF.Builder.CreateTrunc(V, IntTy);
+ }
+ Value *Zero = llvm::Constant::getNullValue(IntTy);
+ return CGF.Builder.CreateICmpSLT(V, Zero);
+}
+
static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn,
const CallExpr *E, llvm::Value *calleeValue) {
return CGF.EmitCall(E->getCallee()->getType(), calleeValue, E,
@@ -557,8 +580,22 @@
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
}
- // TODO: BI__builtin_isinf_sign
- // isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0
+ case Builtin::BI__builtin_isinf_sign: {
+ // isinf_sign(x) -> fabs(x) == infinity ? (signbit(x) ? -1 : 1) : 0
+ Value *Arg = EmitScalarExpr(E->getArg(0));
+ Value *AbsArg = EmitFAbs(*this, Arg);
+ Value *IsInf = Builder.CreateFCmpOEQ(
+ AbsArg, ConstantFP::getInfinity(Arg->getType()), "isinf");
+ Value *IsNeg = EmitSignBit(*this, Arg);
+
+ llvm::Type *IntTy = ConvertType(E->getType());
+ Value *Zero = Constant::getNullValue(IntTy);
+ Value *One = ConstantInt::get(IntTy, 1);
+ Value *NegativeOne = ConstantInt::get(IntTy, -1);
+ Value *SignResult = Builder.CreateSelect(IsNeg, NegativeOne, One);
+ Value *Result = Builder.CreateSelect(IsInf, SignResult, Zero);
+ return RValue::get(Result);
+ }
case Builtin::BI__builtin_isnormal: {
// isnormal(x) --> x == x && fabsf(x) < infinity && fabsf(x) >= float_min
@@ -859,8 +896,6 @@
return RValue::get(Builder.CreateZExt(Result, Int64Ty, "extend.zext"));
}
case Builtin::BI__builtin_setjmp: {
- if (!getTargetHooks().hasSjLjLowering(*this))
- break;
// Buffer is a void**.
Value *Buf = EmitScalarExpr(E->getArg(0));
@@ -883,8 +918,6 @@
return RValue::get(Builder.CreateCall(F, Buf));
}
case Builtin::BI__builtin_longjmp: {
- if (!getTargetHooks().hasSjLjLowering(*this))
- break;
Value *Buf = EmitScalarExpr(E->getArg(0));
Buf = Builder.CreateBitCast(Buf, Int8PtrTy);
@@ -1401,24 +1434,9 @@
case Builtin::BI__builtin_signbit:
case Builtin::BI__builtin_signbitf:
case Builtin::BI__builtin_signbitl: {
- LLVMContext &C = CGM.getLLVMContext();
-
- Value *Arg = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgTy = Arg->getType();
- int ArgWidth = ArgTy->getPrimitiveSizeInBits();
- llvm::Type *ArgIntTy = llvm::IntegerType::get(C, ArgWidth);
- Value *BCArg = Builder.CreateBitCast(Arg, ArgIntTy);
- if (ArgTy->isPPC_FP128Ty()) {
- // The higher-order double comes first, and so we need to truncate the
- // pair to extract the overall sign. The order of the pair is the same
- // in both little- and big-Endian modes.
- ArgWidth >>= 1;
- ArgIntTy = llvm::IntegerType::get(C, ArgWidth);
- BCArg = Builder.CreateTrunc(BCArg, ArgIntTy);
- }
- Value *ZeroCmp = llvm::Constant::getNullValue(ArgIntTy);
- Value *Result = Builder.CreateICmpSLT(BCArg, ZeroCmp);
- return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType())));
+ return RValue::get(
+ Builder.CreateZExt(EmitSignBit(*this, EmitScalarExpr(E->getArg(0))),
+ ConvertType(E->getType())));
}
case Builtin::BI__builtin_annotation: {
llvm::Value *AnnVal = EmitScalarExpr(E->getArg(0));
@@ -1682,8 +1700,8 @@
llvm::Constant *SetJmpEx = CGM.CreateRuntimeFunction(
llvm::FunctionType::get(IntTy, ArgTypes, /*isVarArg=*/false),
"_setjmpex", ReturnsTwiceAttr);
- llvm::Value *Buf =
- Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)), Int8PtrTy);
+ llvm::Value *Buf = Builder.CreateBitOrPointerCast(
+ EmitScalarExpr(E->getArg(0)), Int8PtrTy);
llvm::Value *FrameAddr =
Builder.CreateCall(CGM.getIntrinsic(Intrinsic::frameaddress),
ConstantInt::get(Int32Ty, 0));
@@ -1692,14 +1710,15 @@
CS.setAttributes(ReturnsTwiceAttr);
return RValue::get(CS.getInstruction());
}
+ break;
}
case Builtin::BI_setjmp: {
if (getTarget().getTriple().isOSMSVCRT()) {
llvm::AttributeSet ReturnsTwiceAttr =
AttributeSet::get(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
llvm::Attribute::ReturnsTwice);
- llvm::Value *Buf =
- Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)), Int8PtrTy);
+ llvm::Value *Buf = Builder.CreateBitOrPointerCast(
+ EmitScalarExpr(E->getArg(0)), Int8PtrTy);
llvm::CallSite CS;
if (getTarget().getTriple().getArch() == llvm::Triple::x86) {
llvm::Type *ArgTypes[] = {Int8PtrTy, IntTy};
@@ -1723,6 +1742,14 @@
CS.setAttributes(ReturnsTwiceAttr);
return RValue::get(CS.getInstruction());
}
+ break;
+ }
+
+ case Builtin::BI__GetExceptionInfo: {
+ if (llvm::GlobalVariable *GV =
+ CGM.getCXXABI().getThrowInfo(FD->getParamDecl(0)->getType()))
+ return RValue::get(llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy));
+ break;
}
}
@@ -6090,13 +6117,6 @@
Builder.CreateStore(Builder.CreateExtractValue(Call, 0), Ops[0]);
return Builder.CreateExtractValue(Call, 1);
}
- // AVX2 broadcast
- case X86::BI__builtin_ia32_vbroadcastsi256: {
- Value *VecTmp = CreateMemTemp(E->getArg(0)->getType());
- Builder.CreateStore(Ops[0], VecTmp);
- Value *F = CGM.getIntrinsic(Intrinsic::x86_avx2_vbroadcasti128);
- return Builder.CreateCall(F, Builder.CreateBitCast(VecTmp, Int8PtrTy));
- }
// SSE comparison intrisics
case X86::BI__builtin_ia32_cmpeqps:
case X86::BI__builtin_ia32_cmpltps:
@@ -6351,6 +6371,119 @@
llvm::Function *F = CGM.getIntrinsic(ID);
return Builder.CreateCall(F, Ops, "");
}
+
+ // P8 Crypto builtins
+ case PPC::BI__builtin_altivec_crypto_vshasigmaw:
+ case PPC::BI__builtin_altivec_crypto_vshasigmad:
+ {
+ ConstantInt *CI1 = dyn_cast<ConstantInt>(Ops[1]);
+ ConstantInt *CI2 = dyn_cast<ConstantInt>(Ops[2]);
+ assert(CI1 && CI2);
+ if (CI1->getZExtValue() > 1) {
+ CGM.Error(E->getArg(1)->getExprLoc(),
+ "argument out of range (should be 0-1).");
+ return llvm::UndefValue::get(Ops[0]->getType());
+ }
+ if (CI2->getZExtValue() > 15) {
+ CGM.Error(E->getArg(2)->getExprLoc(),
+ "argument out of range (should be 0-15).");
+ return llvm::UndefValue::get(Ops[0]->getType());
+ }
+ switch (BuiltinID) {
+ default: llvm_unreachable("Unsupported sigma intrinsic!");
+ case PPC::BI__builtin_altivec_crypto_vshasigmaw:
+ ID = Intrinsic::ppc_altivec_crypto_vshasigmaw;
+ break;
+ case PPC::BI__builtin_altivec_crypto_vshasigmad:
+ ID = Intrinsic::ppc_altivec_crypto_vshasigmad;
+ break;
+ }
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, Ops, "");
+ }
+
+ // HTM builtins
+ case PPC::BI__builtin_tbegin:
+ case PPC::BI__builtin_tend:
+ case PPC::BI__builtin_tsr: {
+ unsigned int MaxValue;
+ // The HTM instructions only accept one argument and with limited range.
+ ConstantInt *CI = dyn_cast<ConstantInt>(Ops[0]);
+ assert(CI);
+ switch (BuiltinID) {
+ case PPC::BI__builtin_tbegin:
+ ID = Intrinsic::ppc_tbegin;
+ MaxValue = 1;
+ break;
+ case PPC::BI__builtin_tend:
+ ID = Intrinsic::ppc_tend;
+ MaxValue = 1;
+ break;
+ case PPC::BI__builtin_tsr:
+ ID = Intrinsic::ppc_tsr;
+ MaxValue = 7;
+ break;
+ }
+ if (CI->getZExtValue() > MaxValue) {
+ std::stringstream ss;
+ ss << "argument out of range (should be 0 or " << MaxValue << ")";
+ CGM.Error(E->getArg(0)->getExprLoc(), ss.str());
+ return llvm::UndefValue::get(Ops[0]->getType());
+ }
+
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, Ops, "");
+ }
+ case PPC::BI__builtin_tabortdc:
+ case PPC::BI__builtin_tabortwc: {
+ // For wd and dc variant of tabort first argument must be a 5-bit constant
+ // integer
+ ConstantInt *CI = dyn_cast<ConstantInt>(Ops[0]);
+ assert(CI);
+ if (CI->getZExtValue() > 31) {
+ CGM.ErrorUnsupported(E->getArg(0), "argument out of range (should be 0-31)");
+ return llvm::UndefValue::get(Ops[0]->getType());
+ }
+ switch (BuiltinID) {
+ case PPC::BI__builtin_tabortdc:
+ ID = Intrinsic::ppc_tabortdc;
+ break;
+ case PPC::BI__builtin_tabortwc:
+ ID = Intrinsic::ppc_tabortwc;
+ break;
+ }
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, Ops, "");
+ }
+ case PPC::BI__builtin_tabortdci:
+ case PPC::BI__builtin_tabortwci: {
+ // For wd and dc variant of tabort first and third argument must be a
+ // 5-bit constant integer
+ ConstantInt *CI = dyn_cast<ConstantInt>(Ops[0]);
+ assert(CI);
+ if (CI->getZExtValue() > 31) {
+ CGM.ErrorUnsupported(E->getArg(0), "argument out of range (should be 0-31)");
+ return llvm::UndefValue::get(Ops[0]->getType());
+ }
+ CI = dyn_cast<ConstantInt>(Ops[2]);
+ assert(CI);
+ if (CI->getZExtValue() > 31) {
+ CGM.ErrorUnsupported(E->getArg(2), "argument out of range (should be 0-31)");
+ return llvm::UndefValue::get(Ops[2]->getType());
+ }
+ switch (BuiltinID) {
+ default: llvm_unreachable("Unsupported htm intrinsic!");
+ case PPC::BI__builtin_tabortdci:
+ ID = Intrinsic::ppc_tabortdci;
+ break;
+ case PPC::BI__builtin_tabortwci:
+ ID = Intrinsic::ppc_tabortwci;
+ break;
+ }
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, Ops, "");
+ }
+
}
}
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index d31331d..cb7e6df 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -302,3 +302,10 @@
bool CGCXXABI::NeedsVTTParameter(GlobalDecl GD) {
return false;
}
+
+llvm::CallInst *
+CGCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF,
+ llvm::Value *Exn) {
+ // Just call std::terminate and ignore the violating exception.
+ return CGF.EmitNounwindRuntimeCall(CGF.CGM.getTerminateFn());
+}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index cc5c1b2..b6a94f9 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -22,6 +22,7 @@
class Constant;
class Type;
class Value;
+class CallInst;
}
namespace clang {
@@ -214,8 +215,18 @@
llvm::Value *Ptr, QualType ElementType,
const CXXDestructorDecl *Dtor) = 0;
virtual void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) = 0;
+ virtual void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) = 0;
+ virtual llvm::GlobalVariable *getThrowInfo(QualType T) { return nullptr; }
+
+ virtual void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) = 0;
+
+ virtual llvm::CallInst *
+ emitTerminateForUnexpectedException(CodeGenFunction &CGF,
+ llvm::Value *Exn);
virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0;
+ virtual llvm::Constant *
+ getAddrOfCXXHandlerMapEntry(QualType Ty, QualType CatchHandlerType) = 0;
virtual bool shouldTypeidBeNullChecked(bool IsDeref,
QualType SrcRecordTy) = 0;
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 7e6fef9..d397761 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -31,6 +31,7 @@
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Transforms/Utils/Local.h"
+#include <sstream>
using namespace clang;
using namespace CodeGen;
@@ -346,6 +347,26 @@
FTP->getExtInfo(), RequiredArgs(1));
}
+const CGFunctionInfo &
+CodeGenTypes::arrangeMSCtorClosure(const CXXConstructorDecl *CD,
+ CXXCtorType CT) {
+ assert(CT == Ctor_CopyingClosure || CT == Ctor_DefaultClosure);
+
+ CanQual<FunctionProtoType> FTP = GetFormalType(CD);
+ SmallVector<CanQualType, 2> ArgTys;
+ const CXXRecordDecl *RD = CD->getParent();
+ ArgTys.push_back(GetThisType(Context, RD));
+ if (CT == Ctor_CopyingClosure)
+ ArgTys.push_back(*FTP->param_type_begin());
+ if (RD->getNumVBases() > 0)
+ ArgTys.push_back(Context.IntTy);
+ CallingConv CC = Context.getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/true);
+ return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/true,
+ /*chainCall=*/false, ArgTys,
+ FunctionType::ExtInfo(CC), RequiredArgs::All);
+}
+
/// Arrange a call as unto a free function, except possibly with an
/// additional number of formal parameters considered required.
static const CGFunctionInfo &
@@ -1455,6 +1476,26 @@
if (!CodeGenOpts.StackRealignment)
FuncAttrs.addAttribute("no-realign-stack");
+
+ // Add target-cpu and target-features work if they differ from the defaults.
+ std::string &CPU = getTarget().getTargetOpts().CPU;
+ if (CPU != "" && CPU != getTarget().getTriple().getArchName())
+ FuncAttrs.addAttribute("target-cpu", getTarget().getTargetOpts().CPU);
+
+ // TODO: FeaturesAsWritten gets us the features on the command line,
+ // for canonicalization purposes we might want to avoid putting features
+ // in the target-features set if we know it'll be one of the default
+ // features in the backend, e.g. corei7-avx and +avx.
+ std::vector<std::string> &Features =
+ getTarget().getTargetOpts().FeaturesAsWritten;
+ if (!Features.empty()) {
+ std::stringstream S;
+ std::copy(Features.begin(), Features.end(),
+ std::ostream_iterator<std::string>(S, ","));
+ // The drop_back gets rid of the trailing space.
+ FuncAttrs.addAttribute("target-features",
+ StringRef(S.str()).drop_back(1));
+ }
}
ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI);
@@ -3102,8 +3143,8 @@
: 0);
if ((!ArgInfo.getIndirectByVal() && I->NeedsCopy) ||
(ArgInfo.getIndirectByVal() && TypeAlign.getQuantity() < Align &&
- llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align) ||
- (ArgInfo.getIndirectByVal() && (RVAddrSpace != ArgAddrSpace))) {
+ llvm::getOrEnforceKnownAlignment(Addr, Align, *TD) < Align) ||
+ (ArgInfo.getIndirectByVal() && (RVAddrSpace != ArgAddrSpace))) {
// Create an aligned temporary, and copy to it.
llvm::AllocaInst *AI = CreateMemTemp(I->Ty);
if (Align > AI->getAlignment())
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 5649708..84d6437 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -2093,7 +2093,96 @@
if (!SanOpts.has(SanitizerKind::CFIVptr))
return;
- const CXXRecordDecl *RD = MD->getParent();
+ EmitVTablePtrCheck(MD->getParent(), VTable);
+}
+
+// If a class has a single non-virtual base and does not introduce or override
+// virtual member functions or fields, it will have the same layout as its base.
+// This function returns the least derived such class.
+//
+// Casting an instance of a base class to such a derived class is technically
+// undefined behavior, but it is a relatively common hack for introducing member
+// functions on class instances with specific properties (e.g. llvm::Operator)
+// that works under most compilers and should not have security implications, so
+// we allow it by default. It can be disabled with -fsanitize=cfi-cast-strict.
+static const CXXRecordDecl *
+LeastDerivedClassWithSameLayout(const CXXRecordDecl *RD) {
+ if (!RD->field_empty())
+ return RD;
+
+ if (RD->getNumVBases() != 0)
+ return RD;
+
+ if (RD->getNumBases() != 1)
+ return RD;
+
+ for (const CXXMethodDecl *MD : RD->methods()) {
+ if (MD->isVirtual()) {
+ // Virtual member functions are only ok if they are implicit destructors
+ // because the implicit destructor will have the same semantics as the
+ // base class's destructor if no fields are added.
+ if (isa<CXXDestructorDecl>(MD) && MD->isImplicit())
+ continue;
+ return RD;
+ }
+ }
+
+ return LeastDerivedClassWithSameLayout(
+ RD->bases_begin()->getType()->getAsCXXRecordDecl());
+}
+
+void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T,
+ llvm::Value *Derived,
+ bool MayBeNull) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ auto *ClassTy = T->getAs<RecordType>();
+ if (!ClassTy)
+ return;
+
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassTy->getDecl());
+
+ if (!ClassDecl->isCompleteDefinition() || !ClassDecl->isDynamicClass())
+ return;
+
+ SmallString<64> MangledName;
+ llvm::raw_svector_ostream Out(MangledName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTI(T.getUnqualifiedType(),
+ Out);
+
+ // Blacklist based on the mangled type.
+ if (CGM.getContext().getSanitizerBlacklist().isBlacklistedType(Out.str()))
+ return;
+
+ if (!SanOpts.has(SanitizerKind::CFICastStrict))
+ ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);
+
+ llvm::BasicBlock *ContBlock = 0;
+
+ if (MayBeNull) {
+ llvm::Value *DerivedNotNull =
+ Builder.CreateIsNotNull(Derived, "cast.nonnull");
+
+ llvm::BasicBlock *CheckBlock = createBasicBlock("cast.check");
+ ContBlock = createBasicBlock("cast.cont");
+
+ Builder.CreateCondBr(DerivedNotNull, CheckBlock, ContBlock);
+
+ EmitBlock(CheckBlock);
+ }
+
+ llvm::Value *VTable = GetVTablePtr(Derived, Int8PtrTy);
+ EmitVTablePtrCheck(ClassDecl, VTable);
+
+ if (MayBeNull) {
+ Builder.CreateBr(ContBlock);
+ EmitBlock(ContBlock);
+ }
+}
+
+void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
+ llvm::Value *VTable) {
// FIXME: Add blacklisting scheme.
if (RD->isInStdNamespace())
return;
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 6d78ee8..186c522 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -647,11 +647,19 @@
unsigned Line = getLineNumber(RD->getLocation());
StringRef RDName = getClassName(RD);
+ uint64_t Size = 0;
+ uint64_t Align = 0;
+
+ const RecordDecl *D = RD->getDefinition();
+ if (D && D->isCompleteDefinition()) {
+ Size = CGM.getContext().getTypeSize(Ty);
+ Align = CGM.getContext().getTypeAlign(Ty);
+ }
// Create the type.
SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU);
llvm::DICompositeType RetTy = DBuilder.createReplaceableCompositeType(
- getTagForRecord(RD), RDName, Ctx, DefUnit, Line, 0, 0, 0,
+ getTagForRecord(RD), RDName, Ctx, DefUnit, Line, 0, Size, Align,
llvm::DIDescriptor::FlagFwdDecl, FullName);
ReplaceMap.emplace_back(
std::piecewise_construct, std::make_tuple(Ty),
@@ -2224,7 +2232,7 @@
// Propagate members from the declaration to the definition
// CreateType(const RecordType*) will overwrite this with the members in the
// correct order if the full type is needed.
- DBuilder.replaceArrays(Res, T.getElements());
+ DBuilder.replaceArrays(Res, T ? T.getElements() : llvm::DIArray());
// And update the type cache.
TypeCache[QTy.getAsOpaquePtr()].reset(Res);
@@ -2376,9 +2384,17 @@
// FIXME: Generalize this for even non-member global variables where the
// declaration and definition may have different lexical decl contexts, once
// we have support for emitting declarations of (non-member) global variables.
- VDContext = getContextDescriptor(
- dyn_cast<Decl>(VD->isStaticDataMember() ? VD->getLexicalDeclContext()
- : VD->getDeclContext()));
+ const DeclContext *DC = VD->isStaticDataMember() ? VD->getLexicalDeclContext()
+ : VD->getDeclContext();
+ // When a record type contains an in-line initialization of a static data
+ // member, and the record type is marked as __declspec(dllexport), an implicit
+ // definition of the member will be created in the record context. DWARF
+ // doesn't seem to have a nice way to describe this in a form that consumers
+ // are likely to understand, so fake the "normal" situation of a definition
+ // outside the class by putting it in the global scope.
+ if (DC->isRecord())
+ DC = CGM.getContext().getTranslationUnitDecl();
+ VDContext = getContextDescriptor(dyn_cast<Decl>(DC));
}
llvm::DISubprogram
@@ -3171,6 +3187,7 @@
CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) {
if (!D->isStaticDataMember())
return llvm::DIDerivedType();
+
auto MI = StaticDataMemberCache.find(D->getCanonicalDecl());
if (MI != StaticDataMemberCache.end()) {
assert(MI->second && "Static data member declaration should still exist");
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index fb72a9a..f79d137 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -34,6 +34,7 @@
void CodeGenFunction::EmitDecl(const Decl &D) {
switch (D.getKind()) {
case Decl::TranslationUnit:
+ case Decl::ExternCContext:
case Decl::Namespace:
case Decl::UnresolvedUsingTypename:
case Decl::ClassTemplateSpecialization:
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 9a4303e..236337b 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -139,6 +139,29 @@
const Expr *Init = D.getInit();
QualType T = D.getType();
+ // The address space of a static local variable (DeclPtr) may be different
+ // from the address space of the "this" argument of the constructor. In that
+ // case, we need an addrspacecast before calling the constructor.
+ //
+ // struct StructWithCtor {
+ // __device__ StructWithCtor() {...}
+ // };
+ // __device__ void foo() {
+ // __shared__ StructWithCtor s;
+ // ...
+ // }
+ //
+ // For example, in the above CUDA code, the static local variable s has a
+ // "shared" address space qualifier, but the constructor of StructWithCtor
+ // expects "this" in the "generic" address space.
+ unsigned ExpectedAddrSpace = getContext().getTargetAddressSpace(T);
+ unsigned ActualAddrSpace = DeclPtr->getType()->getPointerAddressSpace();
+ if (ActualAddrSpace != ExpectedAddrSpace) {
+ llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(T);
+ llvm::PointerType *PTy = llvm::PointerType::get(LTy, ExpectedAddrSpace);
+ DeclPtr = llvm::ConstantExpr::getAddrSpaceCast(DeclPtr, PTy);
+ }
+
if (!T->isReferenceType()) {
if (getLangOpts().OpenMP && D.hasAttr<OMPThreadPrivateDeclAttr>())
(void)CGM.getOpenMPRuntime().emitThreadPrivateVarDefinition(
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 4e9eb32..223b8f7 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -25,15 +25,6 @@
using namespace clang;
using namespace CodeGen;
-static llvm::Constant *getAllocateExceptionFn(CodeGenModule &CGM) {
- // void *__cxa_allocate_exception(size_t thrown_size);
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.Int8PtrTy, CGM.SizeTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
-}
-
static llvm::Constant *getFreeExceptionFn(CodeGenModule &CGM) {
// void __cxa_free_exception(void *thrown_exception);
@@ -43,50 +34,6 @@
return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
}
-static llvm::Constant *getThrowFn(CodeGenModule &CGM) {
- // void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
- // void (*dest) (void *));
-
- llvm::Type *Args[3] = { CGM.Int8PtrTy, CGM.Int8PtrTy, CGM.Int8PtrTy };
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, Args, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
-}
-
-static llvm::Constant *getGetExceptionPtrFn(CodeGenModule &CGM) {
- // void *__cxa_get_exception_ptr(void*);
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
-}
-
-static llvm::Constant *getBeginCatchFn(CodeGenModule &CGM) {
- if (CGM.getTarget().getCXXABI().isMicrosoft())
- return CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch);
-
- // void *__cxa_begin_catch(void*);
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
-}
-
-static llvm::Constant *getEndCatchFn(CodeGenModule &CGM) {
- if (CGM.getTarget().getCXXABI().isMicrosoft())
- return CGM.getIntrinsic(llvm::Intrinsic::eh_endcatch);
-
- // void __cxa_end_catch();
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
-}
-
static llvm::Constant *getUnexpectedFn(CodeGenModule &CGM) {
// void __cxa_call_unexpected(void *thrown_exception);
@@ -96,27 +43,27 @@
return CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
-static llvm::Constant *getTerminateFn(CodeGenModule &CGM) {
+llvm::Constant *CodeGenModule::getTerminateFn() {
// void __terminate();
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(VoidTy, /*IsVarArgs=*/false);
StringRef name;
// In C++, use std::terminate().
- if (CGM.getLangOpts().CPlusPlus &&
- CGM.getTarget().getCXXABI().isItaniumFamily()) {
+ if (getLangOpts().CPlusPlus &&
+ getTarget().getCXXABI().isItaniumFamily()) {
name = "_ZSt9terminatev";
- } else if (CGM.getLangOpts().CPlusPlus &&
- CGM.getTarget().getCXXABI().isMicrosoft()) {
+ } else if (getLangOpts().CPlusPlus &&
+ getTarget().getCXXABI().isMicrosoft()) {
name = "\01?terminate@@YAXXZ";
- } else if (CGM.getLangOpts().ObjC1 &&
- CGM.getLangOpts().ObjCRuntime.hasTerminate())
+ } else if (getLangOpts().ObjC1 &&
+ getLangOpts().ObjCRuntime.hasTerminate())
name = "objc_terminate";
else
name = "abort";
- return CGM.CreateRuntimeFunction(FTy, name);
+ return CreateRuntimeFunction(FTy, name);
}
static llvm::Constant *getCatchallRethrowFn(CodeGenModule &CGM,
@@ -414,17 +361,16 @@
// differs from EmitAnyExprToMem only in that, if a final copy-ctor
// call is required, an exception within that copy ctor causes
// std::terminate to be invoked.
-static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e,
- llvm::Value *addr) {
+void CodeGenFunction::EmitAnyExprToExn(const Expr *e, llvm::Value *addr) {
// Make sure the exception object is cleaned up if there's an
// exception during initialization.
- CGF.pushFullExprCleanup<FreeException>(EHCleanup, addr);
- EHScopeStack::stable_iterator cleanup = CGF.EHStack.stable_begin();
+ pushFullExprCleanup<FreeException>(EHCleanup, addr);
+ EHScopeStack::stable_iterator cleanup = EHStack.stable_begin();
// __cxa_allocate_exception returns a void*; we need to cast this
// to the appropriate type for the object.
- llvm::Type *ty = CGF.ConvertTypeForMem(e->getType())->getPointerTo();
- llvm::Value *typedAddr = CGF.Builder.CreateBitCast(addr, ty);
+ llvm::Type *ty = ConvertTypeForMem(e->getType())->getPointerTo();
+ llvm::Value *typedAddr = Builder.CreateBitCast(addr, ty);
// FIXME: this isn't quite right! If there's a final unelided call
// to a copy constructor, then according to [except.terminate]p1 we
@@ -433,11 +379,11 @@
// evaluated but before the exception is caught. But the best way
// to handle that is to teach EmitAggExpr to do the final copy
// differently if it can't be elided.
- CGF.EmitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(),
- /*IsInit*/ true);
+ EmitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(),
+ /*IsInit*/ true);
// Deactivate the cleanup block.
- CGF.DeactivateCleanupBlock(cleanup, cast<llvm::Instruction>(typedAddr));
+ DeactivateCleanupBlock(cleanup, cast<llvm::Instruction>(typedAddr));
}
llvm::Value *CodeGenFunction::getExceptionSlot() {
@@ -469,75 +415,18 @@
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
bool KeepInsertionPoint) {
- if (!E->getSubExpr()) {
- CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/true);
-
- // throw is an expression, and the expression emitters expect us
- // to leave ourselves at a valid insertion point.
- if (KeepInsertionPoint)
- EmitBlock(createBasicBlock("throw.cont"));
-
- return;
- }
-
- if (CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment()) {
- // Call std::terminate().
- llvm::CallInst *TermCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
- TermCall->setDoesNotReturn();
-
- // throw is an expression, and the expression emitters expect us
- // to leave ourselves at a valid insertion point.
- if (KeepInsertionPoint)
- EmitBlock(createBasicBlock("throw.cont"));
-
- return;
- }
-
- QualType ThrowType = E->getSubExpr()->getType();
-
- if (ThrowType->isObjCObjectPointerType()) {
- const Stmt *ThrowStmt = E->getSubExpr();
- const ObjCAtThrowStmt S(E->getExprLoc(),
- const_cast<Stmt *>(ThrowStmt));
- CGM.getObjCRuntime().EmitThrowStmt(*this, S, false);
- // This will clear insertion point which was not cleared in
- // call to EmitThrowStmt.
- if (KeepInsertionPoint)
- EmitBlock(createBasicBlock("throw.cont"));
- return;
- }
-
- // Now allocate the exception object.
- llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
- uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity();
-
- llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(CGM);
- llvm::CallInst *ExceptionPtr =
- EmitNounwindRuntimeCall(AllocExceptionFn,
- llvm::ConstantInt::get(SizeTy, TypeSize),
- "exception");
-
- EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr);
-
- // Now throw the exception.
- llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType,
- /*ForEH=*/true);
-
- // The address of the destructor. If the exception type has a
- // trivial destructor (or isn't a record), we just pass null.
- llvm::Constant *Dtor = nullptr;
- if (const RecordType *RecordTy = ThrowType->getAs<RecordType>()) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
- if (!Record->hasTrivialDestructor()) {
- CXXDestructorDecl *DtorD = Record->getDestructor();
- Dtor = CGM.getAddrOfCXXStructor(DtorD, StructorType::Complete);
- Dtor = llvm::ConstantExpr::getBitCast(Dtor, Int8PtrTy);
+ if (const Expr *SubExpr = E->getSubExpr()) {
+ QualType ThrowType = SubExpr->getType();
+ if (ThrowType->isObjCObjectPointerType()) {
+ const Stmt *ThrowStmt = E->getSubExpr();
+ const ObjCAtThrowStmt S(E->getExprLoc(), const_cast<Stmt *>(ThrowStmt));
+ CGM.getObjCRuntime().EmitThrowStmt(*this, S, false);
+ } else {
+ CGM.getCXXABI().emitThrow(*this, E);
}
+ } else {
+ CGM.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
}
- if (!Dtor) Dtor = llvm::Constant::getNullValue(Int8PtrTy);
-
- llvm::Value *args[] = { ExceptionPtr, TypeInfo, Dtor };
- EmitNoreturnRuntimeCallOrInvoke(getThrowFn(CGM), args);
// throw is an expression, and the expression emitters expect us
// to leave ourselves at a valid insertion point.
@@ -678,7 +567,8 @@
if (CaughtType->isObjCObjectPointerType())
TypeInfo = CGM.getObjCRuntime().GetEHType(CaughtType);
else
- TypeInfo = CGM.GetAddrOfRTTIDescriptor(CaughtType, /*ForEH=*/true);
+ TypeInfo =
+ CGM.getAddrOfCXXHandlerMapEntry(CaughtType, C->getCaughtType());
CatchScope->setHandler(I, TypeInfo, Handler);
} else {
// No exception decl indicates '...', a catch-all.
@@ -920,263 +810,6 @@
return lpad;
}
-namespace {
- /// A cleanup to call __cxa_end_catch. In many cases, the caught
- /// exception type lets us state definitively that the thrown exception
- /// type does not have a destructor. In particular:
- /// - Catch-alls tell us nothing, so we have to conservatively
- /// assume that the thrown exception might have a destructor.
- /// - Catches by reference behave according to their base types.
- /// - Catches of non-record types will only trigger for exceptions
- /// of non-record types, which never have destructors.
- /// - Catches of record types can trigger for arbitrary subclasses
- /// of the caught type, so we have to assume the actual thrown
- /// exception type might have a throwing destructor, even if the
- /// caught type's destructor is trivial or nothrow.
- struct CallEndCatch : EHScopeStack::Cleanup {
- CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}
- bool MightThrow;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- if (!MightThrow) {
- CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
- return;
- }
-
- CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM));
- }
- };
-}
-
-/// Emits a call to __cxa_begin_catch and enters a cleanup to call
-/// __cxa_end_catch.
-///
-/// \param EndMightThrow - true if __cxa_end_catch might throw
-static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
- llvm::Value *Exn,
- bool EndMightThrow) {
- llvm::CallInst *call =
- CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn);
-
- CGF.EHStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup, EndMightThrow);
-
- return call;
-}
-
-/// A "special initializer" callback for initializing a catch
-/// parameter during catch initialization.
-static void InitCatchParam(CodeGenFunction &CGF,
- const VarDecl &CatchParam,
- llvm::Value *ParamAddr,
- SourceLocation Loc) {
- // Load the exception from where the landing pad saved it.
- llvm::Value *Exn = CGF.getExceptionFromSlot();
-
- CanQualType CatchType =
- CGF.CGM.getContext().getCanonicalType(CatchParam.getType());
- llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType);
-
- // If we're catching by reference, we can just cast the object
- // pointer to the appropriate pointer.
- if (isa<ReferenceType>(CatchType)) {
- QualType CaughtType = cast<ReferenceType>(CatchType)->getPointeeType();
- bool EndCatchMightThrow = CaughtType->isRecordType();
-
- // __cxa_begin_catch returns the adjusted object pointer.
- llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, EndCatchMightThrow);
-
- // We have no way to tell the personality function that we're
- // catching by reference, so if we're catching a pointer,
- // __cxa_begin_catch will actually return that pointer by value.
- if (const PointerType *PT = dyn_cast<PointerType>(CaughtType)) {
- QualType PointeeType = PT->getPointeeType();
-
- // When catching by reference, generally we should just ignore
- // this by-value pointer and use the exception object instead.
- if (!PointeeType->isRecordType()) {
-
- // Exn points to the struct _Unwind_Exception header, which
- // we have to skip past in order to reach the exception data.
- unsigned HeaderSize =
- CGF.CGM.getTargetCodeGenInfo().getSizeOfUnwindException();
- AdjustedExn = CGF.Builder.CreateConstGEP1_32(Exn, HeaderSize);
-
- // However, if we're catching a pointer-to-record type that won't
- // work, because the personality function might have adjusted
- // the pointer. There's actually no way for us to fully satisfy
- // the language/ABI contract here: we can't use Exn because it
- // might have the wrong adjustment, but we can't use the by-value
- // pointer because it's off by a level of abstraction.
- //
- // The current solution is to dump the adjusted pointer into an
- // alloca, which breaks language semantics (because changing the
- // pointer doesn't change the exception) but at least works.
- // The better solution would be to filter out non-exact matches
- // and rethrow them, but this is tricky because the rethrow
- // really needs to be catchable by other sites at this landing
- // pad. The best solution is to fix the personality function.
- } else {
- // Pull the pointer for the reference type off.
- llvm::Type *PtrTy =
- cast<llvm::PointerType>(LLVMCatchTy)->getElementType();
-
- // Create the temporary and write the adjusted pointer into it.
- llvm::Value *ExnPtrTmp = CGF.CreateTempAlloca(PtrTy, "exn.byref.tmp");
- llvm::Value *Casted = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
- CGF.Builder.CreateStore(Casted, ExnPtrTmp);
-
- // Bind the reference to the temporary.
- AdjustedExn = ExnPtrTmp;
- }
- }
-
- llvm::Value *ExnCast =
- CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref");
- CGF.Builder.CreateStore(ExnCast, ParamAddr);
- return;
- }
-
- // Scalars and complexes.
- TypeEvaluationKind TEK = CGF.getEvaluationKind(CatchType);
- if (TEK != TEK_Aggregate) {
- llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);
-
- // If the catch type is a pointer type, __cxa_begin_catch returns
- // the pointer by value.
- if (CatchType->hasPointerRepresentation()) {
- llvm::Value *CastExn =
- CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.casted");
-
- switch (CatchType.getQualifiers().getObjCLifetime()) {
- case Qualifiers::OCL_Strong:
- CastExn = CGF.EmitARCRetainNonBlock(CastExn);
- // fallthrough
-
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- CGF.Builder.CreateStore(CastExn, ParamAddr);
- return;
-
- case Qualifiers::OCL_Weak:
- CGF.EmitARCInitWeak(ParamAddr, CastExn);
- return;
- }
- llvm_unreachable("bad ownership qualifier!");
- }
-
- // Otherwise, it returns a pointer into the exception object.
-
- llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
- llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
-
- LValue srcLV = CGF.MakeNaturalAlignAddrLValue(Cast, CatchType);
- LValue destLV = CGF.MakeAddrLValue(ParamAddr, CatchType,
- CGF.getContext().getDeclAlign(&CatchParam));
- switch (TEK) {
- case TEK_Complex:
- CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV, Loc), destLV,
- /*init*/ true);
- return;
- case TEK_Scalar: {
- llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV, Loc);
- CGF.EmitStoreOfScalar(ExnLoad, destLV, /*init*/ true);
- return;
- }
- case TEK_Aggregate:
- llvm_unreachable("evaluation kind filtered out!");
- }
- llvm_unreachable("bad evaluation kind");
- }
-
- assert(isa<RecordType>(CatchType) && "unexpected catch type!");
-
- llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
-
- // Check for a copy expression. If we don't have a copy expression,
- // that means a trivial copy is okay.
- const Expr *copyExpr = CatchParam.getInit();
- if (!copyExpr) {
- llvm::Value *rawAdjustedExn = CallBeginCatch(CGF, Exn, true);
- llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);
- CGF.EmitAggregateCopy(ParamAddr, adjustedExn, CatchType);
- return;
- }
-
- // We have to call __cxa_get_exception_ptr to get the adjusted
- // pointer before copying.
- llvm::CallInst *rawAdjustedExn =
- CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn);
-
- // Cast that to the appropriate type.
- llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);
-
- // The copy expression is defined in terms of an OpaqueValueExpr.
- // Find it and map it to the adjusted expression.
- CodeGenFunction::OpaqueValueMapping
- opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr),
- CGF.MakeAddrLValue(adjustedExn, CatchParam.getType()));
-
- // Call the copy ctor in a terminate scope.
- CGF.EHStack.pushTerminate();
-
- // Perform the copy construction.
- CharUnits Alignment = CGF.getContext().getDeclAlign(&CatchParam);
- CGF.EmitAggExpr(copyExpr,
- AggValueSlot::forAddr(ParamAddr, Alignment, Qualifiers(),
- AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased));
-
- // Leave the terminate scope.
- CGF.EHStack.popTerminate();
-
- // Undo the opaque value mapping.
- opaque.pop();
-
- // Finally we can call __cxa_begin_catch.
- CallBeginCatch(CGF, Exn, true);
-}
-
-/// Begins a catch statement by initializing the catch variable and
-/// calling __cxa_begin_catch.
-static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) {
- // We have to be very careful with the ordering of cleanups here:
- // C++ [except.throw]p4:
- // The destruction [of the exception temporary] occurs
- // immediately after the destruction of the object declared in
- // the exception-declaration in the handler.
- //
- // So the precise ordering is:
- // 1. Construct catch variable.
- // 2. __cxa_begin_catch
- // 3. Enter __cxa_end_catch cleanup
- // 4. Enter dtor cleanup
- //
- // We do this by using a slightly abnormal initialization process.
- // Delegation sequence:
- // - ExitCXXTryStmt opens a RunCleanupsScope
- // - EmitAutoVarAlloca creates the variable and debug info
- // - InitCatchParam initializes the variable from the exception
- // - CallBeginCatch calls __cxa_begin_catch
- // - CallBeginCatch enters the __cxa_end_catch cleanup
- // - EmitAutoVarCleanups enters the variable destructor cleanup
- // - EmitCXXTryStmt emits the code for the catch body
- // - EmitCXXTryStmt close the RunCleanupsScope
-
- VarDecl *CatchParam = S->getExceptionDecl();
- if (!CatchParam) {
- llvm::Value *Exn = CGF.getExceptionFromSlot();
- CallBeginCatch(CGF, Exn, true);
- return;
- }
-
- // Emit the local.
- CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam);
- InitCatchParam(CGF, *CatchParam, var.getObjectAddress(CGF), S->getLocStart());
- CGF.EmitAutoVarCleanups(var);
-}
-
/// Emit the structure of the dispatch block for the given catch scope.
/// It is an invariant that the dispatch block already exists.
static void emitCatchDispatchBlock(CodeGenFunction &CGF,
@@ -1315,7 +948,7 @@
RunCleanupsScope CatchScope(*this);
// Initialize the catch variable and set up the cleanups.
- BeginCatch(*this, C);
+ CGM.getCXXABI().emitBeginCatch(*this, C);
// Emit the PGO counter increment.
RegionCounter CatchCnt = getPGORegionCounter(C);
@@ -1543,70 +1176,6 @@
CGF.PopCleanupBlock();
}
-/// In a terminate landing pad, should we use __clang__call_terminate
-/// or just a naked call to std::terminate?
-///
-/// __clang_call_terminate calls __cxa_begin_catch, which then allows
-/// std::terminate to usefully report something about the
-/// violating exception.
-static bool useClangCallTerminate(CodeGenModule &CGM) {
- // Only do this for Itanium-family ABIs in C++ mode.
- return (CGM.getLangOpts().CPlusPlus &&
- CGM.getTarget().getCXXABI().isItaniumFamily());
-}
-
-/// Get or define the following function:
-/// void @__clang_call_terminate(i8* %exn) nounwind noreturn
-/// This code is used only in C++.
-static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) {
- llvm::FunctionType *fnTy =
- llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- llvm::Constant *fnRef =
- CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate");
-
- llvm::Function *fn = dyn_cast<llvm::Function>(fnRef);
- if (fn && fn->empty()) {
- fn->setDoesNotThrow();
- fn->setDoesNotReturn();
-
- // What we really want is to massively penalize inlining without
- // forbidding it completely. The difference between that and
- // 'noinline' is negligible.
- fn->addFnAttr(llvm::Attribute::NoInline);
-
- // Allow this function to be shared across translation units, but
- // we don't want it to turn into an exported symbol.
- fn->setLinkage(llvm::Function::LinkOnceODRLinkage);
- fn->setVisibility(llvm::Function::HiddenVisibility);
- if (CGM.supportsCOMDAT())
- fn->setComdat(CGM.getModule().getOrInsertComdat(fn->getName()));
-
- // Set up the function.
- llvm::BasicBlock *entry =
- llvm::BasicBlock::Create(CGM.getLLVMContext(), "", fn);
- CGBuilderTy builder(entry);
-
- // Pull the exception pointer out of the parameter list.
- llvm::Value *exn = &*fn->arg_begin();
-
- // Call __cxa_begin_catch(exn).
- llvm::CallInst *catchCall = builder.CreateCall(getBeginCatchFn(CGM), exn);
- catchCall->setDoesNotThrow();
- catchCall->setCallingConv(CGM.getRuntimeCC());
-
- // Call std::terminate().
- llvm::CallInst *termCall = builder.CreateCall(getTerminateFn(CGM));
- termCall->setDoesNotThrow();
- termCall->setDoesNotReturn();
- termCall->setCallingConv(CGM.getRuntimeCC());
-
- // std::terminate cannot return.
- builder.CreateUnreachable();
- }
-
- return fnRef;
-}
-
llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
if (TerminateLandingPad)
return TerminateLandingPad;
@@ -1624,14 +1193,11 @@
getOpaquePersonalityFn(CGM, Personality), 0);
LPadInst->addClause(getCatchAllValue(*this));
- llvm::CallInst *terminateCall;
- if (useClangCallTerminate(CGM)) {
- // Extract out the exception pointer.
- llvm::Value *exn = Builder.CreateExtractValue(LPadInst, 0);
- terminateCall = EmitNounwindRuntimeCall(getClangCallTerminateFn(CGM), exn);
- } else {
- terminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
- }
+ llvm::Value *Exn = 0;
+ if (getLangOpts().CPlusPlus)
+ Exn = Builder.CreateExtractValue(LPadInst, 0);
+ llvm::CallInst *terminateCall =
+ CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);
terminateCall->setDoesNotReturn();
Builder.CreateUnreachable();
@@ -1651,14 +1217,11 @@
// end of the function by FinishFunction.
TerminateHandler = createBasicBlock("terminate.handler");
Builder.SetInsertPoint(TerminateHandler);
- llvm::CallInst *terminateCall;
- if (useClangCallTerminate(CGM)) {
- // Load the exception pointer.
- llvm::Value *exn = getExceptionFromSlot();
- terminateCall = EmitNounwindRuntimeCall(getClangCallTerminateFn(CGM), exn);
- } else {
- terminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
- }
+ llvm::Value *Exn = 0;
+ if (getLangOpts().CPlusPlus)
+ Exn = getExceptionFromSlot();
+ llvm::CallInst *terminateCall =
+ CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);
terminateCall->setDoesNotReturn();
Builder.CreateUnreachable();
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 78e80a1..5ba51cc 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -301,6 +301,23 @@
switch (M->getStorageDuration()) {
case SD_FullExpression:
case SD_Automatic:
+ // If we have a constant temporary array or record try to promote it into a
+ // constant global under the same rules a normal constant would've been
+ // promoted. This is easier on the optimizer and generally emits fewer
+ // instructions.
+ if (CGF.CGM.getCodeGenOpts().MergeAllConstants &&
+ (M->getType()->isArrayType() || M->getType()->isRecordType()) &&
+ CGF.CGM.isTypeConstant(M->getType(), true))
+ if (llvm::Constant *Init =
+ CGF.CGM.EmitConstantExpr(Inner, M->getType(), &CGF)) {
+ auto *GV = new llvm::GlobalVariable(
+ CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp");
+ GV->setAlignment(
+ CGF.getContext().getTypeAlignInChars(M->getType()).getQuantity());
+ // FIXME: Should we put the new global into a COMDAT?
+ return GV;
+ }
return CGF.CreateMemTemp(Inner->getType(), "ref.tmp");
case SD_Thread:
@@ -324,14 +341,15 @@
M->getType().getObjCLifetime() != Qualifiers::OCL_None &&
M->getType().getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
llvm::Value *Object = createReferenceTemporary(*this, M, E);
- LValue RefTempDst = MakeAddrLValue(Object, M->getType());
-
if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
+ Object = llvm::ConstantExpr::getBitCast(
+ Var, ConvertTypeForMem(E->getType())->getPointerTo());
// We should not have emitted the initializer for this temporary as a
// constant.
assert(!Var->hasInitializer());
Var->setInitializer(CGM.EmitNullConstant(E->getType()));
}
+ LValue RefTempDst = MakeAddrLValue(Object, M->getType());
switch (getEvaluationKind(E->getType())) {
default: llvm_unreachable("expected scalar or aggregate expression");
@@ -370,8 +388,11 @@
// Create and initialize the reference temporary.
llvm::Value *Object = createReferenceTemporary(*this, M, E);
if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
- // If the temporary is a global and has a constant initializer, we may
- // have already initialized it.
+ Object = llvm::ConstantExpr::getBitCast(
+ Var, ConvertTypeForMem(E->getType())->getPointerTo());
+ // If the temporary is a global and has a constant initializer or is a
+ // constant temporary that we promoted to a global, we may have already
+ // initialized it.
if (!Var->hasInitializer()) {
Var->setInitializer(CGM.EmitNullConstant(E->getType()));
EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
@@ -3013,6 +3034,9 @@
EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(),
Derived, E->getType());
+ if (SanOpts.has(SanitizerKind::CFIDerivedCast))
+ EmitVTablePtrCheckForCast(E->getType(), Derived, /*MayBeNull=*/false);
+
return MakeAddrLValue(Derived, E->getType());
}
case CK_LValueBitCast: {
@@ -3022,6 +3046,10 @@
LValue LV = EmitLValue(E->getSubExpr());
llvm::Value *V = Builder.CreateBitCast(LV.getAddress(),
ConvertType(CE->getTypeAsWritten()));
+
+ if (SanOpts.has(SanitizerKind::CFIUnrelatedCast))
+ EmitVTablePtrCheckForCast(E->getType(), V, /*MayBeNull=*/false);
+
return MakeAddrLValue(V, E->getType());
}
case CK_ObjCObjectLValueCast: {
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 425a968..6852d3a 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -1422,71 +1422,6 @@
OperatorDelete, ElementType);
}
-static void EmitDelete(CodeGenFunction &CGF,
- const CXXDeleteExpr *DE,
- llvm::Value *Ptr,
- QualType ElementType);
-
-static void EmitSizedDelete(CodeGenFunction &CGF,
- const CXXDeleteExpr *DE,
- llvm::Value *Ptr,
- QualType ElementType,
- FunctionDecl* UnsizedDealloc) {
-
- if (CGF.getLangOpts().DefineSizedDeallocation) {
- // The delete operator in use is fixed. So simply emit the delete expr.
- EmitDelete(CGF, DE, Ptr, ElementType);
- return;
- }
-
- assert(UnsizedDealloc && "We must be emiting a 'sized' delete expr");
-
- // Branch off over the value of operator delete:
- // Use the sized form if available, and default on the unsized form otherwise.
- llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("if.then");
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("if.end");
- llvm::BasicBlock *ElseBlock = CGF.createBasicBlock("if.else");
-
- // Emit the condition.
- const FunctionDecl *OpDelFD = DE->getOperatorDelete();
- llvm::Value *OpDelAddr = CGF.CGM.GetAddrOfFunction(OpDelFD);
- //llvm::Function *OpDel = dyn_cast<llvm::Function>(OpDelAddr);
- llvm::Value *SDE = CGF.Builder.CreateIsNotNull(OpDelAddr, "sized.del.exists");
- CGF.Builder.CreateCondBr(SDE, ThenBlock, ElseBlock);
-
- // Emit the 'then' code.
- CGF.EmitBlock(ThenBlock);
- EmitDelete(CGF, DE, Ptr, ElementType);
- CGF.EmitBranch(ContBlock);
-
- // Compute the 'unsized' delete expr.
- CXXDeleteExpr * E = const_cast<CXXDeleteExpr*>(DE);
- CXXDeleteExpr *UnsizedDE =
- new (CGF.getContext()) CXXDeleteExpr(CGF.getContext().VoidTy,
- E->isGlobalDelete(),
- E->isArrayForm(),
- E->isArrayFormAsWritten(),
- E->doesUsualArrayDeleteWantSize(),
- UnsizedDealloc,
- E->getArgument(),
- E->getLocStart());
- // Emit the 'else' code.
- {
- // There is no need to emit line number for an unconditional branch.
- auto NL = ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBlock(ElseBlock);
- }
- EmitDelete(CGF, UnsizedDE, Ptr, ElementType);
- {
- // There is no need to emit line number for an unconditional branch.
- auto NL = ApplyDebugLocation::CreateEmpty(CGF);
- CGF.EmitBranch(ContBlock);
- }
-
- // Emit the continuation block for code after the if.
- CGF.EmitBlock(ContBlock, true);
-}
-
/// Emit the code for deleting a single object.
static void EmitObjectDelete(CodeGenFunction &CGF,
const CXXDeleteExpr *DE,
@@ -1646,17 +1581,6 @@
CGF.PopCleanupBlock();
}
-static void EmitDelete(CodeGenFunction &CGF,
- const CXXDeleteExpr *DE,
- llvm::Value *Ptr,
- QualType ElementType) {
- if (DE->isArrayForm()) {
- EmitArrayDelete(CGF, DE, Ptr, ElementType);
- } else {
- EmitObjectDelete(CGF, DE, Ptr, ElementType);
- }
-}
-
void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
const Expr *Arg = E->getArgument();
llvm::Value *Ptr = EmitScalarExpr(Arg);
@@ -1696,12 +1620,11 @@
assert(ConvertTypeForMem(DeleteTy) ==
cast<llvm::PointerType>(Ptr->getType())->getElementType());
- const FunctionDecl *Dealloc = E->getOperatorDelete();
- if (FunctionDecl* UnsizedDealloc =
- Dealloc->getCorrespondingUnsizedGlobalDeallocationFunction())
- EmitSizedDelete(*this, E, Ptr, DeleteTy, UnsizedDealloc);
- else
- EmitDelete(*this, E, Ptr, DeleteTy);
+ if (E->isArrayForm()) {
+ EmitArrayDelete(*this, E, Ptr, DeleteTy);
+ } else {
+ EmitObjectDelete(*this, E, Ptr, DeleteTy);
+ }
EmitBlock(DeleteEnd);
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 54f7eee..7406354 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -383,14 +383,19 @@
if (!EltInit)
return false;
-
+
if (!Field->isBitField()) {
// Handle non-bitfield members.
AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit);
} else {
// Otherwise we have a bitfield.
- AppendBitField(*Field, Layout.getFieldOffset(FieldNo),
- cast<llvm::ConstantInt>(EltInit));
+ if (auto *CI = dyn_cast<llvm::ConstantInt>(EltInit)) {
+ AppendBitField(*Field, Layout.getFieldOffset(FieldNo), CI);
+ } else {
+ // We are trying to initialize a bitfield with a non-trivial constant,
+ // this must require run-time code.
+ return false;
+ }
}
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index dc12dd8..16ce69d 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -745,23 +745,37 @@
QualType OrigSrcType = SrcType;
llvm::Type *SrcTy = Src->getType();
- // If casting to/from storage-only half FP, use special intrinsics.
- if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
- !CGF.getContext().getLangOpts().HalfArgsAndReturns) {
- Src = Builder.CreateCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
- CGF.CGM.FloatTy),
- Src);
- SrcType = CGF.getContext().FloatTy;
- SrcTy = CGF.FloatTy;
- }
-
// Handle conversions to bool first, they are special: comparisons against 0.
if (DstType->isBooleanType())
return EmitConversionToBool(Src, SrcType);
llvm::Type *DstTy = ConvertType(DstType);
+ // Cast from half through float if half isn't a native type.
+ if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
+ // Cast to FP using the intrinsic if the half type itself isn't supported.
+ if (DstTy->isFloatingPointTy()) {
+ if (!CGF.getContext().getLangOpts().HalfArgsAndReturns)
+ return Builder.CreateCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16, DstTy),
+ Src);
+ } else {
+ // Cast to other types through float, using either the intrinsic or FPExt,
+ // depending on whether the half type itself is supported
+ // (as opposed to operations on half, available with NativeHalfType).
+ if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) {
+ Src = Builder.CreateCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
+ CGF.CGM.FloatTy),
+ Src);
+ } else {
+ Src = Builder.CreateFPExt(Src, CGF.CGM.FloatTy, "conv");
+ }
+ SrcType = CGF.getContext().FloatTy;
+ SrcTy = CGF.FloatTy;
+ }
+ }
+
// Ignore conversions like int -> uint.
if (SrcTy == DstTy)
return Src;
@@ -818,10 +832,20 @@
EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType,
DstTy);
- // Cast to half via float
- if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
- !CGF.getContext().getLangOpts().HalfArgsAndReturns)
+ // Cast to half through float if half isn't a native type.
+ if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
+ // Make sure we cast in a single step if from another FP type.
+ if (SrcTy->isFloatingPointTy()) {
+ // Use the intrinsic if the half type itself isn't supported
+ // (as opposed to operations on half, available with NativeHalfType).
+ if (!CGF.getContext().getLangOpts().HalfArgsAndReturns)
+ return Builder.CreateCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, SrcTy), Src);
+ // If the half type is supported, just use an fptrunc.
+ return Builder.CreateFPTrunc(Src, DstTy);
+ }
DstTy = CGF.FloatTy;
+ }
if (isa<llvm::IntegerType>(SrcTy)) {
bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
@@ -847,10 +871,14 @@
}
if (DstTy != ResTy) {
- assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion");
- Res = Builder.CreateCall(
+ if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) {
+ assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion");
+ Res = Builder.CreateCall(
CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, CGF.CGM.FloatTy),
Res);
+ } else {
+ Res = Builder.CreateFPTrunc(Res, ResTy, "conv");
+ }
}
return Res;
@@ -1355,6 +1383,13 @@
llvm_unreachable("wrong cast for pointers in different address spaces"
"(must be an address space cast)!");
}
+
+ if (CGF.SanOpts.has(SanitizerKind::CFIUnrelatedCast)) {
+ if (auto PT = DestTy->getAs<PointerType>())
+ CGF.EmitVTablePtrCheckForCast(PT->getPointeeType(), Src,
+ /*MayBeNull=*/true);
+ }
+
return Builder.CreateBitCast(Src, DstTy);
}
case CK_AddressSpaceConversion: {
@@ -1384,6 +1419,10 @@
CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(),
Derived, DestTy->getPointeeType());
+ if (CGF.SanOpts.has(SanitizerKind::CFIDerivedCast))
+ CGF.EmitVTablePtrCheckForCast(DestTy->getPointeeType(), Derived,
+ /*MayBeNull=*/true);
+
return Derived;
}
case CK_UncheckedDerivedToBase:
@@ -1742,13 +1781,16 @@
// Add the inc/dec to the real part.
llvm::Value *amt;
- if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
- !CGF.getContext().getLangOpts().HalfArgsAndReturns) {
+ if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
// Another special case: half FP increment should be done via float
- value = Builder.CreateCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
- CGF.CGM.FloatTy),
- input);
+ if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) {
+ value = Builder.CreateCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
+ CGF.CGM.FloatTy),
+ input, "incdec.conv");
+ } else {
+ value = Builder.CreateFPExt(input, CGF.CGM.FloatTy, "incdec.conv");
+ }
}
if (value->getType()->isFloatTy())
@@ -1758,20 +1800,29 @@
amt = llvm::ConstantFP::get(VMContext,
llvm::APFloat(static_cast<double>(amount)));
else {
+ // Remaining types are either Half or LongDouble. Convert from float.
llvm::APFloat F(static_cast<float>(amount));
bool ignored;
- F.convert(CGF.getTarget().getLongDoubleFormat(),
+ // Don't use getFloatTypeSemantics because Half isn't
+ // necessarily represented using the "half" LLVM type.
+ F.convert(value->getType()->isHalfTy()
+ ? CGF.getTarget().getHalfFormat()
+ : CGF.getTarget().getLongDoubleFormat(),
llvm::APFloat::rmTowardZero, &ignored);
amt = llvm::ConstantFP::get(VMContext, F);
}
value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec");
- if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
- !CGF.getContext().getLangOpts().HalfArgsAndReturns)
- value = Builder.CreateCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16,
- CGF.CGM.FloatTy),
- value);
+ if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
+ if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) {
+ value = Builder.CreateCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16,
+ CGF.CGM.FloatTy),
+ value, "incdec.conv");
+ } else {
+ value = Builder.CreateFPTrunc(value, input->getType(), "incdec.conv");
+ }
+ }
// Objective-C pointer types.
} else {
@@ -2664,21 +2715,34 @@
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.SanOpts.has(SanitizerKind::Shift) && !CGF.getLangOpts().OpenCL &&
- isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ bool SanitizeBase = CGF.SanOpts.has(SanitizerKind::ShiftBase) &&
+ Ops.Ty->hasSignedIntegerRepresentation();
+ bool SanitizeExponent = CGF.SanOpts.has(SanitizerKind::ShiftExponent);
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ if (CGF.getLangOpts().OpenCL)
+ RHS =
+ Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shl.mask");
+ else if ((SanitizeBase || SanitizeExponent) &&
+ isa<llvm::IntegerType>(Ops.LHS->getType())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
+ SmallVector<std::pair<Value *, SanitizerKind>, 2> Checks;
llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, RHS);
- llvm::Value *Valid = Builder.CreateICmpULE(RHS, WidthMinusOne);
+ llvm::Value *ValidExponent = Builder.CreateICmpULE(RHS, WidthMinusOne);
- if (Ops.Ty->hasSignedIntegerRepresentation()) {
+ if (SanitizeExponent) {
+ Checks.push_back(
+ std::make_pair(ValidExponent, SanitizerKind::ShiftExponent));
+ }
+
+ if (SanitizeBase) {
+ // Check whether we are shifting any non-zero bits off the top of the
+ // integer. We only emit this check if exponent is valid - otherwise
+ // instructions below will have undefined behavior themselves.
llvm::BasicBlock *Orig = Builder.GetInsertBlock();
llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
- llvm::BasicBlock *CheckBitsShifted = CGF.createBasicBlock("check");
- Builder.CreateCondBr(Valid, CheckBitsShifted, Cont);
-
- // Check whether we are shifting any non-zero bits off the top of the
- // integer.
- CGF.EmitBlock(CheckBitsShifted);
+ llvm::BasicBlock *CheckShiftBase = CGF.createBasicBlock("check");
+ Builder.CreateCondBr(ValidExponent, CheckShiftBase, Cont);
+ CGF.EmitBlock(CheckShiftBase);
llvm::Value *BitsShiftedOff =
Builder.CreateLShr(Ops.LHS,
Builder.CreateSub(WidthMinusOne, RHS, "shl.zeros",
@@ -2693,19 +2757,17 @@
BitsShiftedOff = Builder.CreateLShr(BitsShiftedOff, One);
}
llvm::Value *Zero = llvm::ConstantInt::get(BitsShiftedOff->getType(), 0);
- llvm::Value *SecondCheck = Builder.CreateICmpEQ(BitsShiftedOff, Zero);
+ llvm::Value *ValidBase = Builder.CreateICmpEQ(BitsShiftedOff, Zero);
CGF.EmitBlock(Cont);
- llvm::PHINode *P = Builder.CreatePHI(Valid->getType(), 2);
- P->addIncoming(Valid, Orig);
- P->addIncoming(SecondCheck, CheckBitsShifted);
- Valid = P;
+ llvm::PHINode *BaseCheck = Builder.CreatePHI(ValidBase->getType(), 2);
+ BaseCheck->addIncoming(Builder.getTrue(), Orig);
+ BaseCheck->addIncoming(ValidBase, CheckShiftBase);
+ Checks.push_back(std::make_pair(BaseCheck, SanitizerKind::ShiftBase));
}
- EmitBinOpCheck(std::make_pair(Valid, SanitizerKind::Shift), Ops);
+ assert(!Checks.empty());
+ EmitBinOpCheck(Checks, Ops);
}
- // OpenCL 6.3j: shift values are effectively % word size of LHS.
- if (CGF.getLangOpts().OpenCL)
- RHS = Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shl.mask");
return Builder.CreateShl(Ops.LHS, RHS, "shl");
}
@@ -2717,18 +2779,18 @@
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.SanOpts.has(SanitizerKind::Shift) && !CGF.getLangOpts().OpenCL &&
- isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ if (CGF.getLangOpts().OpenCL)
+ RHS =
+ Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shr.mask");
+ else if (CGF.SanOpts.has(SanitizerKind::ShiftExponent) &&
+ isa<llvm::IntegerType>(Ops.LHS->getType())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *Valid =
Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS));
- EmitBinOpCheck(std::make_pair(Valid, SanitizerKind::Shift), Ops);
+ EmitBinOpCheck(std::make_pair(Valid, SanitizerKind::ShiftExponent), Ops);
}
- // OpenCL 6.3j: shift values are effectively % word size of LHS.
- if (CGF.getLangOpts().OpenCL)
- RHS = Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shr.mask");
-
if (Ops.Ty->hasUnsignedIntegerRepresentation())
return Builder.CreateLShr(Ops.LHS, RHS, "shr");
return Builder.CreateAShr(Ops.LHS, RHS, "shr");
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index 51865a6..ef2d214 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -13,6 +13,7 @@
#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
+#include "CGCleanup.h"
#include "clang/AST/Decl.h"
#include "clang/AST/StmtOpenMP.h"
#include "llvm/ADT/ArrayRef.h"
@@ -41,7 +42,8 @@
virtual const VarDecl *getThreadIDVariable() const = 0;
/// \brief Get an LValue for the current ThreadID variable.
- LValue getThreadIDVariableLValue(CodeGenFunction &CGF);
+ /// \return LValue for thread id variable. This LValue always has type int32*.
+ virtual LValue getThreadIDVariableLValue(CodeGenFunction &CGF);
/// \brief Emit the captured statement body.
virtual void EmitBody(CodeGenFunction &CGF, const Stmt *S) override;
@@ -76,6 +78,41 @@
const VarDecl *ThreadIDVar;
};
+/// \brief API for captured statement code generation in OpenMP constructs.
+class CGOpenMPTaskOutlinedRegionInfo : public CGOpenMPRegionInfo {
+public:
+ CGOpenMPTaskOutlinedRegionInfo(const OMPExecutableDirective &D,
+ const CapturedStmt &CS,
+ const VarDecl *ThreadIDVar,
+ const VarDecl *PartIDVar)
+ : CGOpenMPRegionInfo(D, CS), ThreadIDVar(ThreadIDVar),
+ PartIDVar(PartIDVar) {
+ assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
+ }
+ /// \brief Get a variable or parameter for storing global thread id
+ /// inside OpenMP construct.
+ virtual const VarDecl *getThreadIDVariable() const override {
+ return ThreadIDVar;
+ }
+
+ /// \brief Get an LValue for the current ThreadID variable.
+ virtual LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override;
+
+ /// \brief Emit the captured statement body.
+ virtual void EmitBody(CodeGenFunction &CGF, const Stmt *S) override;
+
+ /// \brief Get the name of the capture helper.
+ StringRef getHelperName() const override { return ".omp_outlined."; }
+
+private:
+ /// \brief A variable or parameter storing global thread id for OpenMP
+ /// constructs.
+ const VarDecl *ThreadIDVar;
+ /// \brief A variable or parameter storing part id for OpenMP tasking
+ /// constructs.
+ const VarDecl *PartIDVar;
+};
+
/// \brief API for inlined captured statement code generation in OpenMP
/// constructs.
class CGOpenMPInlinedRegionInfo : public CGOpenMPRegionInfo {
@@ -109,6 +146,7 @@
return OuterRegionInfo->getThreadIDVariable();
return nullptr;
}
+
/// \brief Get the name of the capture helper.
virtual StringRef getHelperName() const override {
llvm_unreachable("No helper name for inlined OpenMP construct");
@@ -125,8 +163,13 @@
LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) {
return CGF.MakeNaturalAlignAddrLValue(
- CGF.GetAddrOfLocalVar(getThreadIDVariable()),
- CGF.getContext().getPointerType(getThreadIDVariable()->getType()));
+ CGF.Builder.CreateAlignedLoad(
+ CGF.GetAddrOfLocalVar(getThreadIDVariable()),
+ CGF.PointerAlignInBytes),
+ getThreadIDVariable()
+ ->getType()
+ ->castAs<PointerType>()
+ ->getPointeeType());
}
void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, const Stmt *S) {
@@ -140,8 +183,23 @@
CGCapturedStmtInfo::EmitBody(CGF, S);
}
+LValue CGOpenMPTaskOutlinedRegionInfo::getThreadIDVariableLValue(
+ CodeGenFunction &CGF) {
+ return CGF.MakeNaturalAlignAddrLValue(
+ CGF.GetAddrOfLocalVar(getThreadIDVariable()),
+ getThreadIDVariable()->getType());
+}
+
+void CGOpenMPTaskOutlinedRegionInfo::EmitBody(CodeGenFunction &CGF,
+ const Stmt *S) {
+ if (PartIDVar) {
+ // TODO: emit code for untied tasks.
+ }
+ CGCapturedStmtInfo::EmitBody(CGF, S);
+}
+
CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
- : CGM(CGM), DefaultOpenMPPSource(nullptr) {
+ : CGM(CGM), DefaultOpenMPPSource(nullptr), KmpRoutineEntryPtrTy(nullptr) {
IdentTy = llvm::StructType::create(
"ident_t", CGM.Int32Ty /* reserved_1 */, CGM.Int32Ty /* flags */,
CGM.Int32Ty /* reserved_2 */, CGM.Int32Ty /* reserved_3 */,
@@ -153,9 +211,15 @@
KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
}
+void CGOpenMPRuntime::clear() {
+ InternalVars.clear();
+}
+
llvm::Value *
CGOpenMPRuntime::emitOutlinedFunction(const OMPExecutableDirective &D,
const VarDecl *ThreadIDVar) {
+ assert(ThreadIDVar->getType()->isPointerType() &&
+ "thread id variable must be of type kmp_int32 *");
const CapturedStmt *CS = cast<CapturedStmt>(D.getAssociatedStmt());
CodeGenFunction CGF(CGM, true);
CGOpenMPOutlinedRegionInfo CGInfo(D, *CS, ThreadIDVar);
@@ -164,6 +228,19 @@
}
llvm::Value *
+CGOpenMPRuntime::emitTaskOutlinedFunction(const OMPExecutableDirective &D,
+ const VarDecl *ThreadIDVar,
+ const VarDecl *PartIDVar) {
+ assert(!ThreadIDVar->getType()->isPointerType() &&
+ "thread id variable must be of type kmp_int32 for tasks");
+ auto *CS = cast<CapturedStmt>(D.getAssociatedStmt());
+ CodeGenFunction CGF(CGM, true);
+ CGOpenMPTaskOutlinedRegionInfo CGInfo(D, *CS, ThreadIDVar, PartIDVar);
+ CGF.CapturedStmtInfo = &CGInfo;
+ return CGF.GenerateCapturedStmtFunction(*CS);
+}
+
+llvm::Value *
CGOpenMPRuntime::getOrCreateDefaultLocation(OpenMPLocationFlags Flags) {
llvm::Value *Entry = OpenMPDefaultLocMap.lookup(Flags);
if (!Entry) {
@@ -265,12 +342,9 @@
}
if (auto OMPRegionInfo =
dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
- if (auto ThreadIDVar = OMPRegionInfo->getThreadIDVariable()) {
+ if (OMPRegionInfo->getThreadIDVariable()) {
// Check if this an outlined function with thread id passed as argument.
auto LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF);
- auto RVal = CGF.EmitLoadOfLValue(LVal, Loc);
- LVal = CGF.MakeNaturalAlignAddrLValue(RVal.getScalarVal(),
- ThreadIDVar->getType());
ThreadID = CGF.EmitLoadOfLValue(LVal, Loc).getScalarVal();
// If value loaded in entry block, cache it and use it everywhere in
// function.
@@ -397,87 +471,6 @@
RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_cancel_barrier");
break;
}
- // Build __kmpc_for_static_init*(
- // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype,
- // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower,
- // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride,
- // kmp_int[32|64] incr, kmp_int[32|64] chunk);
- case OMPRTL__kmpc_for_static_init_4: {
- auto ITy = CGM.Int32Ty;
- auto PtrTy = llvm::PointerType::getUnqual(ITy);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), // loc
- CGM.Int32Ty, // tid
- CGM.Int32Ty, // schedtype
- llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
- PtrTy, // p_lower
- PtrTy, // p_upper
- PtrTy, // p_stride
- ITy, // incr
- ITy // chunk
- };
- llvm::FunctionType *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_for_static_init_4");
- break;
- }
- case OMPRTL__kmpc_for_static_init_4u: {
- auto ITy = CGM.Int32Ty;
- auto PtrTy = llvm::PointerType::getUnqual(ITy);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), // loc
- CGM.Int32Ty, // tid
- CGM.Int32Ty, // schedtype
- llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
- PtrTy, // p_lower
- PtrTy, // p_upper
- PtrTy, // p_stride
- ITy, // incr
- ITy // chunk
- };
- llvm::FunctionType *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_for_static_init_4u");
- break;
- }
- case OMPRTL__kmpc_for_static_init_8: {
- auto ITy = CGM.Int64Ty;
- auto PtrTy = llvm::PointerType::getUnqual(ITy);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), // loc
- CGM.Int32Ty, // tid
- CGM.Int32Ty, // schedtype
- llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
- PtrTy, // p_lower
- PtrTy, // p_upper
- PtrTy, // p_stride
- ITy, // incr
- ITy // chunk
- };
- llvm::FunctionType *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_for_static_init_8");
- break;
- }
- case OMPRTL__kmpc_for_static_init_8u: {
- auto ITy = CGM.Int64Ty;
- auto PtrTy = llvm::PointerType::getUnqual(ITy);
- llvm::Type *TypeParams[] = {
- getIdentTyPointerTy(), // loc
- CGM.Int32Ty, // tid
- CGM.Int32Ty, // schedtype
- llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
- PtrTy, // p_lower
- PtrTy, // p_upper
- PtrTy, // p_stride
- ITy, // incr
- ITy // chunk
- };
- llvm::FunctionType *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
- RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_for_static_init_8u");
- break;
- }
case OMPRTL__kmpc_for_static_fini: {
// Build void __kmpc_for_static_fini(ident_t *loc, kmp_int32 global_tid);
llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
@@ -563,10 +556,120 @@
RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_single");
break;
}
+ case OMPRTL__kmpc_omp_task_alloc: {
+ // Build kmp_task_t *__kmpc_omp_task_alloc(ident_t *, kmp_int32 gtid,
+ // kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
+ // kmp_routine_entry_t *task_entry);
+ assert(KmpRoutineEntryPtrTy != nullptr &&
+ "Type kmp_routine_entry_t must be created.");
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.Int32Ty,
+ CGM.SizeTy, CGM.SizeTy, KmpRoutineEntryPtrTy};
+ // Return void * and then cast to particular kmp_task_t type.
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_omp_task_alloc");
+ break;
+ }
+ case OMPRTL__kmpc_omp_task: {
+ // Build kmp_int32 __kmpc_omp_task(ident_t *, kmp_int32 gtid, kmp_task_t
+ // *new_task);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
+ CGM.VoidPtrTy};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_omp_task");
+ break;
+ }
+ case OMPRTL__kmpc_copyprivate: {
+ // Build void __kmpc_copyprivate(ident_t *loc, kmp_int32 global_tid,
+ // kmp_int32 cpy_size, void *cpy_data, void(*cpy_func)(void *, void *),
+ // kmp_int32 didit);
+ llvm::Type *CpyTypeParams[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
+ auto *CpyFnTy =
+ llvm::FunctionType::get(CGM.VoidTy, CpyTypeParams, /*isVarArg=*/false);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.Int32Ty,
+ CGM.VoidPtrTy, CpyFnTy->getPointerTo(),
+ CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_copyprivate");
+ break;
+ }
}
return RTLFn;
}
+llvm::Constant *CGOpenMPRuntime::createForStaticInitFunction(unsigned IVSize,
+ bool IVSigned) {
+ assert((IVSize == 32 || IVSize == 64) &&
+ "IV size is not compatible with the omp runtime");
+ auto Name = IVSize == 32 ? (IVSigned ? "__kmpc_for_static_init_4"
+ : "__kmpc_for_static_init_4u")
+ : (IVSigned ? "__kmpc_for_static_init_8"
+ : "__kmpc_for_static_init_8u");
+ auto ITy = IVSize == 32 ? CGM.Int32Ty : CGM.Int64Ty;
+ auto PtrTy = llvm::PointerType::getUnqual(ITy);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), // loc
+ CGM.Int32Ty, // tid
+ CGM.Int32Ty, // schedtype
+ llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
+ PtrTy, // p_lower
+ PtrTy, // p_upper
+ PtrTy, // p_stride
+ ITy, // incr
+ ITy // chunk
+ };
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ return CGM.CreateRuntimeFunction(FnTy, Name);
+}
+
+llvm::Constant *CGOpenMPRuntime::createDispatchInitFunction(unsigned IVSize,
+ bool IVSigned) {
+ assert((IVSize == 32 || IVSize == 64) &&
+ "IV size is not compatible with the omp runtime");
+ auto Name =
+ IVSize == 32
+ ? (IVSigned ? "__kmpc_dispatch_init_4" : "__kmpc_dispatch_init_4u")
+ : (IVSigned ? "__kmpc_dispatch_init_8" : "__kmpc_dispatch_init_8u");
+ auto ITy = IVSize == 32 ? CGM.Int32Ty : CGM.Int64Ty;
+ llvm::Type *TypeParams[] = { getIdentTyPointerTy(), // loc
+ CGM.Int32Ty, // tid
+ CGM.Int32Ty, // schedtype
+ ITy, // lower
+ ITy, // upper
+ ITy, // stride
+ ITy // chunk
+ };
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ return CGM.CreateRuntimeFunction(FnTy, Name);
+}
+
+llvm::Constant *CGOpenMPRuntime::createDispatchNextFunction(unsigned IVSize,
+ bool IVSigned) {
+ assert((IVSize == 32 || IVSize == 64) &&
+ "IV size is not compatible with the omp runtime");
+ auto Name =
+ IVSize == 32
+ ? (IVSigned ? "__kmpc_dispatch_next_4" : "__kmpc_dispatch_next_4u")
+ : (IVSigned ? "__kmpc_dispatch_next_8" : "__kmpc_dispatch_next_8u");
+ auto ITy = IVSize == 32 ? CGM.Int32Ty : CGM.Int64Ty;
+ auto PtrTy = llvm::PointerType::getUnqual(ITy);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), // loc
+ CGM.Int32Ty, // tid
+ llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
+ PtrTy, // p_lower
+ PtrTy, // p_upper
+ PtrTy // p_stride
+ };
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
+ return CGM.CreateRuntimeFunction(FnTy, Name);
+}
+
llvm::Constant *
CGOpenMPRuntime::getOrCreateThreadPrivateCache(const VarDecl *VD) {
// Lookup the entry, lazily creating it if necessary.
@@ -766,8 +869,7 @@
if (auto OMPRegionInfo =
dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
if (OMPRegionInfo->getThreadIDVariable())
- return CGF.EmitLoadOfLValue(OMPRegionInfo->getThreadIDVariableLValue(CGF),
- Loc).getScalarVal();
+ return OMPRegionInfo->getThreadIDVariableLValue(CGF).getAddress();
auto ThreadID = getThreadID(CGF, Loc);
auto Int32Ty =
@@ -878,19 +980,107 @@
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_taskyield), Args);
}
+static llvm::Value *emitCopyprivateCopyFunction(
+ CodeGenModule &CGM, llvm::Type *ArgsType, ArrayRef<const Expr *> SrcExprs,
+ ArrayRef<const Expr *> DstExprs, ArrayRef<const Expr *> AssignmentOps) {
+ auto &C = CGM.getContext();
+ // void copy_func(void *LHSArg, void *RHSArg);
+ FunctionArgList Args;
+ ImplicitParamDecl LHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
+ C.VoidPtrTy);
+ ImplicitParamDecl RHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
+ C.VoidPtrTy);
+ Args.push_back(&LHSArg);
+ Args.push_back(&RHSArg);
+ FunctionType::ExtInfo EI;
+ auto &CGFI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, Args, EI, /*isVariadic=*/false);
+ auto *Fn = llvm::Function::Create(
+ CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
+ ".omp.copyprivate.copy_func", &CGM.getModule());
+ CGM.SetLLVMFunctionAttributes(/*D=*/nullptr, CGFI, Fn);
+ CodeGenFunction CGF(CGM);
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args);
+ // Dst = (void*[n])(LHSArg);
+ // Src = (void*[n])(RHSArg);
+ auto *LHS = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(CGF.GetAddrOfLocalVar(&LHSArg),
+ CGF.PointerAlignInBytes),
+ ArgsType);
+ auto *RHS = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(CGF.GetAddrOfLocalVar(&RHSArg),
+ CGF.PointerAlignInBytes),
+ ArgsType);
+ // *(Type0*)Dst[0] = *(Type0*)Src[0];
+ // *(Type1*)Dst[1] = *(Type1*)Src[1];
+ // ...
+ // *(Typen*)Dst[n] = *(Typen*)Src[n];
+ CodeGenFunction::OMPPrivateScope Scope(CGF);
+ for (unsigned I = 0, E = AssignmentOps.size(); I < E; ++I) {
+ Scope.addPrivate(
+ cast<VarDecl>(cast<DeclRefExpr>(SrcExprs[I])->getDecl()),
+ [&]() -> llvm::Value *{
+ return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(CGF.Builder.CreateStructGEP(RHS, I),
+ CGM.PointerAlignInBytes),
+ CGF.ConvertTypeForMem(C.getPointerType(SrcExprs[I]->getType())));
+ });
+ Scope.addPrivate(
+ cast<VarDecl>(cast<DeclRefExpr>(DstExprs[I])->getDecl()),
+ [&]() -> llvm::Value *{
+ return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(CGF.Builder.CreateStructGEP(LHS, I),
+ CGM.PointerAlignInBytes),
+ CGF.ConvertTypeForMem(C.getPointerType(SrcExprs[I]->getType())));
+ });
+ }
+ Scope.Privatize();
+ for (auto *E : AssignmentOps) {
+ CGF.EmitIgnoredExpr(E);
+ }
+ Scope.ForceCleanup();
+ CGF.FinishFunction();
+ return Fn;
+}
+
void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF,
const std::function<void()> &SingleOpGen,
- SourceLocation Loc) {
+ SourceLocation Loc,
+ ArrayRef<const Expr *> CopyprivateVars,
+ ArrayRef<const Expr *> SrcExprs,
+ ArrayRef<const Expr *> DstExprs,
+ ArrayRef<const Expr *> AssignmentOps) {
+ assert(CopyprivateVars.size() == SrcExprs.size() &&
+ CopyprivateVars.size() == DstExprs.size() &&
+ CopyprivateVars.size() == AssignmentOps.size());
+ auto &C = CGM.getContext();
+ // int32 did_it = 0;
// if(__kmpc_single(ident_t *, gtid)) {
// SingleOpGen();
// __kmpc_end_single(ident_t *, gtid);
+ // did_it = 1;
// }
+ // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
+ // <copy_func>, did_it);
+
+ llvm::AllocaInst *DidIt = nullptr;
+ if (!CopyprivateVars.empty()) {
+ // int32 did_it = 0;
+ auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
+ DidIt = CGF.CreateMemTemp(KmpInt32Ty, ".omp.copyprivate.did_it");
+ CGF.InitTempAlloca(DidIt, CGF.Builder.getInt32(0));
+ }
// Prepare arguments and build a call to __kmpc_single
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
auto *IsSingle =
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_single), Args);
emitIfStmt(CGF, IsSingle, [&]() -> void {
SingleOpGen();
+ if (DidIt) {
+ // did_it = 1;
+ CGF.Builder.CreateAlignedStore(CGF.Builder.getInt32(1), DidIt,
+ DidIt->getAlignment());
+ }
// Build a call to __kmpc_end_single.
// OpenMP [1.2.2 OpenMP Language Terminology]
// For C/C++, an executable statement, possibly compound, with a single
@@ -907,6 +1097,44 @@
// fallthrough rather than pushing a normal cleanup for it.
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_end_single), Args);
});
+ // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
+ // <copy_func>, did_it);
+ if (DidIt) {
+ llvm::APInt ArraySize(/*unsigned int numBits=*/32, CopyprivateVars.size());
+ auto CopyprivateArrayTy =
+ C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
+ // Create a list of all private variables for copyprivate.
+ auto *CopyprivateList =
+ CGF.CreateMemTemp(CopyprivateArrayTy, ".omp.copyprivate.cpr_list");
+ for (unsigned I = 0, E = CopyprivateVars.size(); I < E; ++I) {
+ auto *Elem = CGF.Builder.CreateStructGEP(CopyprivateList, I);
+ CGF.Builder.CreateAlignedStore(
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.EmitLValue(CopyprivateVars[I]).getAddress(), CGF.VoidPtrTy),
+ Elem, CGM.PointerAlignInBytes);
+ }
+ // Build function that copies private values from single region to all other
+ // threads in the corresponding parallel region.
+ auto *CpyFn = emitCopyprivateCopyFunction(
+ CGM, CGF.ConvertTypeForMem(CopyprivateArrayTy)->getPointerTo(),
+ SrcExprs, DstExprs, AssignmentOps);
+ auto *BufSize = CGF.Builder.getInt32(
+ C.getTypeSizeInChars(CopyprivateArrayTy).getQuantity());
+ auto *CL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(CopyprivateList,
+ CGF.VoidPtrTy);
+ auto *DidItVal =
+ CGF.Builder.CreateAlignedLoad(DidIt, CGF.PointerAlignInBytes);
+ llvm::Value *Args[] = {
+ emitUpdateLocation(CGF, Loc), // ident_t *<loc>
+ getThreadID(CGF, Loc), // i32 <gtid>
+ BufSize, // i32 <buf_size>
+ CL, // void *<copyprivate list>
+ CpyFn, // void (*) (void *, void *) <copy_func>
+ DidItVal // i32 did_it
+ };
+ CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_copyprivate), Args);
+ }
}
void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
@@ -983,34 +1211,50 @@
llvm::Value *UB, llvm::Value *ST,
llvm::Value *Chunk) {
OpenMPSchedType Schedule = getRuntimeSchedule(ScheduleKind, Chunk != nullptr);
- // Call __kmpc_for_static_init(
- // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype,
- // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower,
- // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride,
- // kmp_int[32|64] incr, kmp_int[32|64] chunk);
- // TODO: Implement dynamic schedule.
+ if (Schedule != OMP_sch_static && Schedule != OMP_sch_static_chunked) {
+ // Call __kmpc_dispatch_init(
+ // ident_t *loc, kmp_int32 tid, kmp_int32 schedule,
+ // kmp_int[32|64] lower, kmp_int[32|64] upper,
+ // kmp_int[32|64] stride, kmp_int[32|64] chunk);
- // If the Chunk was not specified in the clause - use default value 1.
- if (Chunk == nullptr)
- Chunk = CGF.Builder.getIntN(IVSize, /*C*/ 1);
-
- llvm::Value *Args[] = {
- emitUpdateLocation(CGF, Loc, OMP_IDENT_KMPC), getThreadID(CGF, Loc),
- CGF.Builder.getInt32(Schedule), // Schedule type
- IL, // &isLastIter
- LB, // &LB
- UB, // &UB
- ST, // &Stride
- CGF.Builder.getIntN(IVSize, 1), // Incr
- Chunk // Chunk
- };
- assert((IVSize == 32 || IVSize == 64) &&
- "Index size is not compatible with the omp runtime");
- auto F = IVSize == 32 ? (IVSigned ? OMPRTL__kmpc_for_static_init_4
- : OMPRTL__kmpc_for_static_init_4u)
- : (IVSigned ? OMPRTL__kmpc_for_static_init_8
- : OMPRTL__kmpc_for_static_init_8u);
- CGF.EmitRuntimeCall(createRuntimeFunction(F), Args);
+ // If the Chunk was not specified in the clause - use default value 1.
+ if (Chunk == nullptr)
+ Chunk = CGF.Builder.getIntN(IVSize, 1);
+ llvm::Value *Args[] = { emitUpdateLocation(CGF, Loc, OMP_IDENT_KMPC),
+ getThreadID(CGF, Loc),
+ CGF.Builder.getInt32(Schedule), // Schedule type
+ CGF.Builder.getIntN(IVSize, 0), // Lower
+ UB, // Upper
+ CGF.Builder.getIntN(IVSize, 1), // Stride
+ Chunk // Chunk
+ };
+ CGF.EmitRuntimeCall(createDispatchInitFunction(IVSize, IVSigned), Args);
+ } else {
+ // Call __kmpc_for_static_init(
+ // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype,
+ // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower,
+ // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride,
+ // kmp_int[32|64] incr, kmp_int[32|64] chunk);
+ if (Chunk == nullptr) {
+ assert(Schedule == OMP_sch_static &&
+ "expected static non-chunked schedule");
+ // If the Chunk was not specified in the clause - use default value 1.
+ Chunk = CGF.Builder.getIntN(IVSize, 1);
+ } else
+ assert(Schedule == OMP_sch_static_chunked &&
+ "expected static chunked schedule");
+ llvm::Value *Args[] = { emitUpdateLocation(CGF, Loc, OMP_IDENT_KMPC),
+ getThreadID(CGF, Loc),
+ CGF.Builder.getInt32(Schedule), // Schedule type
+ IL, // &isLastIter
+ LB, // &LB
+ UB, // &UB
+ ST, // &Stride
+ CGF.Builder.getIntN(IVSize, 1), // Incr
+ Chunk // Chunk
+ };
+ CGF.EmitRuntimeCall(createForStaticInitFunction(IVSize, IVSigned), Args);
+ }
}
void CGOpenMPRuntime::emitForFinish(CodeGenFunction &CGF, SourceLocation Loc,
@@ -1025,6 +1269,29 @@
Args);
}
+llvm::Value *CGOpenMPRuntime::emitForNext(CodeGenFunction &CGF,
+ SourceLocation Loc, unsigned IVSize,
+ bool IVSigned, llvm::Value *IL,
+ llvm::Value *LB, llvm::Value *UB,
+ llvm::Value *ST) {
+ // Call __kmpc_dispatch_next(
+ // ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter,
+ // kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper,
+ // kmp_int[32|64] *p_stride);
+ llvm::Value *Args[] = {
+ emitUpdateLocation(CGF, Loc, OMP_IDENT_KMPC), getThreadID(CGF, Loc),
+ IL, // &isLastIter
+ LB, // &Lower
+ UB, // &Upper
+ ST // &Stride
+ };
+ llvm::Value *Call =
+ CGF.EmitRuntimeCall(createDispatchNextFunction(IVSize, IVSigned), Args);
+ return CGF.EmitScalarConversion(
+ Call, CGF.getContext().getIntTypeForBitwidth(32, /* Signed */ true),
+ CGF.getContext().BoolTy);
+}
+
void CGOpenMPRuntime::emitNumThreadsClause(CodeGenFunction &CGF,
llvm::Value *NumThreads,
SourceLocation Loc) {
@@ -1043,13 +1310,214 @@
emitUpdateLocation(CGF, Loc));
}
+namespace {
+/// \brief Indexes of fields for type kmp_task_t.
+enum KmpTaskTFields {
+ /// \brief List of shared variables.
+ KmpTaskTShareds,
+ /// \brief Task routine.
+ KmpTaskTRoutine,
+ /// \brief Partition id for the untied tasks.
+ KmpTaskTPartId,
+ /// \brief Function with call of destructors for private variables.
+ KmpTaskTDestructors,
+};
+} // namespace
+
+void CGOpenMPRuntime::emitKmpRoutineEntryT(QualType KmpInt32Ty) {
+ if (!KmpRoutineEntryPtrTy) {
+ // Build typedef kmp_int32 (* kmp_routine_entry_t)(kmp_int32, void *); type.
+ auto &C = CGM.getContext();
+ QualType KmpRoutineEntryTyArgs[] = {KmpInt32Ty, C.VoidPtrTy};
+ FunctionProtoType::ExtProtoInfo EPI;
+ KmpRoutineEntryPtrQTy = C.getPointerType(
+ C.getFunctionType(KmpInt32Ty, KmpRoutineEntryTyArgs, EPI));
+ KmpRoutineEntryPtrTy = CGM.getTypes().ConvertType(KmpRoutineEntryPtrQTy);
+ }
+}
+
+static void addFieldToRecordDecl(ASTContext &C, DeclContext *DC,
+ QualType FieldTy) {
+ auto *Field = FieldDecl::Create(
+ C, DC, SourceLocation(), SourceLocation(), /*Id=*/nullptr, FieldTy,
+ C.getTrivialTypeSourceInfo(FieldTy, SourceLocation()),
+ /*BW=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit);
+ Field->setAccess(AS_public);
+ DC->addDecl(Field);
+}
+
+static QualType createKmpTaskTRecordDecl(CodeGenModule &CGM,
+ QualType KmpInt32Ty,
+ QualType KmpRoutineEntryPointerQTy) {
+ auto &C = CGM.getContext();
+ // Build struct kmp_task_t {
+ // void * shareds;
+ // kmp_routine_entry_t routine;
+ // kmp_int32 part_id;
+ // kmp_routine_entry_t destructors;
+ // /* private vars */
+ // };
+ auto *RD = C.buildImplicitRecord("kmp_task_t");
+ RD->startDefinition();
+ addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ addFieldToRecordDecl(C, RD, KmpRoutineEntryPointerQTy);
+ addFieldToRecordDecl(C, RD, KmpInt32Ty);
+ addFieldToRecordDecl(C, RD, KmpRoutineEntryPointerQTy);
+ // TODO: add private fields.
+ RD->completeDefinition();
+ return C.getRecordType(RD);
+}
+
+/// \brief Emit a proxy function which accepts kmp_task_t as the second
+/// argument.
+/// \code
+/// kmp_int32 .omp_task_entry.(kmp_int32 gtid, kmp_task_t *tt) {
+/// TaskFunction(gtid, tt->part_id, tt->shareds);
+/// return 0;
+/// }
+/// \endcode
+static llvm::Value *
+emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc,
+ QualType KmpInt32Ty, QualType KmpTaskTPtrQTy,
+ QualType SharedsPtrTy, llvm::Value *TaskFunction) {
+ auto &C = CGM.getContext();
+ FunctionArgList Args;
+ ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty);
+ ImplicitParamDecl TaskTypeArg(C, /*DC=*/nullptr, Loc,
+ /*Id=*/nullptr, KmpTaskTPtrQTy);
+ Args.push_back(&GtidArg);
+ Args.push_back(&TaskTypeArg);
+ FunctionType::ExtInfo Info;
+ auto &TaskEntryFnInfo =
+ CGM.getTypes().arrangeFreeFunctionDeclaration(KmpInt32Ty, Args, Info,
+ /*isVariadic=*/false);
+ auto *TaskEntryTy = CGM.getTypes().GetFunctionType(TaskEntryFnInfo);
+ auto *TaskEntry =
+ llvm::Function::Create(TaskEntryTy, llvm::GlobalValue::InternalLinkage,
+ ".omp_task_entry.", &CGM.getModule());
+ CGM.SetLLVMFunctionAttributes(/*D=*/nullptr, TaskEntryFnInfo, TaskEntry);
+ CodeGenFunction CGF(CGM);
+ CGF.disableDebugInfo();
+ CGF.StartFunction(GlobalDecl(), KmpInt32Ty, TaskEntry, TaskEntryFnInfo, Args);
+
+ // TaskFunction(gtid, tt->part_id, tt->shareds);
+ auto *GtidParam = CGF.EmitLoadOfScalar(
+ CGF.GetAddrOfLocalVar(&GtidArg), /*Volatile=*/false,
+ C.getTypeAlignInChars(KmpInt32Ty).getQuantity(), KmpInt32Ty, Loc);
+ auto TaskTypeArgAddr = CGF.EmitLoadOfScalar(
+ CGF.GetAddrOfLocalVar(&TaskTypeArg), /*Volatile=*/false,
+ CGM.PointerAlignInBytes, KmpTaskTPtrQTy, Loc);
+ auto *PartidPtr = CGF.Builder.CreateStructGEP(TaskTypeArgAddr,
+ /*Idx=*/KmpTaskTPartId);
+ auto *PartidParam = CGF.EmitLoadOfScalar(
+ PartidPtr, /*Volatile=*/false,
+ C.getTypeAlignInChars(KmpInt32Ty).getQuantity(), KmpInt32Ty, Loc);
+ auto *SharedsPtr = CGF.Builder.CreateStructGEP(TaskTypeArgAddr,
+ /*Idx=*/KmpTaskTShareds);
+ auto *SharedsParam =
+ CGF.EmitLoadOfScalar(SharedsPtr, /*Volatile=*/false,
+ CGM.PointerAlignInBytes, C.VoidPtrTy, Loc);
+ llvm::Value *CallArgs[] = {
+ GtidParam, PartidParam,
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ SharedsParam, CGF.ConvertTypeForMem(SharedsPtrTy))};
+ CGF.EmitCallOrInvoke(TaskFunction, CallArgs);
+ CGF.EmitStoreThroughLValue(
+ RValue::get(CGF.Builder.getInt32(/*C=*/0)),
+ CGF.MakeNaturalAlignAddrLValue(CGF.ReturnValue, KmpInt32Ty));
+ CGF.FinishFunction();
+ return TaskEntry;
+}
+
+void CGOpenMPRuntime::emitTaskCall(
+ CodeGenFunction &CGF, SourceLocation Loc, bool Tied,
+ llvm::PointerIntPair<llvm::Value *, 1, bool> Final,
+ llvm::Value *TaskFunction, QualType SharedsTy, llvm::Value *Shareds) {
+ auto &C = CGM.getContext();
+ auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
+ // Build type kmp_routine_entry_t (if not built yet).
+ emitKmpRoutineEntryT(KmpInt32Ty);
+ // Build particular struct kmp_task_t for the given task.
+ auto KmpTaskQTy =
+ createKmpTaskTRecordDecl(CGM, KmpInt32Ty, KmpRoutineEntryPtrQTy);
+ QualType KmpTaskTPtrQTy = C.getPointerType(KmpTaskQTy);
+ auto KmpTaskTPtrTy = CGF.ConvertType(KmpTaskQTy)->getPointerTo();
+ auto KmpTaskTySize = CGM.getSize(C.getTypeSizeInChars(KmpTaskQTy));
+ QualType SharedsPtrTy = C.getPointerType(SharedsTy);
+
+ // Build a proxy function kmp_int32 .omp_task_entry.(kmp_int32 gtid,
+ // kmp_task_t *tt);
+ auto *TaskEntry = emitProxyTaskFunction(CGM, Loc, KmpInt32Ty, KmpTaskTPtrQTy,
+ SharedsPtrTy, TaskFunction);
+
+ // Build call kmp_task_t * __kmpc_omp_task_alloc(ident_t *, kmp_int32 gtid,
+ // kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
+ // kmp_routine_entry_t *task_entry);
+ // Task flags. Format is taken from
+ // http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp.h,
+ // description of kmp_tasking_flags struct.
+ const unsigned TiedFlag = 0x1;
+ const unsigned FinalFlag = 0x2;
+ unsigned Flags = Tied ? TiedFlag : 0;
+ auto *TaskFlags =
+ Final.getPointer()
+ ? CGF.Builder.CreateSelect(Final.getPointer(),
+ CGF.Builder.getInt32(FinalFlag),
+ CGF.Builder.getInt32(/*C=*/0))
+ : CGF.Builder.getInt32(Final.getInt() ? FinalFlag : 0);
+ TaskFlags = CGF.Builder.CreateOr(TaskFlags, CGF.Builder.getInt32(Flags));
+ auto SharedsSize = C.getTypeSizeInChars(SharedsTy);
+ llvm::Value *AllocArgs[] = {emitUpdateLocation(CGF, Loc),
+ getThreadID(CGF, Loc), TaskFlags, KmpTaskTySize,
+ CGM.getSize(SharedsSize),
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ TaskEntry, KmpRoutineEntryPtrTy)};
+ auto *NewTask = CGF.EmitRuntimeCall(
+ createRuntimeFunction(OMPRTL__kmpc_omp_task_alloc), AllocArgs);
+ auto *NewTaskNewTaskTTy =
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(NewTask, KmpTaskTPtrTy);
+ // Fill the data in the resulting kmp_task_t record.
+ // Copy shareds if there are any.
+ if (!SharedsTy->getAsStructureType()->getDecl()->field_empty())
+ CGF.EmitAggregateCopy(
+ CGF.EmitLoadOfScalar(
+ CGF.Builder.CreateStructGEP(NewTaskNewTaskTTy,
+ /*Idx=*/KmpTaskTShareds),
+ /*Volatile=*/false, CGM.PointerAlignInBytes, SharedsPtrTy, Loc),
+ Shareds, SharedsTy);
+ // TODO: generate function with destructors for privates.
+ // Provide pointer to function with destructors for privates.
+ CGF.Builder.CreateAlignedStore(
+ llvm::ConstantPointerNull::get(
+ cast<llvm::PointerType>(KmpRoutineEntryPtrTy)),
+ CGF.Builder.CreateStructGEP(NewTaskNewTaskTTy,
+ /*Idx=*/KmpTaskTDestructors),
+ CGM.PointerAlignInBytes);
+
+ // NOTE: routine and part_id fields are intialized by __kmpc_omp_task_alloc()
+ // libcall.
+ // Build kmp_int32 __kmpc_omp_task(ident_t *, kmp_int32 gtid, kmp_task_t
+ // *new_task);
+ llvm::Value *TaskArgs[] = {emitUpdateLocation(CGF, Loc),
+ getThreadID(CGF, Loc), NewTask};
+ // TODO: add check for untied tasks.
+ CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_task), TaskArgs);
+}
+
InlinedOpenMPRegionRAII::InlinedOpenMPRegionRAII(
CodeGenFunction &CGF, const OMPExecutableDirective &D)
: CGF(CGF) {
CGF.CapturedStmtInfo = new CGOpenMPInlinedRegionInfo(D, CGF.CapturedStmtInfo);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CGF.EHStack.pushTerminate();
}
InlinedOpenMPRegionRAII::~InlinedOpenMPRegionRAII() {
+ CGF.EHStack.popTerminate();
auto *OldCSI =
cast<CGOpenMPInlinedRegionInfo>(CGF.CapturedStmtInfo)->getOldCSI();
delete CGF.CapturedStmtInfo;
diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h
index 97aa5b8..f8849e6 100644
--- a/lib/CodeGen/CGOpenMPRuntime.h
+++ b/lib/CodeGen/CGOpenMPRuntime.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
#define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
+#include "clang/AST/Type.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
@@ -64,11 +65,7 @@
// Call to kmp_int32 __kmpc_cancel_barrier(ident_t *loc, kmp_int32
// global_tid);
OMPRTL__kmpc_cancel_barrier,
- // Calls for static scheduling 'omp for' loops.
- OMPRTL__kmpc_for_static_init_4,
- OMPRTL__kmpc_for_static_init_4u,
- OMPRTL__kmpc_for_static_init_8,
- OMPRTL__kmpc_for_static_init_8u,
+ // Call to void __kmpc_for_static_fini(ident_t *loc, kmp_int32 global_tid);
OMPRTL__kmpc_for_static_fini,
// Call to void __kmpc_serialized_parallel(ident_t *loc, kmp_int32
// global_tid);
@@ -92,6 +89,17 @@
OMPRTL__kmpc_single,
// Call to void __kmpc_end_single(ident_t *, kmp_int32 global_tid);
OMPRTL__kmpc_end_single,
+ // Call to kmp_task_t * __kmpc_omp_task_alloc(ident_t *, kmp_int32 gtid,
+ // kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
+ // kmp_routine_entry_t *task_entry);
+ OMPRTL__kmpc_omp_task_alloc,
+ // Call to kmp_int32 __kmpc_omp_task(ident_t *, kmp_int32 gtid, kmp_task_t *
+ // new_task);
+ OMPRTL__kmpc_omp_task,
+ // Call to void __kmpc_copyprivate(ident_t *loc, kmp_int32 global_tid,
+ // kmp_int32 cpy_size, void *cpy_data, void(*cpy_func)(void *, void *),
+ // kmp_int32 didit);
+ OMPRTL__kmpc_copyprivate,
};
/// \brief Values for bit flags used in the ident_t to describe the fields.
@@ -190,6 +198,12 @@
/// variables.
llvm::StringMap<llvm::AssertingVH<llvm::Constant>, llvm::BumpPtrAllocator>
InternalVars;
+ /// \brief Type typedef kmp_int32 (* kmp_routine_entry_t)(kmp_int32, void *);
+ llvm::Type *KmpRoutineEntryPtrTy;
+ QualType KmpRoutineEntryPtrQTy;
+
+ /// \brief Build type kmp_routine_entry_t (if not built yet).
+ void emitKmpRoutineEntryT(QualType KmpInt32Ty);
/// \brief Emits object of ident_t type with info for source location.
/// \param Flags Flags for OpenMP location.
@@ -208,6 +222,18 @@
/// \return Specified function.
llvm::Constant *createRuntimeFunction(OpenMPRTLFunction Function);
+ /// \brief Returns __kmpc_for_static_init_* runtime function for the specified
+ /// size \a IVSize and sign \a IVSigned.
+ llvm::Constant *createForStaticInitFunction(unsigned IVSize, bool IVSigned);
+
+ /// \brief Returns __kmpc_dispatch_init_* runtime function for the specified
+ /// size \a IVSize and sign \a IVSigned.
+ llvm::Constant *createDispatchInitFunction(unsigned IVSize, bool IVSigned);
+
+ /// \brief Returns __kmpc_dispatch_next_* runtime function for the specified
+ /// size \a IVSize and sign \a IVSigned.
+ llvm::Constant *createDispatchNextFunction(unsigned IVSize, bool IVSigned);
+
/// \brief If the specified mangled name is not in the module, create and
/// return threadprivate cache object. This object is a pointer's worth of
/// storage that's reserved for use by the OpenMP runtime.
@@ -256,17 +282,28 @@
public:
explicit CGOpenMPRuntime(CodeGenModule &CGM);
virtual ~CGOpenMPRuntime() {}
+ virtual void clear();
- /// \brief Emits outlined function for the specified OpenMP directive \a D
- /// (required for parallel and task directives). This outlined function has
- /// type void(*)(kmp_int32 /*ThreadID*/, kmp_int32 /*BoundID*/, struct
- /// context_vars*).
+ /// \brief Emits outlined function for the specified OpenMP directive \a D.
+ /// This outlined function has type void(*)(kmp_int32 *ThreadID, kmp_int32
+ /// BoundID, struct context_vars*).
/// \param D OpenMP directive.
/// \param ThreadIDVar Variable for thread id in the current OpenMP region.
///
virtual llvm::Value *emitOutlinedFunction(const OMPExecutableDirective &D,
const VarDecl *ThreadIDVar);
+ /// \brief Emits outlined function for the OpenMP task directive \a D. This
+ /// outlined function has type void(*)(kmp_int32 ThreadID, kmp_int32
+ /// PartID, struct context_vars*).
+ /// \param D OpenMP directive.
+ /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
+ /// \param PartIDVar If not nullptr - variable used for part id in tasks.
+ ///
+ virtual llvm::Value *emitTaskOutlinedFunction(const OMPExecutableDirective &D,
+ const VarDecl *ThreadIDVar,
+ const VarDecl *PartIDVar);
+
/// \brief Cleans up references to the objects in finished function.
///
void functionFinished(CodeGenFunction &CGF);
@@ -274,7 +311,7 @@
/// \brief Emits code for parallel call of the \a OutlinedFn with variables
/// captured in a record which address is stored in \a CapturedStruct.
/// \param OutlinedFn Outlined function to be run in parallel threads. Type of
- /// this function is void(*)(kmp_int32, kmp_int32, struct context_vars*).
+ /// this function is void(*)(kmp_int32 *, kmp_int32, struct context_vars*).
/// \param CapturedStruct A pointer to the record with the references to
/// variables used in \a OutlinedFn function.
///
@@ -315,7 +352,11 @@
/// single region.
virtual void emitSingleRegion(CodeGenFunction &CGF,
const std::function<void()> &SingleOpGen,
- SourceLocation Loc);
+ SourceLocation Loc,
+ ArrayRef<const Expr *> CopyprivateVars,
+ ArrayRef<const Expr *> SrcExprs,
+ ArrayRef<const Expr *> DstExprs,
+ ArrayRef<const Expr *> AssignmentOps);
/// \brief Emits explicit barrier for OpenMP threads.
/// \param IsExplicit true, if it is explicitly specified barrier.
@@ -376,6 +417,25 @@
virtual void emitForFinish(CodeGenFunction &CGF, SourceLocation Loc,
OpenMPScheduleClauseKind ScheduleKind);
+ /// Call __kmpc_dispatch_next(
+ /// ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter,
+ /// kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper,
+ /// kmp_int[32|64] *p_stride);
+ /// \param IVSize Size of the iteration variable in bits.
+ /// \param IVSigned Sign of the interation variable.
+ /// \param IL Address of the output variable in which the flag of the
+ /// last iteration is returned.
+ /// \param LB Address of the output variable in which the lower iteration
+ /// number is returned.
+ /// \param UB Address of the output variable in which the upper iteration
+ /// number is returned.
+ /// \param ST Address of the output variable in which the stride value is
+ /// returned.
+ virtual llvm::Value *emitForNext(CodeGenFunction &CGF, SourceLocation Loc,
+ unsigned IVSize, bool IVSigned,
+ llvm::Value *IL, llvm::Value *LB,
+ llvm::Value *UB, llvm::Value *ST);
+
/// \brief Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32
/// global_tid, kmp_int32 num_threads) to generate code for 'num_threads'
/// clause.
@@ -412,6 +472,39 @@
/// \param Vars List of variables to flush.
virtual void emitFlush(CodeGenFunction &CGF, ArrayRef<const Expr *> Vars,
SourceLocation Loc);
+
+ /// \brief Emit task region for the task directive. The task region is
+ /// emmitted in several steps:
+ /// 1. Emit a call to kmp_task_t *__kmpc_omp_task_alloc(ident_t *, kmp_int32
+ /// gtid, kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
+ /// kmp_routine_entry_t *task_entry). Here task_entry is a pointer to the
+ /// function:
+ /// kmp_int32 .omp_task_entry.(kmp_int32 gtid, kmp_task_t *tt) {
+ /// TaskFunction(gtid, tt->part_id, tt->shareds);
+ /// return 0;
+ /// }
+ /// 2. Copy a list of shared variables to field shareds of the resulting
+ /// structure kmp_task_t returned by the previous call (if any).
+ /// 3. Copy a pointer to destructions function to field destructions of the
+ /// resulting structure kmp_task_t.
+ /// 4. Emit a call to kmp_int32 __kmpc_omp_task(ident_t *, kmp_int32 gtid,
+ /// kmp_task_t *new_task), where new_task is a resulting structure from
+ /// previous items.
+ /// \param Tied true if the task is tied (the task is tied to the thread that
+ /// can suspend its task region), false - untied (the task is not tied to any
+ /// thread).
+ /// \param Final Contains either constant bool value, or llvm::Value * of i1
+ /// type for final clause. If the value is true, the task forces all of its
+ /// child tasks to become final and included tasks.
+ /// \param TaskFunction An LLVM function with type void (*)(i32 /*gtid*/, i32
+ /// /*part_id*/, captured_struct */*__context*/);
+ /// \param SharedsTy A type which contains references the shared variables.
+ /// \param Shareds Context with the list of shared variables from the \a
+ /// TaskFunction.
+ virtual void emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, bool Tied,
+ llvm::PointerIntPair<llvm::Value *, 1, bool> Final,
+ llvm::Value *TaskFunction, QualType SharedsTy,
+ llvm::Value *Shareds);
};
/// \brief RAII for emitting code of CapturedStmt without function outlining.
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 0d160d3..e433984 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -2186,6 +2186,8 @@
llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
CapturedStmtInfo->getHelperName(), &CGM.getModule());
CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
+ if (CD->isNothrow())
+ F->addFnAttr(llvm::Attribute::NoUnwind);
// Generate the function.
StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args,
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index daf5fcc..9af7474 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -23,6 +23,20 @@
//===----------------------------------------------------------------------===//
// OpenMP Directive Emission
//===----------------------------------------------------------------------===//
+namespace {
+/// \brief RAII for inlined OpenMP regions (like 'omp for', 'omp simd', 'omp
+/// critical' etc.). Helps to generate proper debug info and provides correct
+/// code generation for such constructs.
+class InlinedOpenMPRegionScopeRAII {
+ InlinedOpenMPRegionRAII Region;
+ CodeGenFunction::LexicalScope DirectiveScope;
+
+public:
+ InlinedOpenMPRegionScopeRAII(CodeGenFunction &CGF,
+ const OMPExecutableDirective &D)
+ : Region(CGF, D), DirectiveScope(CGF, D.getSourceRange()) {}
+};
+} // namespace
/// \brief Emits code for OpenMP 'if' clause using specified \a CodeGen
/// function. Here is the logic:
@@ -175,7 +189,7 @@
EmitDecl(*VD);
return GetAddrOfLocalVar(VD);
});
- assert(IsRegistered && "counter already registered as private");
+ assert(IsRegistered && "firstprivate var already registered as private");
// Silence the warning about unused variable.
(void)IsRegistered;
++IRef, ++InitsRef;
@@ -202,7 +216,7 @@
EmitDecl(*VD);
return GetAddrOfLocalVar(VD);
});
- assert(IsRegistered && "counter already registered as private");
+ assert(IsRegistered && "private var already registered as private");
// Silence the warning about unused variable.
(void)IsRegistered;
++IRef;
@@ -252,6 +266,13 @@
for (auto I : S.updates()) {
EmitIgnoredExpr(I);
}
+ // Update the linear variables.
+ for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
+ for (auto U : C->updates()) {
+ EmitIgnoredExpr(U);
+ }
+ }
+
// On a continue in the body, jump to the end.
auto Continue = getJumpDestInCurrentScope("omp.body.continue");
BreakContinueStack.push_back(BreakContinue(JumpDest(), Continue));
@@ -268,9 +289,10 @@
}
}
-void CodeGenFunction::EmitOMPInnerLoop(const OMPLoopDirective &S,
- OMPPrivateScope &LoopScope,
- bool SeparateIter) {
+void CodeGenFunction::EmitOMPInnerLoop(const Stmt &S, bool RequiresCleanup,
+ const Expr *LoopCond,
+ const Expr *IncExpr,
+ const std::function<void()> &BodyGen) {
auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end");
auto Cnt = getPGORegionCounter(&S);
@@ -282,17 +304,13 @@
// If there are any cleanups between here and the loop-exit scope,
// create a block to stage a loop exit along.
auto ExitBlock = LoopExit.getBlock();
- if (LoopScope.requiresCleanups())
+ if (RequiresCleanup)
ExitBlock = createBasicBlock("omp.inner.for.cond.cleanup");
auto LoopBody = createBasicBlock("omp.inner.for.body");
- // Emit condition: "IV < LastIteration + 1 [ - 1]"
- // ("- 1" when lastprivate clause is present - separate one iteration).
- llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond(SeparateIter));
- Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock,
- PGO.createLoopWeights(S.getCond(SeparateIter), Cnt));
-
+ // Emit condition.
+ EmitBranchOnBoolExpr(LoopCond, LoopBody, ExitBlock, Cnt.getCount());
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
@@ -305,12 +323,11 @@
auto Continue = getJumpDestInCurrentScope("omp.inner.for.inc");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
- EmitOMPLoopBody(S);
- EmitStopPoint(&S);
+ BodyGen();
// Emit "IV = IV + 1" and a back-edge to the condition block.
EmitBlock(Continue.getBlock());
- EmitIgnoredExpr(S.getInc());
+ EmitIgnoredExpr(IncExpr);
BreakContinueStack.pop_back();
EmitBranch(CondBlock);
LoopStack.pop();
@@ -326,6 +343,12 @@
}
++IC;
}
+ // Emit the final values of the linear variables.
+ for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
+ for (auto F : C->finals()) {
+ EmitIgnoredExpr(F);
+ }
+ }
}
static void EmitOMPAlignedClause(CodeGenFunction &CGF, CodeGenModule &CGM,
@@ -369,7 +392,25 @@
// Silence the warning about unused variable.
(void)IsRegistered;
}
- (void)LoopScope.Privatize();
+}
+
+static void
+EmitPrivateLinearVars(CodeGenFunction &CGF, const OMPExecutableDirective &D,
+ CodeGenFunction::OMPPrivateScope &PrivateScope) {
+ for (auto Clause : OMPExecutableDirective::linear_filter(D.clauses())) {
+ for (auto *E : Clause->varlists()) {
+ auto VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
+ bool IsRegistered = PrivateScope.addPrivate(VD, [&]()->llvm::Value * {
+ // Emit var without initialization.
+ auto VarEmission = CGF.EmitAutoVarAlloca(*VD);
+ CGF.EmitAutoVarCleanups(VarEmission);
+ return VarEmission.getAllocatedAddress();
+ });
+ assert(IsRegistered && "linear var already registered as private");
+ // Silence the warning about unused variable.
+ (void)IsRegistered;
+ }
+ }
}
void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
@@ -417,12 +458,15 @@
}
}
- InlinedOpenMPRegionRAII Region(*this, S);
- RunCleanupsScope DirectiveScope(*this);
+ InlinedOpenMPRegionScopeRAII Region(*this, S);
- CGDebugInfo *DI = getDebugInfo();
- if (DI)
- DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
+ // Emit inits for the linear variables.
+ for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
+ for (auto Init : C->inits()) {
+ auto *D = cast<VarDecl>(cast<DeclRefExpr>(Init)->getDecl());
+ EmitVarDecl(*D);
+ }
+ }
// Emit the loop iteration variable.
const Expr *IVExpr = S.getIterationVariable();
@@ -439,6 +483,17 @@
EmitIgnoredExpr(S.getCalcLastIteration());
}
+ // Emit the linear steps for the linear clauses.
+ // If a step is not constant, it is pre-calculated before the loop.
+ for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
+ if (auto CS = cast_or_null<BinaryOperator>(C->getCalcStep()))
+ if (auto SaveRef = cast<DeclRefExpr>(CS->getLHS())) {
+ EmitVarDecl(*cast<VarDecl>(SaveRef->getDecl()));
+ // Emit calculation of the linear step.
+ EmitIgnoredExpr(CS);
+ }
+ }
+
if (SeparateIter) {
// Emit: if (LastIteration > 0) - begin.
RegionCounter Cnt = getPGORegionCounter(&S);
@@ -451,7 +506,15 @@
{
OMPPrivateScope LoopScope(*this);
EmitPrivateLoopCounters(*this, LoopScope, S.counters());
- EmitOMPInnerLoop(S, LoopScope, /* SeparateIter */ true);
+ EmitPrivateLinearVars(*this, S, LoopScope);
+ EmitOMPPrivateClause(S, LoopScope);
+ (void)LoopScope.Privatize();
+ EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
+ S.getCond(/*SeparateIter=*/true), S.getInc(),
+ [&S, this]() {
+ EmitOMPLoopBody(S);
+ EmitStopPoint(&S);
+ });
EmitOMPLoopBody(S, /* SeparateIter */ true);
}
EmitOMPSimdFinal(S);
@@ -462,13 +525,18 @@
{
OMPPrivateScope LoopScope(*this);
EmitPrivateLoopCounters(*this, LoopScope, S.counters());
- EmitOMPInnerLoop(S, LoopScope);
+ EmitPrivateLinearVars(*this, S, LoopScope);
+ EmitOMPPrivateClause(S, LoopScope);
+ (void)LoopScope.Privatize();
+ EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
+ S.getCond(/*SeparateIter=*/false), S.getInc(),
+ [&S, this]() {
+ EmitOMPLoopBody(S);
+ EmitStopPoint(&S);
+ });
}
EmitOMPSimdFinal(S);
}
-
- if (DI)
- DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
}
void CodeGenFunction::EmitOMPForOuterLoop(OpenMPScheduleClauseKind ScheduleKind,
@@ -478,16 +546,50 @@
llvm::Value *ST, llvm::Value *IL,
llvm::Value *Chunk) {
auto &RT = CGM.getOpenMPRuntime();
+
+ // Dynamic scheduling of the outer loop (dynamic, guided, auto, runtime).
+ const bool Dynamic = RT.isDynamic(ScheduleKind);
+
assert(!RT.isStaticNonchunked(ScheduleKind, /* Chunked */ Chunk != nullptr) &&
"static non-chunked schedule does not need outer loop");
- if (RT.isDynamic(ScheduleKind)) {
- ErrorUnsupported(&S, "OpenMP loop with dynamic schedule");
- return;
- }
// Emit outer loop.
//
// OpenMP [2.7.1, Loop Construct, Description, table 2-1]
+ // When schedule(dynamic,chunk_size) is specified, the iterations are
+ // distributed to threads in the team in chunks as the threads request them.
+ // Each thread executes a chunk of iterations, then requests another chunk,
+ // until no chunks remain to be distributed. Each chunk contains chunk_size
+ // iterations, except for the last chunk to be distributed, which may have
+ // fewer iterations. When no chunk_size is specified, it defaults to 1.
+ //
+ // When schedule(guided,chunk_size) is specified, the iterations are assigned
+ // to threads in the team in chunks as the executing threads request them.
+ // Each thread executes a chunk of iterations, then requests another chunk,
+ // until no chunks remain to be assigned. For a chunk_size of 1, the size of
+ // each chunk is proportional to the number of unassigned iterations divided
+ // by the number of threads in the team, decreasing to 1. For a chunk_size
+ // with value k (greater than 1), the size of each chunk is determined in the
+ // same way, with the restriction that the chunks do not contain fewer than k
+ // iterations (except for the last chunk to be assigned, which may have fewer
+ // than k iterations).
+ //
+ // When schedule(auto) is specified, the decision regarding scheduling is
+ // delegated to the compiler and/or runtime system. The programmer gives the
+ // implementation the freedom to choose any possible mapping of iterations to
+ // threads in the team.
+ //
+ // When schedule(runtime) is specified, the decision regarding scheduling is
+ // deferred until run time, and the schedule and chunk size are taken from the
+ // run-sched-var ICV. If the ICV is set to auto, the schedule is
+ // implementation defined
+ //
+ // while(__kmpc_dispatch_next(&LB, &UB)) {
+ // idx = LB;
+ // while (idx <= UB) { BODY; ++idx; } // inner loop
+ // }
+ //
+ // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
// When schedule(static, chunk_size) is specified, iterations are divided into
// chunks of size chunk_size, and the chunks are assigned to the threads in
// the team in a round-robin fashion in the order of the thread number.
@@ -498,12 +600,16 @@
// UB = UB + ST;
// }
//
+
const Expr *IVExpr = S.getIterationVariable();
const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
- RT.emitForInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, IL, LB,
- UB, ST, Chunk);
+ RT.emitForInit(
+ *this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, IL, LB,
+ (Dynamic ? EmitAnyExpr(S.getLastIteration()).getScalarVal() : UB), ST,
+ Chunk);
+
auto LoopExit = getJumpDestInCurrentScope("omp.dispatch.end");
// Start the loop with a block that tests the condition.
@@ -512,12 +618,17 @@
LoopStack.push(CondBlock);
llvm::Value *BoolCondVal = nullptr;
- // UB = min(UB, GlobalUB)
- EmitIgnoredExpr(S.getEnsureUpperBound());
- // IV = LB
- EmitIgnoredExpr(S.getInit());
- // IV < UB
- BoolCondVal = EvaluateExprAsBool(S.getCond(false));
+ if (!Dynamic) {
+ // UB = min(UB, GlobalUB)
+ EmitIgnoredExpr(S.getEnsureUpperBound());
+ // IV = LB
+ EmitIgnoredExpr(S.getInit());
+ // IV < UB
+ BoolCondVal = EvaluateExprAsBool(S.getCond(false));
+ } else {
+ BoolCondVal = RT.emitForNext(*this, S.getLocStart(), IVSize, IVSigned,
+ IL, LB, UB, ST);
+ }
// If there are any cleanups between here and the loop-exit scope,
// create a block to stage a loop exit along.
@@ -533,17 +644,28 @@
}
EmitBlock(LoopBody);
+ // Emit "IV = LB" (in case of static schedule, we have already calculated new
+ // LB for loop condition and emitted it above).
+ if (Dynamic)
+ EmitIgnoredExpr(S.getInit());
+
// Create a block for the increment.
auto Continue = getJumpDestInCurrentScope("omp.dispatch.inc");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
- EmitOMPInnerLoop(S, LoopScope);
+ EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
+ S.getCond(/*SeparateIter=*/false), S.getInc(), [&S, this]() {
+ EmitOMPLoopBody(S);
+ EmitStopPoint(&S);
+ });
EmitBlock(Continue.getBlock());
BreakContinueStack.pop_back();
- // Emit "LB = LB + Stride", "UB = UB + Stride".
- EmitIgnoredExpr(S.getNextLowerBound());
- EmitIgnoredExpr(S.getNextUpperBound());
+ if (!Dynamic) {
+ // Emit "LB = LB + Stride", "UB = UB + Stride".
+ EmitIgnoredExpr(S.getNextLowerBound());
+ EmitIgnoredExpr(S.getNextUpperBound());
+ }
EmitBranch(CondBlock);
LoopStack.pop();
@@ -551,7 +673,9 @@
EmitBlock(LoopExit.getBlock());
// Tell the runtime we are done.
- RT.emitForFinish(*this, S.getLocStart(), ScheduleKind);
+ // FIXME: Also call fini for ordered loops with dynamic scheduling.
+ if (!Dynamic)
+ RT.emitForFinish(*this, S.getLocStart(), ScheduleKind);
}
/// \brief Emit a helper variable and return corresponding lvalue.
@@ -602,6 +726,7 @@
OMPPrivateScope LoopScope(*this);
EmitPrivateLoopCounters(*this, LoopScope, S.counters());
+ (void)LoopScope.Privatize();
// Detect the loop schedule kind and chunk.
auto ScheduleKind = OMPC_SCHEDULE_unknown;
@@ -632,7 +757,12 @@
// IV = LB;
EmitIgnoredExpr(S.getInit());
// while (idx <= UB) { BODY; ++idx; }
- EmitOMPInnerLoop(S, LoopScope);
+ EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
+ S.getCond(/*SeparateIter=*/false), S.getInc(),
+ [&S, this]() {
+ EmitOMPLoopBody(S);
+ EmitStopPoint(&S);
+ });
// Tell the runtime we are done.
RT.emitForFinish(*this, S.getLocStart(), ScheduleKind);
} else {
@@ -650,47 +780,161 @@
}
void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) {
- InlinedOpenMPRegionRAII Region(*this, S);
- RunCleanupsScope DirectiveScope(*this);
-
- CGDebugInfo *DI = getDebugInfo();
- if (DI)
- DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
+ InlinedOpenMPRegionScopeRAII Region(*this, S);
EmitOMPWorksharingLoop(S);
// Emit an implicit barrier at the end.
CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(),
/*IsExplicit*/ false);
- if (DI)
- DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
}
void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &) {
llvm_unreachable("CodeGen for 'omp for simd' is not supported yet.");
}
-void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &) {
- llvm_unreachable("CodeGen for 'omp sections' is not supported yet.");
+static LValue createSectionLVal(CodeGenFunction &CGF, QualType Ty,
+ const Twine &Name,
+ llvm::Value *Init = nullptr) {
+ auto LVal = CGF.MakeNaturalAlignAddrLValue(CGF.CreateMemTemp(Ty, Name), Ty);
+ if (Init)
+ CGF.EmitScalarInit(Init, LVal);
+ return LVal;
}
-void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &) {
- llvm_unreachable("CodeGen for 'omp section' is not supported yet.");
+void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) {
+ InlinedOpenMPRegionScopeRAII Region(*this, S);
+
+ auto *Stmt = cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt();
+ auto *CS = dyn_cast<CompoundStmt>(Stmt);
+ if (CS && CS->size() > 1) {
+ auto &C = CGM.getContext();
+ auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
+ // Emit helper vars inits.
+ LValue LB = createSectionLVal(*this, KmpInt32Ty, ".omp.sections.lb.",
+ Builder.getInt32(0));
+ auto *GlobalUBVal = Builder.getInt32(CS->size() - 1);
+ LValue UB =
+ createSectionLVal(*this, KmpInt32Ty, ".omp.sections.ub.", GlobalUBVal);
+ LValue ST = createSectionLVal(*this, KmpInt32Ty, ".omp.sections.st.",
+ Builder.getInt32(1));
+ LValue IL = createSectionLVal(*this, KmpInt32Ty, ".omp.sections.il.",
+ Builder.getInt32(0));
+ // Loop counter.
+ LValue IV = createSectionLVal(*this, KmpInt32Ty, ".omp.sections.iv.");
+ OpaqueValueExpr IVRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue);
+ OpaqueValueMapping OpaqueIV(*this, &IVRefExpr, IV);
+ OpaqueValueExpr UBRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue);
+ OpaqueValueMapping OpaqueUB(*this, &UBRefExpr, UB);
+ // Generate condition for loop.
+ BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue,
+ OK_Ordinary, S.getLocStart(), /*fpContractable=*/false);
+ // Increment for loop counter.
+ UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
+ S.getLocStart());
+ auto BodyGen = [this, CS, &S, &IV]() {
+ // Iterate through all sections and emit a switch construct:
+ // switch (IV) {
+ // case 0:
+ // <SectionStmt[0]>;
+ // break;
+ // ...
+ // case <NumSection> - 1:
+ // <SectionStmt[<NumSection> - 1]>;
+ // break;
+ // }
+ // .omp.sections.exit:
+ auto *ExitBB = createBasicBlock(".omp.sections.exit");
+ auto *SwitchStmt = Builder.CreateSwitch(
+ EmitLoadOfLValue(IV, S.getLocStart()).getScalarVal(), ExitBB,
+ CS->size());
+ unsigned CaseNumber = 0;
+ for (auto C = CS->children(); C; ++C, ++CaseNumber) {
+ auto CaseBB = createBasicBlock(".omp.sections.case");
+ EmitBlock(CaseBB);
+ SwitchStmt->addCase(Builder.getInt32(CaseNumber), CaseBB);
+ EmitStmt(*C);
+ EmitBranch(ExitBB);
+ }
+ EmitBlock(ExitBB, /*IsFinished=*/true);
+ };
+ // Emit static non-chunked loop.
+ CGM.getOpenMPRuntime().emitForInit(
+ *this, S.getLocStart(), OMPC_SCHEDULE_static, /*IVSize=*/32,
+ /*IVSigned=*/true, IL.getAddress(), LB.getAddress(), UB.getAddress(),
+ ST.getAddress());
+ // UB = min(UB, GlobalUB);
+ auto *UBVal = EmitLoadOfScalar(UB, S.getLocStart());
+ auto *MinUBGlobalUB = Builder.CreateSelect(
+ Builder.CreateICmpSLT(UBVal, GlobalUBVal), UBVal, GlobalUBVal);
+ EmitStoreOfScalar(MinUBGlobalUB, UB);
+ // IV = LB;
+ EmitStoreOfScalar(EmitLoadOfScalar(LB, S.getLocStart()), IV);
+ // while (idx <= UB) { BODY; ++idx; }
+ EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen);
+ // Tell the runtime we are done.
+ CGM.getOpenMPRuntime().emitForFinish(*this, S.getLocStart(),
+ OMPC_SCHEDULE_static);
+ } else {
+ // If only one section is found - no need to generate loop, emit as a single
+ // region.
+ CGM.getOpenMPRuntime().emitSingleRegion(*this, [&]() -> void {
+ InlinedOpenMPRegionScopeRAII Region(*this, S);
+ EmitStmt(Stmt);
+ EnsureInsertPoint();
+ }, S.getLocStart(), llvm::None, llvm::None, llvm::None, llvm::None);
+ }
+
+ // Emit an implicit barrier at the end.
+ if (!S.getSingleClause(OMPC_nowait))
+ CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(),
+ /*IsExplicit=*/false);
+}
+
+void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &S) {
+ InlinedOpenMPRegionScopeRAII Region(*this, S);
+ EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ EnsureInsertPoint();
}
void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) {
+ llvm::SmallVector<const Expr *, 8> CopyprivateVars;
+ llvm::SmallVector<const Expr *, 8> SrcExprs;
+ llvm::SmallVector<const Expr *, 8> DstExprs;
+ llvm::SmallVector<const Expr *, 8> AssignmentOps;
+ // Check if there are any 'copyprivate' clauses associated with this 'single'
+ // construct.
+ auto CopyprivateFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_copyprivate;
+ };
+ // Build a list of copyprivate variables along with helper expressions
+ // (<source>, <destination>, <destination>=<source> expressions)
+ typedef OMPExecutableDirective::filtered_clause_iterator<decltype(
+ CopyprivateFilter)> CopyprivateIter;
+ for (CopyprivateIter I(S.clauses(), CopyprivateFilter); I; ++I) {
+ auto *C = cast<OMPCopyprivateClause>(*I);
+ CopyprivateVars.append(C->varlists().begin(), C->varlists().end());
+ SrcExprs.append(C->source_exprs().begin(), C->source_exprs().end());
+ DstExprs.append(C->destination_exprs().begin(),
+ C->destination_exprs().end());
+ AssignmentOps.append(C->assignment_ops().begin(),
+ C->assignment_ops().end());
+ }
+ // Emit code for 'single' region along with 'copyprivate' clauses
CGM.getOpenMPRuntime().emitSingleRegion(*this, [&]() -> void {
- InlinedOpenMPRegionRAII Region(*this, S);
- RunCleanupsScope Scope(*this);
+ InlinedOpenMPRegionScopeRAII Region(*this, S);
EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
EnsureInsertPoint();
- }, S.getLocStart());
+ }, S.getLocStart(), CopyprivateVars, SrcExprs, DstExprs, AssignmentOps);
+ // Emit an implicit barrier at the end.
+ if (!S.getSingleClause(OMPC_nowait))
+ CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(),
+ /*IsExplicit=*/false);
}
void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
CGM.getOpenMPRuntime().emitMasterRegion(*this, [&]() -> void {
- InlinedOpenMPRegionRAII Region(*this, S);
- RunCleanupsScope Scope(*this);
+ InlinedOpenMPRegionScopeRAII Region(*this, S);
EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
EnsureInsertPoint();
}, S.getLocStart());
@@ -699,8 +943,7 @@
void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) {
CGM.getOpenMPRuntime().emitCriticalRegion(
*this, S.getDirectiveName().getAsString(), [&]() -> void {
- InlinedOpenMPRegionRAII Region(*this, S);
- RunCleanupsScope Scope(*this);
+ InlinedOpenMPRegionScopeRAII Region(*this, S);
EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
EnsureInsertPoint();
}, S.getLocStart());
@@ -721,8 +964,35 @@
llvm_unreachable("CodeGen for 'omp parallel sections' is not supported yet.");
}
-void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &) {
- llvm_unreachable("CodeGen for 'omp task' is not supported yet.");
+void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &S) {
+ // Emit outlined function for task construct.
+ auto CS = cast<CapturedStmt>(S.getAssociatedStmt());
+ auto CapturedStruct = GenerateCapturedStmtArgument(*CS);
+ auto *I = CS->getCapturedDecl()->param_begin();
+ // The first function argument for tasks is a thread id, the second one is a
+ // part id (0 for tied tasks, >=0 for untied task).
+ auto OutlinedFn =
+ CGM.getOpenMPRuntime().emitTaskOutlinedFunction(S, *I, *std::next(I));
+ // Check if we should emit tied or untied task.
+ bool Tied = !S.getSingleClause(OMPC_untied);
+ // Check if the task is final
+ llvm::PointerIntPair<llvm::Value *, 1, bool> Final;
+ if (auto *Clause = S.getSingleClause(OMPC_final)) {
+ // If the condition constant folds and can be elided, try to avoid emitting
+ // the condition and the dead arm of the if/else.
+ auto *Cond = cast<OMPFinalClause>(Clause)->getCondition();
+ bool CondConstant;
+ if (ConstantFoldsToSimpleInteger(Cond, CondConstant))
+ Final.setInt(CondConstant);
+ else
+ Final.setPointer(EvaluateExprAsBool(Cond));
+ } else {
+ // By default the task is not final.
+ Final.setInt(/*IntVal=*/false);
+ }
+ auto SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl());
+ CGM.getOpenMPRuntime().emitTaskCall(*this, S.getLocStart(), Tied, Final,
+ OutlinedFn, SharedsTy, CapturedStruct);
}
void CodeGenFunction::EmitOMPTaskyieldDirective(
@@ -801,7 +1071,8 @@
? CGF.EmitLoadOfLValue(XLValue, Loc)
: CGF.EmitAtomicLoad(XLValue, Loc,
IsSeqCst ? llvm::SequentiallyConsistent
- : llvm::Monotonic);
+ : llvm::Monotonic,
+ XLValue.isVolatile());
// OpenMP, 2.12.6, atomic Construct
// Any atomic construct with a seq_cst clause forces the atomically
// performed operation to include an implicit flush operation without a
@@ -823,14 +1094,38 @@
}
}
+static void EmitOMPAtomicWriteExpr(CodeGenFunction &CGF, bool IsSeqCst,
+ const Expr *X, const Expr *E,
+ SourceLocation Loc) {
+ // x = expr;
+ assert(X->isLValue() && "X of 'omp atomic write' is not lvalue");
+ LValue XLValue = CGF.EmitLValue(X);
+ RValue ExprRValue = CGF.EmitAnyExpr(E);
+ if (XLValue.isGlobalReg())
+ CGF.EmitStoreThroughGlobalRegLValue(ExprRValue, XLValue);
+ else
+ CGF.EmitAtomicStore(ExprRValue, XLValue,
+ IsSeqCst ? llvm::SequentiallyConsistent
+ : llvm::Monotonic,
+ XLValue.isVolatile(), /*IsInit=*/false);
+ // OpenMP, 2.12.6, atomic Construct
+ // Any atomic construct with a seq_cst clause forces the atomically
+ // performed operation to include an implicit flush operation without a
+ // list.
+ if (IsSeqCst)
+ CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
+}
+
static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
bool IsSeqCst, const Expr *X, const Expr *V,
- const Expr *, SourceLocation Loc) {
+ const Expr *E, SourceLocation Loc) {
switch (Kind) {
case OMPC_read:
EmitOMPAtomicReadExpr(CGF, IsSeqCst, X, V, Loc);
break;
case OMPC_write:
+ EmitOMPAtomicWriteExpr(CGF, IsSeqCst, X, E, Loc);
+ break;
case OMPC_update:
case OMPC_capture:
llvm_unreachable("CodeGen for 'omp atomic clause' is not supported yet.");
@@ -873,6 +1168,13 @@
break;
}
}
+
+ const auto *CS =
+ S.getAssociatedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
+ if (const auto *EWC = dyn_cast<ExprWithCleanups>(CS))
+ enterFullExpression(EWC);
+ InlinedOpenMPRegionScopeRAII Region(*this, S);
+
EmitOMPAtomicExpr(*this, Kind, IsSeqCst, S.getX(), S.getV(), S.getExpr(),
S.getLocStart());
}
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 2e8471e..372db7a 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -743,7 +743,7 @@
return DiscardableODRLinkage;
case TSK_ExplicitInstantiationDeclaration:
- llvm_unreachable("Should not have been asked to emit this");
+ return llvm::GlobalVariable::ExternalLinkage;
case TSK_ExplicitInstantiationDefinition:
return NonDiscardableODRLinkage;
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 7d510d6..9e80f0a 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -802,20 +802,6 @@
F->setDoesNotThrow();
}
-static void EmitSizedDeallocationFunction(CodeGenFunction &CGF,
- const FunctionDecl *UnsizedDealloc) {
- // This is a weak discardable definition of the sized deallocation function.
- CGF.CurFn->setLinkage(llvm::Function::LinkOnceAnyLinkage);
- if (CGF.CGM.supportsCOMDAT())
- CGF.CurFn->setComdat(
- CGF.CGM.getModule().getOrInsertComdat(CGF.CurFn->getName()));
-
- // Call the unsized deallocation function and forward the first argument
- // unchanged.
- llvm::Constant *Unsized = CGF.CGM.GetAddrOfFunction(UnsizedDealloc);
- CGF.Builder.CreateCall(Unsized, &*CGF.CurFn->arg_begin());
-}
-
void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const CGFunctionInfo &FnInfo) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
@@ -870,7 +856,7 @@
else if (isa<CXXConstructorDecl>(FD))
EmitConstructorBody(Args);
else if (getLangOpts().CUDA &&
- !CGM.getCodeGenOpts().CUDAIsDevice &&
+ !getLangOpts().CUDAIsDevice &&
FD->hasAttr<CUDAGlobalAttr>())
CGM.getCUDARuntime().EmitDeviceStubBody(*this, Args);
else if (isa<CXXConversionDecl>(FD) &&
@@ -891,14 +877,6 @@
emitImplicitAssignmentOperatorBody(Args);
} else if (Stmt *Body = FD->getBody()) {
EmitFunctionBody(Args, Body);
- } else if (FunctionDecl *UnsizedDealloc =
- FD->getCorrespondingUnsizedGlobalDeallocationFunction()) {
- // Global sized deallocation functions get an implicit weak definition if
- // they don't have an explicit definition, if allowed.
- assert(getLangOpts().DefineSizedDeallocation &&
- "Can't emit unallowed definition.");
- EmitSizedDeallocationFunction(*this, UnsizedDealloc);
-
} else
llvm_unreachable("no definition for emitted function");
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index c0368aa..151eb7e 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -368,84 +368,26 @@
/// pushFullExprCleanup - Push a cleanup to be run at the end of the
/// current full-expression. Safe against the possibility that
/// we're currently inside a conditionally-evaluated expression.
- template <class T, class A0>
- void pushFullExprCleanup(CleanupKind kind, A0 a0) {
+ template <class T, class... As>
+ void pushFullExprCleanup(CleanupKind kind, As... A) {
// If we're not in a conditional branch, or if none of the
// arguments requires saving, then use the unconditional cleanup.
if (!isInConditionalBranch())
- return EHStack.pushCleanup<T>(kind, a0);
+ return EHStack.pushCleanup<T>(kind, A...);
- typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
+ // Stash values in a tuple so we can guarantee the order of saves.
+ typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple;
+ SavedTuple Saved{saveValueInCond(A)...};
- typedef EHScopeStack::ConditionalCleanup1<T, A0> CleanupType;
- EHStack.pushCleanup<CleanupType>(kind, a0_saved);
- initFullExprCleanup();
- }
-
- /// pushFullExprCleanup - Push a cleanup to be run at the end of the
- /// current full-expression. Safe against the possibility that
- /// we're currently inside a conditionally-evaluated expression.
- template <class T, class A0, class A1>
- void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1) {
- // If we're not in a conditional branch, or if none of the
- // arguments requires saving, then use the unconditional cleanup.
- if (!isInConditionalBranch())
- return EHStack.pushCleanup<T>(kind, a0, a1);
-
- typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
- typename DominatingValue<A1>::saved_type a1_saved = saveValueInCond(a1);
-
- typedef EHScopeStack::ConditionalCleanup2<T, A0, A1> CleanupType;
- EHStack.pushCleanup<CleanupType>(kind, a0_saved, a1_saved);
- initFullExprCleanup();
- }
-
- /// pushFullExprCleanup - Push a cleanup to be run at the end of the
- /// current full-expression. Safe against the possibility that
- /// we're currently inside a conditionally-evaluated expression.
- template <class T, class A0, class A1, class A2>
- void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1, A2 a2) {
- // If we're not in a conditional branch, or if none of the
- // arguments requires saving, then use the unconditional cleanup.
- if (!isInConditionalBranch()) {
- return EHStack.pushCleanup<T>(kind, a0, a1, a2);
- }
-
- typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
- typename DominatingValue<A1>::saved_type a1_saved = saveValueInCond(a1);
- typename DominatingValue<A2>::saved_type a2_saved = saveValueInCond(a2);
-
- typedef EHScopeStack::ConditionalCleanup3<T, A0, A1, A2> CleanupType;
- EHStack.pushCleanup<CleanupType>(kind, a0_saved, a1_saved, a2_saved);
- initFullExprCleanup();
- }
-
- /// pushFullExprCleanup - Push a cleanup to be run at the end of the
- /// current full-expression. Safe against the possibility that
- /// we're currently inside a conditionally-evaluated expression.
- template <class T, class A0, class A1, class A2, class A3>
- void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1, A2 a2, A3 a3) {
- // If we're not in a conditional branch, or if none of the
- // arguments requires saving, then use the unconditional cleanup.
- if (!isInConditionalBranch()) {
- return EHStack.pushCleanup<T>(kind, a0, a1, a2, a3);
- }
-
- typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
- typename DominatingValue<A1>::saved_type a1_saved = saveValueInCond(a1);
- typename DominatingValue<A2>::saved_type a2_saved = saveValueInCond(a2);
- typename DominatingValue<A3>::saved_type a3_saved = saveValueInCond(a3);
-
- typedef EHScopeStack::ConditionalCleanup4<T, A0, A1, A2, A3> CleanupType;
- EHStack.pushCleanup<CleanupType>(kind, a0_saved, a1_saved,
- a2_saved, a3_saved);
+ typedef EHScopeStack::ConditionalCleanup<T, As...> CleanupType;
+ EHStack.pushCleanupTuple<CleanupType>(kind, Saved);
initFullExprCleanup();
}
/// \brief Queue a cleanup to be pushed after finishing the current
/// full-expression.
- template <class T, class A0, class A1, class A2, class A3>
- void pushCleanupAfterFullExpr(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) {
+ template <class T, class... As>
+ void pushCleanupAfterFullExpr(CleanupKind Kind, As... A) {
assert(!isInConditionalBranch() && "can't defer conditional cleanup");
LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind };
@@ -456,7 +398,7 @@
char *Buffer = &LifetimeExtendedCleanupStack[OldSize];
new (Buffer) LifetimeExtendedCleanupHeader(Header);
- new (Buffer + sizeof(Header)) T(a0, a1, a2, a3);
+ new (Buffer + sizeof(Header)) T(A...);
}
/// Set up the last cleaup that was pushed as a conditional
@@ -662,7 +604,10 @@
}
/// \brief Exit scope - all the mapped variables are restored.
- ~OMPPrivateScope() { ForceCleanup(); }
+ ~OMPPrivateScope() {
+ if (PerformCleanup)
+ ForceCleanup();
+ }
};
/// \brief Takes the old cleanup stack size and emits the cleanup blocks
@@ -1346,10 +1291,20 @@
/// to by This.
llvm::Value *GetVTablePtr(llvm::Value *This, llvm::Type *Ty);
+ /// \brief Derived is the presumed address of an object of type T after a
+ /// cast. If T is a polymorphic class type, emit a check that the virtual
+ /// table for Derived belongs to a class derived from T.
+ void EmitVTablePtrCheckForCast(QualType T, llvm::Value *Derived,
+ bool MayBeNull);
+
/// EmitVTablePtrCheckForCall - Virtual method MD is being called via VTable.
/// If vptr CFI is enabled, emit a check that VTable is valid.
void EmitVTablePtrCheckForCall(const CXXMethodDecl *MD, llvm::Value *VTable);
+ /// EmitVTablePtrCheck - Emit a check that VTable is a valid virtual table for
+ /// RD using llvm.bitset.test.
+ void EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *VTable);
+
/// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
/// expr can be devirtualized.
bool CanDevirtualizeMemberFunctionCall(const Expr *Base,
@@ -1567,6 +1522,8 @@
void EmitAnyExprToMem(const Expr *E, llvm::Value *Location,
Qualifiers Quals, bool IsInitializer);
+ void EmitAnyExprToExn(const Expr *E, llvm::Value *Addr);
+
/// EmitExprAsInit - Emits the code necessary to initialize a
/// location in memory with the given initializer.
void EmitExprAsInit(const Expr *init, const ValueDecl *D, LValue lvalue,
@@ -2092,8 +2049,9 @@
/// Helpers for the OpenMP loop directives.
void EmitOMPLoopBody(const OMPLoopDirective &Directive,
bool SeparateIter = false);
- void EmitOMPInnerLoop(const OMPLoopDirective &S, OMPPrivateScope &LoopScope,
- bool SeparateIter = false);
+ void EmitOMPInnerLoop(const Stmt &S, bool RequiresCleanup,
+ const Expr *LoopCond, const Expr *IncExpr,
+ const std::function<void()> &BodyGen);
void EmitOMPSimdFinal(const OMPLoopDirective &S);
void EmitOMPWorksharingLoop(const OMPLoopDirective &S);
void EmitOMPForOuterLoop(OpenMPScheduleClauseKind ScheduleKind,
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 1b6439b..f4ae684 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -323,6 +323,8 @@
void CodeGenModule::clear() {
DeferredDeclsToEmit.clear();
+ if (OpenMPRuntime)
+ OpenMPRuntime->clear();
}
void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags,
@@ -1338,7 +1340,7 @@
// If this is CUDA, be selective about which declarations we emit.
if (LangOpts.CUDA) {
- if (CodeGenOpts.CUDAIsDevice) {
+ if (LangOpts.CUDAIsDevice) {
if (!Global->hasAttr<CUDADeviceAttr>() &&
!Global->hasAttr<CUDAGlobalAttr>() &&
!Global->hasAttr<CUDAConstantAttr>() &&
@@ -1618,16 +1620,6 @@
// don't need it anymore).
addDeferredDeclToEmit(F, DDI->second);
DeferredDecls.erase(DDI);
-
- // Otherwise, if this is a sized deallocation function, emit a weak
- // definition for it at the end of the translation unit (if allowed),
- // unless the sized deallocation function is aliased.
- } else if (D &&
- cast<FunctionDecl>(D)
- ->getCorrespondingUnsizedGlobalDeallocationFunction() &&
- getLangOpts().DefineSizedDeallocation &&
- !D->hasAttr<AliasAttr>()) {
- addDeferredDeclToEmit(F, GD);
// Otherwise, there are cases we have to worry about where we're
// using a declaration for which we must emit a definition but where
@@ -1849,7 +1841,8 @@
OldGV->eraseFromParent();
}
- if (supportsCOMDAT() && GV->isWeakForLinker())
+ if (supportsCOMDAT() && GV->isWeakForLinker() &&
+ !GV->hasAvailableExternallyLinkage())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
return GV;
@@ -1906,7 +1899,7 @@
unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D,
unsigned AddrSpace) {
- if (LangOpts.CUDA && CodeGenOpts.CUDAIsDevice) {
+ if (LangOpts.CUDA && LangOpts.CUDAIsDevice) {
if (D->hasAttr<CUDAConstantAttr>())
AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_constant);
else if (D->hasAttr<CUDASharedAttr>())
@@ -3360,15 +3353,7 @@
case Decl::FileScopeAsm: {
auto *AD = cast<FileScopeAsmDecl>(D);
- StringRef AsmString = AD->getAsmString()->getString();
-
- const std::string &S = getModule().getModuleInlineAsm();
- if (S.empty())
- getModule().setModuleInlineAsm(AsmString);
- else if (S.end()[-1] == '\n')
- getModule().setModuleInlineAsm(S + AsmString.str());
- else
- getModule().setModuleInlineAsm(S + '\n' + AsmString.str());
+ getModule().appendModuleInlineAsm(AD->getAsmString()->getString());
break;
}
@@ -3652,6 +3637,12 @@
return llvm::ConstantStruct::getAnon(Fields);
}
+llvm::Constant *
+CodeGenModule::getAddrOfCXXHandlerMapEntry(QualType Ty,
+ QualType CatchHandlerType) {
+ return getCXXABI().getAddrOfCXXHandlerMapEntry(Ty, CatchHandlerType);
+}
+
llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
bool ForEH) {
// Return a bogus pointer if RTTI is disabled, unless it's for EH.
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 6902d19..ce540e9 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -719,6 +719,9 @@
/// Get the address of the RTTI descriptor for the given type.
llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
+ llvm::Constant *getAddrOfCXXHandlerMapEntry(QualType Ty,
+ QualType CatchHandlerType);
+
/// Get the address of a uuid descriptor .
llvm::Constant *GetAddrOfUuidDescriptor(const CXXUuidofExpr* E);
@@ -1108,6 +1111,9 @@
void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout);
+ /// \breif Get the declaration of std::terminate for the platform.
+ llvm::Constant *getTerminateFn();
+
private:
llvm::Constant *
GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp
index a88335d..557828d 100644
--- a/lib/CodeGen/CodeGenPGO.cpp
+++ b/lib/CodeGen/CodeGenPGO.cpp
@@ -58,12 +58,16 @@
}
void CodeGenPGO::createFuncNameVar(llvm::GlobalValue::LinkageTypes Linkage) {
- // Usually, we want to match the function's linkage, but
- // available_externally and extern_weak both have the wrong semantics.
+ // We generally want to match the function's linkage, but available_externally
+ // and extern_weak both have the wrong semantics, and anything that doesn't
+ // need to link across compilation units doesn't need to be visible at all.
if (Linkage == llvm::GlobalValue::ExternalWeakLinkage)
Linkage = llvm::GlobalValue::LinkOnceAnyLinkage;
else if (Linkage == llvm::GlobalValue::AvailableExternallyLinkage)
Linkage = llvm::GlobalValue::LinkOnceODRLinkage;
+ else if (Linkage == llvm::GlobalValue::InternalLinkage ||
+ Linkage == llvm::GlobalValue::ExternalLinkage)
+ Linkage = llvm::GlobalValue::PrivateLinkage;
auto *Value =
llvm::ConstantDataArray::getString(CGM.getLLVMContext(), FuncName, false);
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 64c5799..26d37f3 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -82,6 +82,9 @@
return StructorType::Base;
case Ctor_Comdat:
llvm_unreachable("not expecting a COMDAT");
+ case Ctor_CopyingClosure:
+ case Ctor_DefaultClosure:
+ llvm_unreachable("not expecting a closure");
}
llvm_unreachable("not a CXXCtorType");
}
@@ -261,6 +264,8 @@
const FunctionProtoType *type,
RequiredArgs required);
const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD);
+ const CGFunctionInfo &arrangeMSCtorClosure(const CXXConstructorDecl *CD,
+ CXXCtorType CT);
const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty);
const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionNoProtoType> Ty);
diff --git a/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp
index 55e7334..07db6c7 100644
--- a/lib/CodeGen/CoverageMappingGen.cpp
+++ b/lib/CodeGen/CoverageMappingGen.cpp
@@ -124,7 +124,7 @@
SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
if (Loc.isMacroID())
return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) -
- SM.getFileOffset(Loc) - 1);
+ SM.getFileOffset(Loc));
return SM.getLocForEndOfFile(SM.getFileID(Loc));
}
@@ -147,7 +147,7 @@
SourceLocation Loc = S->getLocEnd();
while (SM.isMacroArgExpansion(Loc))
Loc = SM.getImmediateExpansionRange(Loc).first;
- return Loc;
+ return getPreciseTokenLocEnd(Loc);
}
/// \brief Find the set of files we have regions for and assign IDs
@@ -257,7 +257,7 @@
if (!CovFileID)
continue;
- SourceLocation LocEnd = getPreciseTokenLocEnd(Region.getEndLoc());
+ SourceLocation LocEnd = Region.getEndLoc();
assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
"region spans multiple files");
@@ -407,7 +407,7 @@
SourceRegions.emplace_back(Region.getCounter(), NestedLoc, EndLoc);
- EndLoc = getIncludeOrExpansionLoc(EndLoc);
+ EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
assert(!EndLoc.isInvalid() &&
"File exit was not handled before popRegions");
}
diff --git a/lib/CodeGen/EHScopeStack.h b/lib/CodeGen/EHScopeStack.h
index 6535b76..363d8b8 100644
--- a/lib/CodeGen/EHScopeStack.h
+++ b/lib/CodeGen/EHScopeStack.h
@@ -17,6 +17,7 @@
#define LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Instructions.h"
@@ -181,84 +182,28 @@
virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0;
};
- /// ConditionalCleanupN stores the saved form of its N parameters,
+ /// ConditionalCleanup stores the saved form of its parameters,
/// then restores them and performs the cleanup.
- template <class T, class A0>
- class ConditionalCleanup1 : public Cleanup {
- typedef typename DominatingValue<A0>::saved_type A0_saved;
- A0_saved a0_saved;
+ template <class T, class... As> class ConditionalCleanup : public Cleanup {
+ typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple;
+ SavedTuple Saved;
+
+ template <std::size_t... Is>
+ T restore(CodeGenFunction &CGF, llvm::index_sequence<Is...>) {
+ // It's important that the restores are emitted in order. The braced init
+ // list guarentees that.
+ return T{DominatingValue<As>::restore(CGF, std::get<Is>(Saved))...};
+ }
void Emit(CodeGenFunction &CGF, Flags flags) override {
- A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
- T(a0).Emit(CGF, flags);
+ restore(CGF, llvm::index_sequence_for<As...>()).Emit(CGF, flags);
}
public:
- ConditionalCleanup1(A0_saved a0)
- : a0_saved(a0) {}
- };
+ ConditionalCleanup(typename DominatingValue<As>::saved_type... A)
+ : Saved(A...) {}
- template <class T, class A0, class A1>
- class ConditionalCleanup2 : public Cleanup {
- typedef typename DominatingValue<A0>::saved_type A0_saved;
- typedef typename DominatingValue<A1>::saved_type A1_saved;
- A0_saved a0_saved;
- A1_saved a1_saved;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
- A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
- T(a0, a1).Emit(CGF, flags);
- }
-
- public:
- ConditionalCleanup2(A0_saved a0, A1_saved a1)
- : a0_saved(a0), a1_saved(a1) {}
- };
-
- template <class T, class A0, class A1, class A2>
- class ConditionalCleanup3 : public Cleanup {
- typedef typename DominatingValue<A0>::saved_type A0_saved;
- typedef typename DominatingValue<A1>::saved_type A1_saved;
- typedef typename DominatingValue<A2>::saved_type A2_saved;
- A0_saved a0_saved;
- A1_saved a1_saved;
- A2_saved a2_saved;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
- A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
- A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
- T(a0, a1, a2).Emit(CGF, flags);
- }
-
- public:
- ConditionalCleanup3(A0_saved a0, A1_saved a1, A2_saved a2)
- : a0_saved(a0), a1_saved(a1), a2_saved(a2) {}
- };
-
- template <class T, class A0, class A1, class A2, class A3>
- class ConditionalCleanup4 : public Cleanup {
- typedef typename DominatingValue<A0>::saved_type A0_saved;
- typedef typename DominatingValue<A1>::saved_type A1_saved;
- typedef typename DominatingValue<A2>::saved_type A2_saved;
- typedef typename DominatingValue<A3>::saved_type A3_saved;
- A0_saved a0_saved;
- A1_saved a1_saved;
- A2_saved a2_saved;
- A3_saved a3_saved;
-
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
- A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
- A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
- A3 a3 = DominatingValue<A3>::restore(CGF, a3_saved);
- T(a0, a1, a2, a3).Emit(CGF, flags);
- }
-
- public:
- ConditionalCleanup4(A0_saved a0, A1_saved a1, A2_saved a2, A3_saved a3)
- : a0_saved(a0), a1_saved(a1), a2_saved(a2), a3_saved(a3) {}
+ ConditionalCleanup(SavedTuple Tuple) : Saved(std::move(Tuple)) {}
};
private:
@@ -319,6 +264,14 @@
(void) Obj;
}
+ /// Push a lazily-created cleanup on the stack. Tuple version.
+ template <class T, class... As>
+ void pushCleanupTuple(CleanupKind Kind, std::tuple<As...> A) {
+ void *Buffer = pushCleanup(Kind, sizeof(T));
+ Cleanup *Obj = new (Buffer) T(std::move(A));
+ (void) Obj;
+ }
+
// Feel free to add more variants of the following:
/// Push a cleanup with non-constant storage requirements on the
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index e580969..f23cd9f 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -19,14 +19,18 @@
//===----------------------------------------------------------------------===//
#include "CGCXXABI.h"
+#include "CGCleanup.h"
#include "CGRecordLayout.h"
#include "CGVTables.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "TargetInfo.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/Type.h"
+#include "clang/AST/StmtCXX.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Value.h"
@@ -111,10 +115,21 @@
const CXXDestructorDecl *Dtor) override;
void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;
+ void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) override;
+
+ void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) override;
+
+ llvm::CallInst *
+ emitTerminateForUnexpectedException(CodeGenFunction &CGF,
+ llvm::Value *Exn) override;
void EmitFundamentalRTTIDescriptor(QualType Type);
void EmitFundamentalRTTIDescriptors();
llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
+ llvm::Constant *
+ getAddrOfCXXHandlerMapEntry(QualType Ty, QualType CatchHandlerType) override {
+ return getAddrOfRTTIDescriptor(Ty);
+ }
bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
void EmitBadTypeidCall(CodeGenFunction &CGF) override;
@@ -906,6 +921,59 @@
CGF.EmitRuntimeCallOrInvoke(Fn);
}
+static llvm::Constant *getAllocateExceptionFn(CodeGenModule &CGM) {
+ // void *__cxa_allocate_exception(size_t thrown_size);
+
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.Int8PtrTy, CGM.SizeTy, /*IsVarArgs=*/false);
+
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
+}
+
+static llvm::Constant *getThrowFn(CodeGenModule &CGM) {
+ // void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
+ // void (*dest) (void *));
+
+ llvm::Type *Args[3] = { CGM.Int8PtrTy, CGM.Int8PtrTy, CGM.Int8PtrTy };
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, Args, /*IsVarArgs=*/false);
+
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
+}
+
+void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) {
+ QualType ThrowType = E->getSubExpr()->getType();
+ // Now allocate the exception object.
+ llvm::Type *SizeTy = CGF.ConvertType(getContext().getSizeType());
+ uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity();
+
+ llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(CGM);
+ llvm::CallInst *ExceptionPtr = CGF.EmitNounwindRuntimeCall(
+ AllocExceptionFn, llvm::ConstantInt::get(SizeTy, TypeSize), "exception");
+
+ CGF.EmitAnyExprToExn(E->getSubExpr(), ExceptionPtr);
+
+ // Now throw the exception.
+ llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType,
+ /*ForEH=*/true);
+
+ // The address of the destructor. If the exception type has a
+ // trivial destructor (or isn't a record), we just pass null.
+ llvm::Constant *Dtor = nullptr;
+ if (const RecordType *RecordTy = ThrowType->getAs<RecordType>()) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!Record->hasTrivialDestructor()) {
+ CXXDestructorDecl *DtorD = Record->getDestructor();
+ Dtor = CGM.getAddrOfCXXStructor(DtorD, StructorType::Complete);
+ Dtor = llvm::ConstantExpr::getBitCast(Dtor, CGM.Int8PtrTy);
+ }
+ }
+ if (!Dtor) Dtor = llvm::Constant::getNullValue(CGM.Int8PtrTy);
+
+ llvm::Value *args[] = { ExceptionPtr, TypeInfo, Dtor };
+ CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(CGM), args);
+}
+
static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {
// void *__dynamic_cast(const void *sub,
// const abi::__class_type_info *src,
@@ -3220,3 +3288,348 @@
CGM.maybeSetTrivialComdat(*MD, *Fn);
}
}
+
+static llvm::Constant *getBeginCatchFn(CodeGenModule &CGM) {
+ // void *__cxa_begin_catch(void*);
+ llvm::FunctionType *FTy = llvm::FunctionType::get(
+ CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
+
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
+}
+
+static llvm::Constant *getEndCatchFn(CodeGenModule &CGM) {
+ // void __cxa_end_catch();
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
+
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
+}
+
+static llvm::Constant *getGetExceptionPtrFn(CodeGenModule &CGM) {
+ // void *__cxa_get_exception_ptr(void*);
+ llvm::FunctionType *FTy = llvm::FunctionType::get(
+ CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
+
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
+}
+
+namespace {
+ /// A cleanup to call __cxa_end_catch. In many cases, the caught
+ /// exception type lets us state definitively that the thrown exception
+ /// type does not have a destructor. In particular:
+ /// - Catch-alls tell us nothing, so we have to conservatively
+ /// assume that the thrown exception might have a destructor.
+ /// - Catches by reference behave according to their base types.
+ /// - Catches of non-record types will only trigger for exceptions
+ /// of non-record types, which never have destructors.
+ /// - Catches of record types can trigger for arbitrary subclasses
+ /// of the caught type, so we have to assume the actual thrown
+ /// exception type might have a throwing destructor, even if the
+ /// caught type's destructor is trivial or nothrow.
+ struct CallEndCatch : EHScopeStack::Cleanup {
+ CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}
+ bool MightThrow;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
+ if (!MightThrow) {
+ CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
+ return;
+ }
+
+ CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM));
+ }
+ };
+}
+
+/// Emits a call to __cxa_begin_catch and enters a cleanup to call
+/// __cxa_end_catch.
+///
+/// \param EndMightThrow - true if __cxa_end_catch might throw
+static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
+ llvm::Value *Exn,
+ bool EndMightThrow) {
+ llvm::CallInst *call =
+ CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn);
+
+ CGF.EHStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup, EndMightThrow);
+
+ return call;
+}
+
+/// A "special initializer" callback for initializing a catch
+/// parameter during catch initialization.
+static void InitCatchParam(CodeGenFunction &CGF,
+ const VarDecl &CatchParam,
+ llvm::Value *ParamAddr,
+ SourceLocation Loc) {
+ // Load the exception from where the landing pad saved it.
+ llvm::Value *Exn = CGF.getExceptionFromSlot();
+
+ CanQualType CatchType =
+ CGF.CGM.getContext().getCanonicalType(CatchParam.getType());
+ llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType);
+
+ // If we're catching by reference, we can just cast the object
+ // pointer to the appropriate pointer.
+ if (isa<ReferenceType>(CatchType)) {
+ QualType CaughtType = cast<ReferenceType>(CatchType)->getPointeeType();
+ bool EndCatchMightThrow = CaughtType->isRecordType();
+
+ // __cxa_begin_catch returns the adjusted object pointer.
+ llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, EndCatchMightThrow);
+
+ // We have no way to tell the personality function that we're
+ // catching by reference, so if we're catching a pointer,
+ // __cxa_begin_catch will actually return that pointer by value.
+ if (const PointerType *PT = dyn_cast<PointerType>(CaughtType)) {
+ QualType PointeeType = PT->getPointeeType();
+
+ // When catching by reference, generally we should just ignore
+ // this by-value pointer and use the exception object instead.
+ if (!PointeeType->isRecordType()) {
+
+ // Exn points to the struct _Unwind_Exception header, which
+ // we have to skip past in order to reach the exception data.
+ unsigned HeaderSize =
+ CGF.CGM.getTargetCodeGenInfo().getSizeOfUnwindException();
+ AdjustedExn = CGF.Builder.CreateConstGEP1_32(Exn, HeaderSize);
+
+ // However, if we're catching a pointer-to-record type that won't
+ // work, because the personality function might have adjusted
+ // the pointer. There's actually no way for us to fully satisfy
+ // the language/ABI contract here: we can't use Exn because it
+ // might have the wrong adjustment, but we can't use the by-value
+ // pointer because it's off by a level of abstraction.
+ //
+ // The current solution is to dump the adjusted pointer into an
+ // alloca, which breaks language semantics (because changing the
+ // pointer doesn't change the exception) but at least works.
+ // The better solution would be to filter out non-exact matches
+ // and rethrow them, but this is tricky because the rethrow
+ // really needs to be catchable by other sites at this landing
+ // pad. The best solution is to fix the personality function.
+ } else {
+ // Pull the pointer for the reference type off.
+ llvm::Type *PtrTy =
+ cast<llvm::PointerType>(LLVMCatchTy)->getElementType();
+
+ // Create the temporary and write the adjusted pointer into it.
+ llvm::Value *ExnPtrTmp = CGF.CreateTempAlloca(PtrTy, "exn.byref.tmp");
+ llvm::Value *Casted = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
+ CGF.Builder.CreateStore(Casted, ExnPtrTmp);
+
+ // Bind the reference to the temporary.
+ AdjustedExn = ExnPtrTmp;
+ }
+ }
+
+ llvm::Value *ExnCast =
+ CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref");
+ CGF.Builder.CreateStore(ExnCast, ParamAddr);
+ return;
+ }
+
+ // Scalars and complexes.
+ TypeEvaluationKind TEK = CGF.getEvaluationKind(CatchType);
+ if (TEK != TEK_Aggregate) {
+ llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);
+
+ // If the catch type is a pointer type, __cxa_begin_catch returns
+ // the pointer by value.
+ if (CatchType->hasPointerRepresentation()) {
+ llvm::Value *CastExn =
+ CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.casted");
+
+ switch (CatchType.getQualifiers().getObjCLifetime()) {
+ case Qualifiers::OCL_Strong:
+ CastExn = CGF.EmitARCRetainNonBlock(CastExn);
+ // fallthrough
+
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ CGF.Builder.CreateStore(CastExn, ParamAddr);
+ return;
+
+ case Qualifiers::OCL_Weak:
+ CGF.EmitARCInitWeak(ParamAddr, CastExn);
+ return;
+ }
+ llvm_unreachable("bad ownership qualifier!");
+ }
+
+ // Otherwise, it returns a pointer into the exception object.
+
+ llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
+ llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
+
+ LValue srcLV = CGF.MakeNaturalAlignAddrLValue(Cast, CatchType);
+ LValue destLV = CGF.MakeAddrLValue(ParamAddr, CatchType,
+ CGF.getContext().getDeclAlign(&CatchParam));
+ switch (TEK) {
+ case TEK_Complex:
+ CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV, Loc), destLV,
+ /*init*/ true);
+ return;
+ case TEK_Scalar: {
+ llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV, Loc);
+ CGF.EmitStoreOfScalar(ExnLoad, destLV, /*init*/ true);
+ return;
+ }
+ case TEK_Aggregate:
+ llvm_unreachable("evaluation kind filtered out!");
+ }
+ llvm_unreachable("bad evaluation kind");
+ }
+
+ assert(isa<RecordType>(CatchType) && "unexpected catch type!");
+
+ llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
+
+ // Check for a copy expression. If we don't have a copy expression,
+ // that means a trivial copy is okay.
+ const Expr *copyExpr = CatchParam.getInit();
+ if (!copyExpr) {
+ llvm::Value *rawAdjustedExn = CallBeginCatch(CGF, Exn, true);
+ llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);
+ CGF.EmitAggregateCopy(ParamAddr, adjustedExn, CatchType);
+ return;
+ }
+
+ // We have to call __cxa_get_exception_ptr to get the adjusted
+ // pointer before copying.
+ llvm::CallInst *rawAdjustedExn =
+ CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn);
+
+ // Cast that to the appropriate type.
+ llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);
+
+ // The copy expression is defined in terms of an OpaqueValueExpr.
+ // Find it and map it to the adjusted expression.
+ CodeGenFunction::OpaqueValueMapping
+ opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr),
+ CGF.MakeAddrLValue(adjustedExn, CatchParam.getType()));
+
+ // Call the copy ctor in a terminate scope.
+ CGF.EHStack.pushTerminate();
+
+ // Perform the copy construction.
+ CharUnits Alignment = CGF.getContext().getDeclAlign(&CatchParam);
+ CGF.EmitAggExpr(copyExpr,
+ AggValueSlot::forAddr(ParamAddr, Alignment, Qualifiers(),
+ AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
+
+ // Leave the terminate scope.
+ CGF.EHStack.popTerminate();
+
+ // Undo the opaque value mapping.
+ opaque.pop();
+
+ // Finally we can call __cxa_begin_catch.
+ CallBeginCatch(CGF, Exn, true);
+}
+
+/// Begins a catch statement by initializing the catch variable and
+/// calling __cxa_begin_catch.
+void ItaniumCXXABI::emitBeginCatch(CodeGenFunction &CGF,
+ const CXXCatchStmt *S) {
+ // We have to be very careful with the ordering of cleanups here:
+ // C++ [except.throw]p4:
+ // The destruction [of the exception temporary] occurs
+ // immediately after the destruction of the object declared in
+ // the exception-declaration in the handler.
+ //
+ // So the precise ordering is:
+ // 1. Construct catch variable.
+ // 2. __cxa_begin_catch
+ // 3. Enter __cxa_end_catch cleanup
+ // 4. Enter dtor cleanup
+ //
+ // We do this by using a slightly abnormal initialization process.
+ // Delegation sequence:
+ // - ExitCXXTryStmt opens a RunCleanupsScope
+ // - EmitAutoVarAlloca creates the variable and debug info
+ // - InitCatchParam initializes the variable from the exception
+ // - CallBeginCatch calls __cxa_begin_catch
+ // - CallBeginCatch enters the __cxa_end_catch cleanup
+ // - EmitAutoVarCleanups enters the variable destructor cleanup
+ // - EmitCXXTryStmt emits the code for the catch body
+ // - EmitCXXTryStmt close the RunCleanupsScope
+
+ VarDecl *CatchParam = S->getExceptionDecl();
+ if (!CatchParam) {
+ llvm::Value *Exn = CGF.getExceptionFromSlot();
+ CallBeginCatch(CGF, Exn, true);
+ return;
+ }
+
+ // Emit the local.
+ CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam);
+ InitCatchParam(CGF, *CatchParam, var.getObjectAddress(CGF), S->getLocStart());
+ CGF.EmitAutoVarCleanups(var);
+}
+
+/// Get or define the following function:
+/// void @__clang_call_terminate(i8* %exn) nounwind noreturn
+/// This code is used only in C++.
+static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) {
+ llvm::FunctionType *fnTy =
+ llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::Constant *fnRef =
+ CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate");
+
+ llvm::Function *fn = dyn_cast<llvm::Function>(fnRef);
+ if (fn && fn->empty()) {
+ fn->setDoesNotThrow();
+ fn->setDoesNotReturn();
+
+ // What we really want is to massively penalize inlining without
+ // forbidding it completely. The difference between that and
+ // 'noinline' is negligible.
+ fn->addFnAttr(llvm::Attribute::NoInline);
+
+ // Allow this function to be shared across translation units, but
+ // we don't want it to turn into an exported symbol.
+ fn->setLinkage(llvm::Function::LinkOnceODRLinkage);
+ fn->setVisibility(llvm::Function::HiddenVisibility);
+ if (CGM.supportsCOMDAT())
+ fn->setComdat(CGM.getModule().getOrInsertComdat(fn->getName()));
+
+ // Set up the function.
+ llvm::BasicBlock *entry =
+ llvm::BasicBlock::Create(CGM.getLLVMContext(), "", fn);
+ CGBuilderTy builder(entry);
+
+ // Pull the exception pointer out of the parameter list.
+ llvm::Value *exn = &*fn->arg_begin();
+
+ // Call __cxa_begin_catch(exn).
+ llvm::CallInst *catchCall = builder.CreateCall(getBeginCatchFn(CGM), exn);
+ catchCall->setDoesNotThrow();
+ catchCall->setCallingConv(CGM.getRuntimeCC());
+
+ // Call std::terminate().
+ llvm::CallInst *termCall = builder.CreateCall(CGM.getTerminateFn());
+ termCall->setDoesNotThrow();
+ termCall->setDoesNotReturn();
+ termCall->setCallingConv(CGM.getRuntimeCC());
+
+ // std::terminate cannot return.
+ builder.CreateUnreachable();
+ }
+
+ return fnRef;
+}
+
+llvm::CallInst *
+ItaniumCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF,
+ llvm::Value *Exn) {
+ // In C++, we want to call __cxa_begin_catch() before terminating.
+ if (Exn) {
+ assert(CGF.CGM.getLangOpts().CPlusPlus);
+ return CGF.EmitNounwindRuntimeCall(getClangCallTerminateFn(CGF.CGM), Exn);
+ }
+ return CGF.EmitNounwindRuntimeCall(CGF.CGM.getTerminateFn());
+}
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 48adf3a..f8f7845 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -17,12 +17,16 @@
#include "CGCXXABI.h"
#include "CGVTables.h"
#include "CodeGenModule.h"
+#include "CodeGenTypes.h"
+#include "TargetInfo.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/StmtCXX.h"
#include "clang/AST/VTableBuilder.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/IR/CallSite.h"
+#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -40,7 +44,8 @@
MicrosoftCXXABI(CodeGenModule &CGM)
: CGCXXABI(CGM), BaseClassDescriptorType(nullptr),
ClassHierarchyDescriptorType(nullptr),
- CompleteObjectLocatorType(nullptr) {}
+ CompleteObjectLocatorType(nullptr), CatchableTypeType(nullptr),
+ ThrowInfoType(nullptr), HandlerMapEntryType(nullptr) {}
bool HasThisReturn(GlobalDecl GD) const override;
bool hasMostDerivedReturn(GlobalDecl GD) const override;
@@ -71,11 +76,16 @@
const CXXDestructorDecl *Dtor) override;
void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;
+ void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) override;
+
+ void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) override;
llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl *RD,
const VPtrInfo *Info);
llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
+ llvm::Constant *
+ getAddrOfCXXHandlerMapEntry(QualType Ty, QualType CatchHandlerType) override;
bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
void EmitBadTypeidCall(CodeGenFunction &CGF) override;
@@ -225,7 +235,7 @@
assert(GD.getDtorType() == Dtor_Deleting &&
"Only deleting destructor thunks are available in this ABI");
CallArgs.add(RValue::get(getStructorImplicitParamValue(CGF)),
- CGM.getContext().IntTy);
+ getContext().IntTy);
}
void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
@@ -410,6 +420,9 @@
if (!isImageRelative())
return PtrVal;
+ if (PtrVal->isNullValue())
+ return llvm::Constant::getNullValue(CGM.IntTy);
+
llvm::Constant *ImageBaseAsInt =
llvm::ConstantExpr::getPtrToInt(getImageBase(), CGM.IntPtrTy);
llvm::Constant *PtrValAsInt =
@@ -467,6 +480,10 @@
return GetVBaseOffsetFromVBPtr(CGF, Base, VBPOffset, VBTOffset, VBPtr);
}
+ std::pair<llvm::Value *, llvm::Value *>
+ performBaseAdjustment(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy);
+
/// \brief Performs a full virtual base adjustment. Used to dereference
/// pointers to members of virtual bases.
llvm::Value *AdjustVirtualBase(CodeGenFunction &CGF, const Expr *E,
@@ -556,6 +573,94 @@
void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
+ llvm::StructType *getHandlerMapEntryType() {
+ if (!HandlerMapEntryType) {
+ llvm::Type *FieldTypes[] = {
+ CGM.IntTy, // Flags
+ getImageRelativeType(CGM.Int8PtrTy), // TypeDescriptor
+ };
+ HandlerMapEntryType = llvm::StructType::create(
+ CGM.getLLVMContext(), FieldTypes, "eh.HandlerMapEntry");
+ }
+ return HandlerMapEntryType;
+ }
+
+ llvm::StructType *getCatchableTypeType() {
+ if (CatchableTypeType)
+ return CatchableTypeType;
+ llvm::Type *FieldTypes[] = {
+ CGM.IntTy, // Flags
+ getImageRelativeType(CGM.Int8PtrTy), // TypeDescriptor
+ CGM.IntTy, // NonVirtualAdjustment
+ CGM.IntTy, // OffsetToVBPtr
+ CGM.IntTy, // VBTableIndex
+ CGM.IntTy, // Size
+ getImageRelativeType(CGM.Int8PtrTy) // CopyCtor
+ };
+ CatchableTypeType = llvm::StructType::create(
+ CGM.getLLVMContext(), FieldTypes, "eh.CatchableType");
+ return CatchableTypeType;
+ }
+
+ llvm::StructType *getCatchableTypeArrayType(uint32_t NumEntries) {
+ llvm::StructType *&CatchableTypeArrayType =
+ CatchableTypeArrayTypeMap[NumEntries];
+ if (CatchableTypeArrayType)
+ return CatchableTypeArrayType;
+
+ llvm::SmallString<23> CTATypeName("eh.CatchableTypeArray.");
+ CTATypeName += llvm::utostr(NumEntries);
+ llvm::Type *CTType =
+ getImageRelativeType(getCatchableTypeType()->getPointerTo());
+ llvm::Type *FieldTypes[] = {
+ CGM.IntTy, // NumEntries
+ llvm::ArrayType::get(CTType, NumEntries) // CatchableTypes
+ };
+ CatchableTypeArrayType =
+ llvm::StructType::create(CGM.getLLVMContext(), FieldTypes, CTATypeName);
+ return CatchableTypeArrayType;
+ }
+
+ llvm::StructType *getThrowInfoType() {
+ if (ThrowInfoType)
+ return ThrowInfoType;
+ llvm::Type *FieldTypes[] = {
+ CGM.IntTy, // Flags
+ getImageRelativeType(CGM.Int8PtrTy), // CleanupFn
+ getImageRelativeType(CGM.Int8PtrTy), // ForwardCompat
+ getImageRelativeType(CGM.Int8PtrTy) // CatchableTypeArray
+ };
+ ThrowInfoType = llvm::StructType::create(CGM.getLLVMContext(), FieldTypes,
+ "eh.ThrowInfo");
+ return ThrowInfoType;
+ }
+
+ llvm::Constant *getThrowFn() {
+ // _CxxThrowException is passed an exception object and a ThrowInfo object
+ // which describes the exception.
+ llvm::Type *Args[] = {CGM.Int8PtrTy, getThrowInfoType()->getPointerTo()};
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, Args, /*IsVarArgs=*/false);
+ auto *Fn = cast<llvm::Function>(
+ CGM.CreateRuntimeFunction(FTy, "_CxxThrowException"));
+ // _CxxThrowException is stdcall on 32-bit x86 platforms.
+ if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86)
+ Fn->setCallingConv(llvm::CallingConv::X86_StdCall);
+ return Fn;
+ }
+
+ llvm::Function *getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD,
+ CXXCtorType CT);
+
+ llvm::Constant *getCatchableType(QualType T,
+ uint32_t NVOffset = 0,
+ int32_t VBPtrOffset = -1,
+ uint32_t VBIndex = 0);
+
+ llvm::GlobalVariable *getCatchableTypeArray(QualType T);
+
+ llvm::GlobalVariable *getThrowInfo(QualType T) override;
+
private:
typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy;
typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *> VTablesMapTy;
@@ -587,6 +692,13 @@
llvm::StructType *BaseClassDescriptorType;
llvm::StructType *ClassHierarchyDescriptorType;
llvm::StructType *CompleteObjectLocatorType;
+
+ llvm::DenseMap<QualType, llvm::GlobalVariable *> CatchableTypeArrays;
+
+ llvm::StructType *CatchableTypeType;
+ llvm::DenseMap<uint32_t, llvm::StructType *> CatchableTypeArrayTypeMap;
+ llvm::StructType *ThrowInfoType;
+ llvm::StructType *HandlerMapEntryType;
};
}
@@ -667,55 +779,72 @@
CGF.EmitDeleteCall(DE->getOperatorDelete(), MDThis, ElementType);
}
-static llvm::Function *getRethrowFn(CodeGenModule &CGM) {
- // _CxxThrowException takes two pointer width arguments: a value and a context
- // object which points to a TypeInfo object.
- llvm::Type *ArgTypes[] = {CGM.Int8PtrTy, CGM.Int8PtrTy};
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false);
- auto *Fn = cast<llvm::Function>(
- CGM.CreateRuntimeFunction(FTy, "_CxxThrowException"));
- // _CxxThrowException is stdcall on 32-bit x86 platforms.
- if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86)
- Fn->setCallingConv(llvm::CallingConv::X86_StdCall);
- return Fn;
-}
-
void MicrosoftCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) {
- llvm::Value *Args[] = {llvm::ConstantPointerNull::get(CGM.Int8PtrTy),
- llvm::ConstantPointerNull::get(CGM.Int8PtrTy)};
- auto *Fn = getRethrowFn(CGM);
+ llvm::Value *Args[] = {
+ llvm::ConstantPointerNull::get(CGM.Int8PtrTy),
+ llvm::ConstantPointerNull::get(getThrowInfoType()->getPointerTo())};
+ auto *Fn = getThrowFn();
if (isNoReturn)
CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, Args);
else
CGF.EmitRuntimeCallOrInvoke(Fn, Args);
}
-/// \brief Gets the offset to the virtual base that contains the vfptr for
-/// MS-ABI polymorphic types.
-static llvm::Value *getPolymorphicOffset(CodeGenFunction &CGF,
- const CXXRecordDecl *RD,
- llvm::Value *Value) {
- const ASTContext &Context = RD->getASTContext();
- for (const CXXBaseSpecifier &Base : RD->vbases())
- if (Context.getASTRecordLayout(Base.getType()->getAsCXXRecordDecl())
- .hasExtendableVFPtr())
- return CGF.CGM.getCXXABI().GetVirtualBaseClassOffset(
- CGF, Value, RD, Base.getType()->getAsCXXRecordDecl());
- llvm_unreachable("One of our vbases should be polymorphic.");
+namespace {
+struct CallEndCatchMSVC : EHScopeStack::Cleanup {
+ CallEndCatchMSVC() {}
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
+ CGF.EmitNounwindRuntimeCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_endcatch));
+ }
+};
}
-static std::pair<llvm::Value *, llvm::Value *>
-performBaseAdjustment(CodeGenFunction &CGF, llvm::Value *Value,
- QualType SrcRecordTy) {
+void MicrosoftCXXABI::emitBeginCatch(CodeGenFunction &CGF,
+ const CXXCatchStmt *S) {
+ // In the MS ABI, the runtime handles the copy, and the catch handler is
+ // responsible for destruction.
+ VarDecl *CatchParam = S->getExceptionDecl();
+ llvm::Value *Exn = CGF.getExceptionFromSlot();
+ llvm::Function *BeginCatch =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch);
+
+ if (!CatchParam) {
+ llvm::Value *Args[2] = {Exn, llvm::Constant::getNullValue(CGF.Int8PtrTy)};
+ CGF.EmitNounwindRuntimeCall(BeginCatch, Args);
+ CGF.EHStack.pushCleanup<CallEndCatchMSVC>(NormalAndEHCleanup);
+ return;
+ }
+
+ CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam);
+ llvm::Value *ParamAddr =
+ CGF.Builder.CreateBitCast(var.getObjectAddress(CGF), CGF.Int8PtrTy);
+ llvm::Value *Args[2] = {Exn, ParamAddr};
+ CGF.EmitNounwindRuntimeCall(BeginCatch, Args);
+ // FIXME: Do we really need exceptional endcatch cleanups?
+ CGF.EHStack.pushCleanup<CallEndCatchMSVC>(NormalAndEHCleanup);
+ CGF.EmitAutoVarCleanups(var);
+}
+
+std::pair<llvm::Value *, llvm::Value *>
+MicrosoftCXXABI::performBaseAdjustment(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy) {
Value = CGF.Builder.CreateBitCast(Value, CGF.Int8PtrTy);
const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+ const ASTContext &Context = getContext();
- if (CGF.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr())
+ if (Context.getASTRecordLayout(SrcDecl).hasExtendableVFPtr())
return std::make_pair(Value, llvm::ConstantInt::get(CGF.Int32Ty, 0));
// Perform a base adjustment.
- llvm::Value *Offset = getPolymorphicOffset(CGF, SrcDecl, Value);
+ const CXXBaseSpecifier *PolymorphicBase = std::find_if(
+ SrcDecl->vbases_begin(), SrcDecl->vbases_end(),
+ [&](const CXXBaseSpecifier &Base) {
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ return Context.getASTRecordLayout(BaseDecl).hasExtendableVFPtr();
+ });
+ llvm::Value *Offset = GetVirtualBaseClassOffset(
+ CGF, Value, SrcDecl, PolymorphicBase->getType()->getAsCXXRecordDecl());
Value = CGF.Builder.CreateInBoundsGEP(Value, Offset);
Offset = CGF.Builder.CreateTrunc(Offset, CGF.Int32Ty);
return std::make_pair(Value, Offset);
@@ -725,7 +854,7 @@
QualType SrcRecordTy) {
const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
return IsDeref &&
- !CGM.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
+ !getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
}
static llvm::CallSite emitRTtypeidCall(CodeGenFunction &CGF,
@@ -759,7 +888,7 @@
QualType SrcRecordTy) {
const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
return SrcIsPtr &&
- !CGM.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
+ !getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
}
llvm::Value *MicrosoftCXXABI::EmitDynamicCastCall(
@@ -817,10 +946,11 @@
llvm::Value *MicrosoftCXXABI::GetVirtualBaseClassOffset(
CodeGenFunction &CGF, llvm::Value *This, const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl) {
+ const ASTContext &Context = getContext();
int64_t VBPtrChars =
- getContext().getASTRecordLayout(ClassDecl).getVBPtrOffset().getQuantity();
+ Context.getASTRecordLayout(ClassDecl).getVBPtrOffset().getQuantity();
llvm::Value *VBPtrOffset = llvm::ConstantInt::get(CGM.PtrDiffTy, VBPtrChars);
- CharUnits IntSize = getContext().getTypeSizeInChars(getContext().IntTy);
+ CharUnits IntSize = Context.getTypeSizeInChars(Context.IntTy);
CharUnits VBTableChars =
IntSize *
CGM.getMicrosoftVTableContext().getVBTableIndex(ClassDecl, BaseClassDecl);
@@ -947,23 +1077,44 @@
}
}
+static bool hasDefaultCXXMethodCC(ASTContext &Context,
+ const CXXMethodDecl *MD) {
+ CallingConv ExpectedCallingConv = Context.getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/true);
+ CallingConv ActualCallingConv =
+ MD->getType()->getAs<FunctionProtoType>()->getCallConv();
+ return ExpectedCallingConv == ActualCallingConv;
+}
+
void MicrosoftCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
// There's only one constructor type in this ABI.
CGM.EmitGlobal(GlobalDecl(D, Ctor_Complete));
+
+ // Exported default constructors either have a simple call-site where they use
+ // the typical calling convention and have a single 'this' pointer for an
+ // argument -or- they get a wrapper function which appropriately thunks to the
+ // real default constructor. This thunk is the default constructor closure.
+ if (D->hasAttr<DLLExportAttr>() && D->isDefaultConstructor())
+ if (!hasDefaultCXXMethodCC(getContext(), D) || D->getNumParams() != 0) {
+ llvm::Function *Fn = getAddrOfCXXCtorClosure(D, Ctor_DefaultClosure);
+ Fn->setLinkage(llvm::GlobalValue::WeakODRLinkage);
+ Fn->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+ }
}
void MicrosoftCXXABI::EmitVBPtrStores(CodeGenFunction &CGF,
const CXXRecordDecl *RD) {
llvm::Value *ThisInt8Ptr =
CGF.Builder.CreateBitCast(getThisValue(CGF), CGM.Int8PtrTy, "this.int8");
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ const ASTContext &Context = getContext();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
const VBTableGlobals &VBGlobals = enumerateVBTables(RD);
for (unsigned I = 0, E = VBGlobals.VBTables->size(); I != E; ++I) {
const VPtrInfo *VBT = (*VBGlobals.VBTables)[I];
llvm::GlobalVariable *GV = VBGlobals.Globals[I];
const ASTRecordLayout &SubobjectLayout =
- CGM.getContext().getASTRecordLayout(VBT->BaseWithVPtr);
+ Context.getASTRecordLayout(VBT->BaseWithVPtr);
CharUnits Offs = VBT->NonVirtualOffset;
Offs += SubobjectLayout.getVBPtrOffset();
if (VBT->getVBaseWithVPtr())
@@ -983,7 +1134,7 @@
// TODO: 'for base' flag
if (T == StructorType::Deleting) {
// The scalar deleting destructor takes an implicit int parameter.
- ArgTys.push_back(CGM.getContext().IntTy);
+ ArgTys.push_back(getContext().IntTy);
}
auto *CD = dyn_cast<CXXConstructorDecl>(MD);
if (!CD)
@@ -996,9 +1147,9 @@
const FunctionProtoType *FPT = CD->getType()->castAs<FunctionProtoType>();
if (Class->getNumVBases()) {
if (FPT->isVariadic())
- ArgTys.insert(ArgTys.begin() + 1, CGM.getContext().IntTy);
+ ArgTys.insert(ArgTys.begin() + 1, getContext().IntTy);
else
- ArgTys.push_back(CGM.getContext().IntTy);
+ ArgTys.push_back(getContext().IntTy);
}
}
@@ -1038,7 +1189,7 @@
if (ML.VBase) {
const ASTRecordLayout &DerivedLayout =
- CGM.getContext().getASTRecordLayout(MD->getParent());
+ getContext().getASTRecordLayout(MD->getParent());
Adjustment += DerivedLayout.getVBaseClassOffset(ML.VBase);
}
@@ -1280,7 +1431,7 @@
llvm::GlobalValue *VTableAddressPoint = VFTablesMap[ID];
if (!VTableAddressPoint) {
assert(Base.getBase()->getNumVBases() &&
- !CGM.getContext().getASTRecordLayout(Base.getBase()).hasOwnVFPtr());
+ !getContext().getASTRecordLayout(Base.getBase()).hasOwnVFPtr());
}
return VTableAddressPoint;
}
@@ -1336,102 +1487,97 @@
#endif
}
- for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) {
- if (VFPtrs[J]->FullOffsetInMDC != VPtrOffset)
- continue;
- SmallString<256> VFTableName;
- mangleVFTableName(getMangleContext(), RD, VFPtrs[J], VFTableName);
- StringRef VTableName = VFTableName;
+ VPtrInfo *const *VFPtrI =
+ std::find_if(VFPtrs.begin(), VFPtrs.end(), [&](VPtrInfo *VPI) {
+ return VPI->FullOffsetInMDC == VPtrOffset;
+ });
+ if (VFPtrI == VFPtrs.end()) {
+ VFTablesMap[ID] = nullptr;
+ return nullptr;
+ }
+ VPtrInfo *VFPtr = *VFPtrI;
- uint64_t NumVTableSlots =
- VTContext.getVFTableLayout(RD, VFPtrs[J]->FullOffsetInMDC)
- .getNumVTableComponents();
- llvm::GlobalValue::LinkageTypes VTableLinkage =
- llvm::GlobalValue::ExternalLinkage;
- llvm::ArrayType *VTableType =
- llvm::ArrayType::get(CGM.Int8PtrTy, NumVTableSlots);
- if (getContext().getLangOpts().RTTIData) {
- VTableLinkage = llvm::GlobalValue::PrivateLinkage;
- VTableName = "";
- }
+ SmallString<256> VFTableName;
+ mangleVFTableName(getMangleContext(), RD, VFPtr, VFTableName);
- VTable = CGM.getModule().getNamedGlobal(VFTableName);
- if (!VTable) {
- // Create a backing variable for the contents of VTable. The VTable may
- // or may not include space for a pointer to RTTI data.
- llvm::GlobalValue *VFTable = VTable = new llvm::GlobalVariable(
- CGM.getModule(), VTableType, /*isConstant=*/true, VTableLinkage,
- /*Initializer=*/nullptr, VTableName);
- VTable->setUnnamedAddr(true);
+ llvm::GlobalValue::LinkageTypes VFTableLinkage = CGM.getVTableLinkage(RD);
+ bool VFTableComesFromAnotherTU =
+ llvm::GlobalValue::isAvailableExternallyLinkage(VFTableLinkage) ||
+ llvm::GlobalValue::isExternalLinkage(VFTableLinkage);
+ bool VTableAliasIsRequred =
+ !VFTableComesFromAnotherTU && getContext().getLangOpts().RTTIData;
- // Only insert a pointer into the VFTable for RTTI data if we are not
- // importing it. We never reference the RTTI data directly so there is no
- // need to make room for it.
- if (getContext().getLangOpts().RTTIData &&
- !RD->hasAttr<DLLImportAttr>()) {
- llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0),
- llvm::ConstantInt::get(CGM.IntTy, 1)};
- // Create a GEP which points just after the first entry in the VFTable,
- // this should be the location of the first virtual method.
- llvm::Constant *VTableGEP =
- llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, GEPIndices);
- // The symbol for the VFTable is an alias to the GEP. It is
- // transparent, to other modules, what the nature of this symbol is; all
- // that matters is that the alias be the address of the first virtual
- // method.
- VFTable = llvm::GlobalAlias::create(
- cast<llvm::SequentialType>(VTableGEP->getType())->getElementType(),
- /*AddressSpace=*/0, llvm::GlobalValue::ExternalLinkage,
- VFTableName.str(), VTableGEP, &CGM.getModule());
- } else {
- // We don't need a GlobalAlias to be a symbol for the VTable if we won't
- // be referencing any RTTI data. The GlobalVariable will end up being
- // an appropriate definition of the VFTable.
- VTable->setName(VFTableName.str());
- }
-
- VFTable->setUnnamedAddr(true);
- if (RD->hasAttr<DLLImportAttr>())
- VFTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
- else if (RD->hasAttr<DLLExportAttr>())
- VFTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
-
- llvm::GlobalValue::LinkageTypes VFTableLinkage = CGM.getVTableLinkage(RD);
- if (VFTable != VTable) {
- if (llvm::GlobalValue::isAvailableExternallyLinkage(VFTableLinkage)) {
- // AvailableExternally implies that we grabbed the data from another
- // executable. No need to stick the alias in a Comdat.
- } else if (llvm::GlobalValue::isInternalLinkage(VFTableLinkage) ||
- llvm::GlobalValue::isWeakODRLinkage(VFTableLinkage) ||
- llvm::GlobalValue::isLinkOnceODRLinkage(VFTableLinkage)) {
- // The alias is going to be dropped into a Comdat, no need to make it
- // weak.
- if (!llvm::GlobalValue::isInternalLinkage(VFTableLinkage))
- VFTableLinkage = llvm::GlobalValue::ExternalLinkage;
- llvm::Comdat *C =
- CGM.getModule().getOrInsertComdat(VFTable->getName());
- // We must indicate which VFTable is larger to support linking between
- // translation units which do and do not have RTTI data. The largest
- // VFTable contains the RTTI data; translation units which reference
- // the smaller VFTable always reference it relative to the first
- // virtual method.
- C->setSelectionKind(llvm::Comdat::Largest);
- VTable->setComdat(C);
- } else {
- llvm_unreachable("unexpected linkage for vftable!");
- }
- } else {
- if (llvm::GlobalValue::isWeakForLinker(VFTableLinkage))
- VTable->setComdat(
- CGM.getModule().getOrInsertComdat(VTable->getName()));
- }
- VFTable->setLinkage(VFTableLinkage);
- CGM.setGlobalVisibility(VFTable, RD);
- VFTablesMap[ID] = VFTable;
- }
- break;
+ if (llvm::GlobalValue *VFTable =
+ CGM.getModule().getNamedGlobal(VFTableName)) {
+ VFTablesMap[ID] = VFTable;
+ return VTableAliasIsRequred
+ ? cast<llvm::GlobalVariable>(
+ cast<llvm::GlobalAlias>(VFTable)->getBaseObject())
+ : cast<llvm::GlobalVariable>(VFTable);
}
+ uint64_t NumVTableSlots =
+ VTContext.getVFTableLayout(RD, VFPtr->FullOffsetInMDC)
+ .getNumVTableComponents();
+ llvm::GlobalValue::LinkageTypes VTableLinkage =
+ VTableAliasIsRequred ? llvm::GlobalValue::PrivateLinkage : VFTableLinkage;
+
+ StringRef VTableName = VTableAliasIsRequred ? StringRef() : VFTableName.str();
+
+ llvm::ArrayType *VTableType =
+ llvm::ArrayType::get(CGM.Int8PtrTy, NumVTableSlots);
+
+ // Create a backing variable for the contents of VTable. The VTable may
+ // or may not include space for a pointer to RTTI data.
+ llvm::GlobalValue *VFTable;
+ VTable = new llvm::GlobalVariable(CGM.getModule(), VTableType,
+ /*isConstant=*/true, VTableLinkage,
+ /*Initializer=*/nullptr, VTableName);
+ VTable->setUnnamedAddr(true);
+
+ llvm::Comdat *C = nullptr;
+ if (!VFTableComesFromAnotherTU &&
+ (llvm::GlobalValue::isWeakForLinker(VFTableLinkage) ||
+ (llvm::GlobalValue::isLocalLinkage(VFTableLinkage) &&
+ VTableAliasIsRequred)))
+ C = CGM.getModule().getOrInsertComdat(VFTableName.str());
+
+ // Only insert a pointer into the VFTable for RTTI data if we are not
+ // importing it. We never reference the RTTI data directly so there is no
+ // need to make room for it.
+ if (VTableAliasIsRequred) {
+ llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0),
+ llvm::ConstantInt::get(CGM.IntTy, 1)};
+ // Create a GEP which points just after the first entry in the VFTable,
+ // this should be the location of the first virtual method.
+ llvm::Constant *VTableGEP =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, GEPIndices);
+ if (llvm::GlobalValue::isWeakForLinker(VFTableLinkage)) {
+ VFTableLinkage = llvm::GlobalValue::ExternalLinkage;
+ if (C)
+ C->setSelectionKind(llvm::Comdat::Largest);
+ }
+ VFTable = llvm::GlobalAlias::create(
+ cast<llvm::SequentialType>(VTableGEP->getType())->getElementType(),
+ /*AddressSpace=*/0, VFTableLinkage, VFTableName.str(), VTableGEP,
+ &CGM.getModule());
+ VFTable->setUnnamedAddr(true);
+ } else {
+ // We don't need a GlobalAlias to be a symbol for the VTable if we won't
+ // be referencing any RTTI data.
+ // The GlobalVariable will end up being an appropriate definition of the
+ // VFTable.
+ VFTable = VTable;
+ }
+ if (C)
+ VTable->setComdat(C);
+
+ if (RD->hasAttr<DLLImportAttr>())
+ VFTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ else if (RD->hasAttr<DLLExportAttr>())
+ VFTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+
+ VFTablesMap[ID] = VFTable;
return VTable;
}
@@ -1468,7 +1614,7 @@
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
llvm::Value *Callee = getVirtualFunctionPointer(CGF, GD, This, Ty);
- ASTContext &Context = CGF.getContext();
+ ASTContext &Context = getContext();
llvm::Value *ImplicitParam = llvm::ConstantInt::get(
llvm::IntegerType::getInt32Ty(CGF.getLLVMContext()),
DtorType == Dtor_Deleting);
@@ -1625,9 +1771,8 @@
"should only emit vbtables for classes with vbtables");
const ASTRecordLayout &BaseLayout =
- CGM.getContext().getASTRecordLayout(VBT.BaseWithVPtr);
- const ASTRecordLayout &DerivedLayout =
- CGM.getContext().getASTRecordLayout(RD);
+ getContext().getASTRecordLayout(VBT.BaseWithVPtr);
+ const ASTRecordLayout &DerivedLayout = getContext().getASTRecordLayout(RD);
SmallVector<llvm::Constant *, 4> Offsets(1 + ReusingBase->getNumVBases(),
nullptr);
@@ -1661,9 +1806,6 @@
llvm::ArrayType::get(CGM.IntTy, Offsets.size());
llvm::Constant *Init = llvm::ConstantArray::get(VBTableType, Offsets);
GV->setInitializer(Init);
-
- // Set the right visibility.
- CGM.setGlobalVisibility(GV, RD);
}
llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF,
@@ -1719,8 +1861,8 @@
if (RA.Virtual.Microsoft.VBIndex) {
assert(RA.Virtual.Microsoft.VBIndex > 0);
- int32_t IntSize =
- getContext().getTypeSizeInChars(getContext().IntTy).getQuantity();
+ const ASTContext &Context = getContext();
+ int32_t IntSize = Context.getTypeSizeInChars(Context.IntTy).getQuantity();
llvm::Value *VBPtr;
llvm::Value *VBaseOffset =
GetVBaseOffsetFromVBPtr(CGF, V, RA.Virtual.Microsoft.VBPtrOffset,
@@ -2874,7 +3016,7 @@
auto Type = ABI.getClassHierarchyDescriptorType();
auto CHD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
/*Initializer=*/nullptr,
- MangledName.c_str());
+ StringRef(MangledName));
if (CHD->isWeakForLinker())
CHD->setComdat(CGM.getModule().getOrInsertComdat(CHD->getName()));
@@ -2907,9 +3049,10 @@
llvm::Type *PtrType = ABI.getImageRelativeType(
ABI.getBaseClassDescriptorType()->getPointerTo());
auto *ArrType = llvm::ArrayType::get(PtrType, Classes.size() + 1);
- auto *BCA = new llvm::GlobalVariable(
- Module, ArrType,
- /*Constant=*/true, Linkage, /*Initializer=*/nullptr, MangledName.c_str());
+ auto *BCA =
+ new llvm::GlobalVariable(Module, ArrType,
+ /*Constant=*/true, Linkage,
+ /*Initializer=*/nullptr, StringRef(MangledName));
if (BCA->isWeakForLinker())
BCA->setComdat(CGM.getModule().getOrInsertComdat(BCA->getName()));
@@ -2949,9 +3092,9 @@
// Forward-declare the base class descriptor.
auto Type = ABI.getBaseClassDescriptorType();
- auto BCD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
- /*Initializer=*/nullptr,
- MangledName.c_str());
+ auto BCD =
+ new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
+ /*Initializer=*/nullptr, StringRef(MangledName));
if (BCD->isWeakForLinker())
BCD->setComdat(CGM.getModule().getOrInsertComdat(BCD->getName()));
@@ -2997,7 +3140,7 @@
// Forward-declare the complete object locator.
llvm::StructType *Type = ABI.getCompleteObjectLocatorType();
auto COL = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
- /*Initializer=*/nullptr, MangledName.c_str());
+ /*Initializer=*/nullptr, StringRef(MangledName));
// Initialize the CompleteObjectLocator.
llvm::Constant *Fields[] = {
@@ -3018,12 +3161,87 @@
return COL;
}
+static QualType decomposeTypeForEH(ASTContext &Context, QualType T,
+ bool &IsConst, bool &IsVolatile) {
+ T = Context.getExceptionObjectType(T);
+
+ // C++14 [except.handle]p3:
+ // A handler is a match for an exception object of type E if [...]
+ // - the handler is of type cv T or const T& where T is a pointer type and
+ // E is a pointer type that can be converted to T by [...]
+ // - a qualification conversion
+ IsConst = false;
+ IsVolatile = false;
+ QualType PointeeType = T->getPointeeType();
+ if (!PointeeType.isNull()) {
+ IsConst = PointeeType.isConstQualified();
+ IsVolatile = PointeeType.isVolatileQualified();
+ }
+
+ // Member pointer types like "const int A::*" are represented by having RTTI
+ // for "int A::*" and separately storing the const qualifier.
+ if (const auto *MPTy = T->getAs<MemberPointerType>())
+ T = Context.getMemberPointerType(PointeeType.getUnqualifiedType(),
+ MPTy->getClass());
+
+ // Pointer types like "const int * const *" are represented by having RTTI
+ // for "const int **" and separately storing the const qualifier.
+ if (T->isPointerType())
+ T = Context.getPointerType(PointeeType.getUnqualifiedType());
+
+ return T;
+}
+
+llvm::Constant *
+MicrosoftCXXABI::getAddrOfCXXHandlerMapEntry(QualType Type,
+ QualType CatchHandlerType) {
+ // TypeDescriptors for exceptions never have qualified pointer types,
+ // qualifiers are stored seperately in order to support qualification
+ // conversions.
+ bool IsConst, IsVolatile;
+ Type = decomposeTypeForEH(getContext(), Type, IsConst, IsVolatile);
+
+ bool IsReference = CatchHandlerType->isReferenceType();
+
+ SmallString<256> MangledName;
+ {
+ llvm::raw_svector_ostream Out(MangledName);
+ getMangleContext().mangleCXXHandlerMapEntry(Type, IsConst, IsVolatile,
+ IsReference, Out);
+ }
+
+ if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
+ return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
+
+ uint32_t Flags = 0;
+ if (IsConst)
+ Flags |= 1;
+ if (IsVolatile)
+ Flags |= 2;
+ if (IsReference)
+ Flags |= 8;
+
+ llvm::Constant *Fields[] = {
+ llvm::ConstantInt::get(CGM.IntTy, Flags), // Flags
+ getImageRelativeConstant(getAddrOfRTTIDescriptor(Type)), // TypeDescriptor
+ };
+ llvm::StructType *HandlerMapEntryType = getHandlerMapEntryType();
+ auto *Var = new llvm::GlobalVariable(
+ CGM.getModule(), HandlerMapEntryType, /*Constant=*/true,
+ llvm::GlobalValue::PrivateLinkage,
+ llvm::ConstantStruct::get(HandlerMapEntryType, Fields),
+ StringRef(MangledName));
+ Var->setUnnamedAddr(true);
+ Var->setSection("llvm.metadata");
+ return Var;
+}
+
/// \brief Gets a TypeDescriptor. Returns a llvm::Constant * rather than a
/// llvm::GlobalVariable * because different type descriptors have different
/// types, and need to be abstracted. They are abstracting by casting the
/// address to an Int8PtrTy.
llvm::Constant *MicrosoftCXXABI::getAddrOfRTTIDescriptor(QualType Type) {
- SmallString<256> MangledName, TypeInfoString;
+ SmallString<256> MangledName;
{
llvm::raw_svector_ostream Out(MangledName);
getMangleContext().mangleCXXRTTI(Type, Out);
@@ -3034,6 +3252,7 @@
return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
// Compute the fields for the TypeDescriptor.
+ SmallString<256> TypeInfoString;
{
llvm::raw_svector_ostream Out(TypeInfoString);
getMangleContext().mangleCXXRTTIName(Type, Out);
@@ -3050,7 +3269,7 @@
CGM.getModule(), TypeDescriptorType, /*Constant=*/false,
getLinkageForRTTI(Type),
llvm::ConstantStruct::get(TypeDescriptorType, Fields),
- MangledName.c_str());
+ StringRef(MangledName));
if (Var->isWeakForLinker())
Var->setComdat(CGM.getModule().getOrInsertComdat(Var->getName()));
return llvm::ConstantExpr::getBitCast(Var, CGM.Int8PtrTy);
@@ -3107,3 +3326,399 @@
}
emitCXXDestructor(CGM, cast<CXXDestructorDecl>(MD), Type);
}
+
+llvm::Function *
+MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD,
+ CXXCtorType CT) {
+ assert(CT == Ctor_CopyingClosure || CT == Ctor_DefaultClosure);
+
+ // Calculate the mangled name.
+ SmallString<256> ThunkName;
+ llvm::raw_svector_ostream Out(ThunkName);
+ getMangleContext().mangleCXXCtor(CD, CT, Out);
+ Out.flush();
+
+ // If the thunk has been generated previously, just return it.
+ if (llvm::GlobalValue *GV = CGM.getModule().getNamedValue(ThunkName))
+ return cast<llvm::Function>(GV);
+
+ // Create the llvm::Function.
+ const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeMSCtorClosure(CD, CT);
+ llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
+ const CXXRecordDecl *RD = CD->getParent();
+ QualType RecordTy = getContext().getRecordType(RD);
+ llvm::Function *ThunkFn = llvm::Function::Create(
+ ThunkTy, getLinkageForRTTI(RecordTy), ThunkName.str(), &CGM.getModule());
+ ThunkFn->setCallingConv(static_cast<llvm::CallingConv::ID>(
+ FnInfo.getEffectiveCallingConvention()));
+ bool IsCopy = CT == Ctor_CopyingClosure;
+
+ // Start codegen.
+ CodeGenFunction CGF(CGM);
+ CGF.CurGD = GlobalDecl(CD, Ctor_Complete);
+
+ // Build FunctionArgs.
+ FunctionArgList FunctionArgs;
+
+ // A constructor always starts with a 'this' pointer as its first argument.
+ buildThisParam(CGF, FunctionArgs);
+
+ // Following the 'this' pointer is a reference to the source object that we
+ // are copying from.
+ ImplicitParamDecl SrcParam(
+ getContext(), nullptr, SourceLocation(), &getContext().Idents.get("src"),
+ getContext().getLValueReferenceType(RecordTy,
+ /*SpelledAsLValue=*/true));
+ if (IsCopy)
+ FunctionArgs.push_back(&SrcParam);
+
+ // Constructors for classes which utilize virtual bases have an additional
+ // parameter which indicates whether or not it is being delegated to by a more
+ // derived constructor.
+ ImplicitParamDecl IsMostDerived(getContext(), nullptr, SourceLocation(),
+ &getContext().Idents.get("is_most_derived"),
+ getContext().IntTy);
+ // Only add the parameter to the list if thie class has virtual bases.
+ if (RD->getNumVBases() > 0)
+ FunctionArgs.push_back(&IsMostDerived);
+
+ // Start defining the function.
+ CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo,
+ FunctionArgs, CD->getLocation(), SourceLocation());
+ EmitThisParam(CGF);
+ llvm::Value *This = getThisValue(CGF);
+
+ llvm::Value *SrcVal =
+ IsCopy ? CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&SrcParam), "src")
+ : nullptr;
+
+ CallArgList Args;
+
+ // Push the this ptr.
+ Args.add(RValue::get(This), CD->getThisType(getContext()));
+
+ // Push the src ptr.
+ if (SrcVal)
+ Args.add(RValue::get(SrcVal), SrcParam.getType());
+
+ // Add the rest of the default arguments.
+ std::vector<Stmt *> ArgVec;
+ for (unsigned I = IsCopy ? 1 : 0, E = CD->getNumParams(); I != E; ++I) {
+ Stmt *DefaultArg = getContext().getDefaultArgExprForConstructor(CD, I);
+ assert(DefaultArg && "sema forgot to instantiate default args");
+ ArgVec.push_back(DefaultArg);
+ }
+
+ CodeGenFunction::RunCleanupsScope Cleanups(CGF);
+
+ const auto *FPT = CD->getType()->castAs<FunctionProtoType>();
+ ConstExprIterator ArgBegin(ArgVec.data()),
+ ArgEnd(ArgVec.data() + ArgVec.size());
+ CGF.EmitCallArgs(Args, FPT, ArgBegin, ArgEnd, CD, IsCopy ? 1 : 0);
+
+ // Insert any ABI-specific implicit constructor arguments.
+ unsigned ExtraArgs = addImplicitConstructorArgs(CGF, CD, Ctor_Complete,
+ /*ForVirtualBase=*/false,
+ /*Delegating=*/false, Args);
+
+ // Call the destructor with our arguments.
+ llvm::Value *CalleeFn = CGM.getAddrOfCXXStructor(CD, StructorType::Complete);
+ const CGFunctionInfo &CalleeInfo = CGM.getTypes().arrangeCXXConstructorCall(
+ Args, CD, Ctor_Complete, ExtraArgs);
+ CGF.EmitCall(CalleeInfo, CalleeFn, ReturnValueSlot(), Args, CD);
+
+ Cleanups.ForceCleanup();
+
+ // Emit the ret instruction, remove any temporary instructions created for the
+ // aid of CodeGen.
+ CGF.FinishFunction(SourceLocation());
+
+ return ThunkFn;
+}
+
+llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T,
+ uint32_t NVOffset,
+ int32_t VBPtrOffset,
+ uint32_t VBIndex) {
+ assert(!T->isReferenceType());
+
+ CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+ const CXXConstructorDecl *CD =
+ RD ? CGM.getContext().getCopyConstructorForExceptionObject(RD) : nullptr;
+ CXXCtorType CT = Ctor_Complete;
+ if (CD)
+ if (!hasDefaultCXXMethodCC(getContext(), CD) || CD->getNumParams() != 1)
+ CT = Ctor_CopyingClosure;
+
+ uint32_t Size = getContext().getTypeSizeInChars(T).getQuantity();
+ SmallString<256> MangledName;
+ {
+ llvm::raw_svector_ostream Out(MangledName);
+ getMangleContext().mangleCXXCatchableType(T, CD, CT, Size, NVOffset,
+ VBPtrOffset, VBIndex, Out);
+ }
+ if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
+ return getImageRelativeConstant(GV);
+
+ // The TypeDescriptor is used by the runtime to determine if a catch handler
+ // is appropriate for the exception object.
+ llvm::Constant *TD = getImageRelativeConstant(getAddrOfRTTIDescriptor(T));
+
+ // The runtime is responsible for calling the copy constructor if the
+ // exception is caught by value.
+ llvm::Constant *CopyCtor;
+ if (CD) {
+ if (CT == Ctor_CopyingClosure)
+ CopyCtor = getAddrOfCXXCtorClosure(CD, Ctor_CopyingClosure);
+ else
+ CopyCtor = CGM.getAddrOfCXXStructor(CD, StructorType::Complete);
+
+ CopyCtor = llvm::ConstantExpr::getBitCast(CopyCtor, CGM.Int8PtrTy);
+ } else {
+ CopyCtor = llvm::Constant::getNullValue(CGM.Int8PtrTy);
+ }
+ CopyCtor = getImageRelativeConstant(CopyCtor);
+
+ bool IsScalar = !RD;
+ bool HasVirtualBases = false;
+ bool IsStdBadAlloc = false; // std::bad_alloc is special for some reason.
+ QualType PointeeType = T;
+ if (T->isPointerType())
+ PointeeType = T->getPointeeType();
+ if (const CXXRecordDecl *RD = PointeeType->getAsCXXRecordDecl()) {
+ HasVirtualBases = RD->getNumVBases() > 0;
+ if (IdentifierInfo *II = RD->getIdentifier())
+ IsStdBadAlloc = II->isStr("bad_alloc") && RD->isInStdNamespace();
+ }
+
+ // Encode the relevant CatchableType properties into the Flags bitfield.
+ // FIXME: Figure out how bits 2 or 8 can get set.
+ uint32_t Flags = 0;
+ if (IsScalar)
+ Flags |= 1;
+ if (HasVirtualBases)
+ Flags |= 4;
+ if (IsStdBadAlloc)
+ Flags |= 16;
+
+ llvm::Constant *Fields[] = {
+ llvm::ConstantInt::get(CGM.IntTy, Flags), // Flags
+ TD, // TypeDescriptor
+ llvm::ConstantInt::get(CGM.IntTy, NVOffset), // NonVirtualAdjustment
+ llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset), // OffsetToVBPtr
+ llvm::ConstantInt::get(CGM.IntTy, VBIndex), // VBTableIndex
+ llvm::ConstantInt::get(CGM.IntTy, Size), // Size
+ CopyCtor // CopyCtor
+ };
+ llvm::StructType *CTType = getCatchableTypeType();
+ auto *GV = new llvm::GlobalVariable(
+ CGM.getModule(), CTType, /*Constant=*/true, getLinkageForRTTI(T),
+ llvm::ConstantStruct::get(CTType, Fields), StringRef(MangledName));
+ GV->setUnnamedAddr(true);
+ GV->setSection(".xdata");
+ if (GV->isWeakForLinker())
+ GV->setComdat(CGM.getModule().getOrInsertComdat(GV->getName()));
+ return getImageRelativeConstant(GV);
+}
+
+llvm::GlobalVariable *MicrosoftCXXABI::getCatchableTypeArray(QualType T) {
+ assert(!T->isReferenceType());
+
+ // See if we've already generated a CatchableTypeArray for this type before.
+ llvm::GlobalVariable *&CTA = CatchableTypeArrays[T];
+ if (CTA)
+ return CTA;
+
+ // Ensure that we don't have duplicate entries in our CatchableTypeArray by
+ // using a SmallSetVector. Duplicates may arise due to virtual bases
+ // occurring more than once in the hierarchy.
+ llvm::SmallSetVector<llvm::Constant *, 2> CatchableTypes;
+
+ // C++14 [except.handle]p3:
+ // A handler is a match for an exception object of type E if [...]
+ // - the handler is of type cv T or cv T& and T is an unambiguous public
+ // base class of E, or
+ // - the handler is of type cv T or const T& where T is a pointer type and
+ // E is a pointer type that can be converted to T by [...]
+ // - a standard pointer conversion (4.10) not involving conversions to
+ // pointers to private or protected or ambiguous classes
+ const CXXRecordDecl *MostDerivedClass = nullptr;
+ bool IsPointer = T->isPointerType();
+ if (IsPointer)
+ MostDerivedClass = T->getPointeeType()->getAsCXXRecordDecl();
+ else
+ MostDerivedClass = T->getAsCXXRecordDecl();
+
+ // Collect all the unambiguous public bases of the MostDerivedClass.
+ if (MostDerivedClass) {
+ const ASTContext &Context = getContext();
+ const ASTRecordLayout &MostDerivedLayout =
+ Context.getASTRecordLayout(MostDerivedClass);
+ MicrosoftVTableContext &VTableContext = CGM.getMicrosoftVTableContext();
+ SmallVector<MSRTTIClass, 8> Classes;
+ serializeClassHierarchy(Classes, MostDerivedClass);
+ Classes.front().initialize(/*Parent=*/nullptr, /*Specifier=*/nullptr);
+ detectAmbiguousBases(Classes);
+ for (const MSRTTIClass &Class : Classes) {
+ // Skip any ambiguous or private bases.
+ if (Class.Flags &
+ (MSRTTIClass::IsPrivateOnPath | MSRTTIClass::IsAmbiguous))
+ continue;
+ // Write down how to convert from a derived pointer to a base pointer.
+ uint32_t OffsetInVBTable = 0;
+ int32_t VBPtrOffset = -1;
+ if (Class.VirtualRoot) {
+ OffsetInVBTable =
+ VTableContext.getVBTableIndex(MostDerivedClass, Class.VirtualRoot)*4;
+ VBPtrOffset = MostDerivedLayout.getVBPtrOffset().getQuantity();
+ }
+
+ // Turn our record back into a pointer if the exception object is a
+ // pointer.
+ QualType RTTITy = QualType(Class.RD->getTypeForDecl(), 0);
+ if (IsPointer)
+ RTTITy = Context.getPointerType(RTTITy);
+ CatchableTypes.insert(getCatchableType(RTTITy, Class.OffsetInVBase,
+ VBPtrOffset, OffsetInVBTable));
+ }
+ }
+
+ // C++14 [except.handle]p3:
+ // A handler is a match for an exception object of type E if
+ // - The handler is of type cv T or cv T& and E and T are the same type
+ // (ignoring the top-level cv-qualifiers)
+ CatchableTypes.insert(getCatchableType(T));
+
+ // C++14 [except.handle]p3:
+ // A handler is a match for an exception object of type E if
+ // - the handler is of type cv T or const T& where T is a pointer type and
+ // E is a pointer type that can be converted to T by [...]
+ // - a standard pointer conversion (4.10) not involving conversions to
+ // pointers to private or protected or ambiguous classes
+ //
+ // All pointers are convertible to pointer-to-void so ensure that it is in the
+ // CatchableTypeArray.
+ if (IsPointer)
+ CatchableTypes.insert(getCatchableType(getContext().VoidPtrTy));
+
+ // C++14 [except.handle]p3:
+ // A handler is a match for an exception object of type E if [...]
+ // - the handler is of type cv T or const T& where T is a pointer or
+ // pointer to member type and E is std::nullptr_t.
+ //
+ // We cannot possibly list all possible pointer types here, making this
+ // implementation incompatible with the standard. However, MSVC includes an
+ // entry for pointer-to-void in this case. Let's do the same.
+ if (T->isNullPtrType())
+ CatchableTypes.insert(getCatchableType(getContext().VoidPtrTy));
+
+ uint32_t NumEntries = CatchableTypes.size();
+ llvm::Type *CTType =
+ getImageRelativeType(getCatchableTypeType()->getPointerTo());
+ llvm::ArrayType *AT = llvm::ArrayType::get(CTType, NumEntries);
+ llvm::StructType *CTAType = getCatchableTypeArrayType(NumEntries);
+ llvm::Constant *Fields[] = {
+ llvm::ConstantInt::get(CGM.IntTy, NumEntries), // NumEntries
+ llvm::ConstantArray::get(
+ AT, llvm::makeArrayRef(CatchableTypes.begin(),
+ CatchableTypes.end())) // CatchableTypes
+ };
+ SmallString<256> MangledName;
+ {
+ llvm::raw_svector_ostream Out(MangledName);
+ getMangleContext().mangleCXXCatchableTypeArray(T, NumEntries, Out);
+ }
+ CTA = new llvm::GlobalVariable(
+ CGM.getModule(), CTAType, /*Constant=*/true, getLinkageForRTTI(T),
+ llvm::ConstantStruct::get(CTAType, Fields), StringRef(MangledName));
+ CTA->setUnnamedAddr(true);
+ CTA->setSection(".xdata");
+ if (CTA->isWeakForLinker())
+ CTA->setComdat(CGM.getModule().getOrInsertComdat(CTA->getName()));
+ return CTA;
+}
+
+llvm::GlobalVariable *MicrosoftCXXABI::getThrowInfo(QualType T) {
+ bool IsConst, IsVolatile;
+ T = decomposeTypeForEH(getContext(), T, IsConst, IsVolatile);
+
+ // The CatchableTypeArray enumerates the various (CV-unqualified) types that
+ // the exception object may be caught as.
+ llvm::GlobalVariable *CTA = getCatchableTypeArray(T);
+ // The first field in a CatchableTypeArray is the number of CatchableTypes.
+ // This is used as a component of the mangled name which means that we need to
+ // know what it is in order to see if we have previously generated the
+ // ThrowInfo.
+ uint32_t NumEntries =
+ cast<llvm::ConstantInt>(CTA->getInitializer()->getAggregateElement(0U))
+ ->getLimitedValue();
+
+ SmallString<256> MangledName;
+ {
+ llvm::raw_svector_ostream Out(MangledName);
+ getMangleContext().mangleCXXThrowInfo(T, IsConst, IsVolatile, NumEntries,
+ Out);
+ }
+
+ // Reuse a previously generated ThrowInfo if we have generated an appropriate
+ // one before.
+ if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
+ return GV;
+
+ // The RTTI TypeDescriptor uses an unqualified type but catch clauses must
+ // be at least as CV qualified. Encode this requirement into the Flags
+ // bitfield.
+ uint32_t Flags = 0;
+ if (IsConst)
+ Flags |= 1;
+ if (IsVolatile)
+ Flags |= 2;
+
+ // The cleanup-function (a destructor) must be called when the exception
+ // object's lifetime ends.
+ llvm::Constant *CleanupFn = llvm::Constant::getNullValue(CGM.Int8PtrTy);
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ if (CXXDestructorDecl *DtorD = RD->getDestructor())
+ if (!DtorD->isTrivial())
+ CleanupFn = llvm::ConstantExpr::getBitCast(
+ CGM.getAddrOfCXXStructor(DtorD, StructorType::Complete),
+ CGM.Int8PtrTy);
+ // This is unused as far as we can tell, initialize it to null.
+ llvm::Constant *ForwardCompat =
+ getImageRelativeConstant(llvm::Constant::getNullValue(CGM.Int8PtrTy));
+ llvm::Constant *PointerToCatchableTypes = getImageRelativeConstant(
+ llvm::ConstantExpr::getBitCast(CTA, CGM.Int8PtrTy));
+ llvm::StructType *TIType = getThrowInfoType();
+ llvm::Constant *Fields[] = {
+ llvm::ConstantInt::get(CGM.IntTy, Flags), // Flags
+ getImageRelativeConstant(CleanupFn), // CleanupFn
+ ForwardCompat, // ForwardCompat
+ PointerToCatchableTypes // CatchableTypeArray
+ };
+ auto *GV = new llvm::GlobalVariable(
+ CGM.getModule(), TIType, /*Constant=*/true, getLinkageForRTTI(T),
+ llvm::ConstantStruct::get(TIType, Fields), StringRef(MangledName));
+ GV->setUnnamedAddr(true);
+ GV->setSection(".xdata");
+ if (GV->isWeakForLinker())
+ GV->setComdat(CGM.getModule().getOrInsertComdat(GV->getName()));
+ return GV;
+}
+
+void MicrosoftCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) {
+ const Expr *SubExpr = E->getSubExpr();
+ QualType ThrowType = SubExpr->getType();
+ // The exception object lives on the stack and it's address is passed to the
+ // runtime function.
+ llvm::AllocaInst *AI = CGF.CreateMemTemp(ThrowType);
+ CGF.EmitAnyExprToMem(SubExpr, AI, ThrowType.getQualifiers(),
+ /*IsInit=*/true);
+
+ // The so-called ThrowInfo is used to describe how the exception object may be
+ // caught.
+ llvm::GlobalVariable *TI = getThrowInfo(ThrowType);
+
+ // Call into the runtime to throw the exception.
+ llvm::Value *Args[] = {CGF.Builder.CreateBitCast(AI, CGM.Int8PtrTy), TI};
+ CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(), Args);
+}
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 36f9914..43cf791 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -238,7 +238,7 @@
/// \return The field declaration for the single non-empty field, if
/// it exists.
static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
- const RecordType *RT = T->getAsStructureType();
+ const RecordType *RT = T->getAs<RecordType>();
if (!RT)
return nullptr;
@@ -664,10 +664,6 @@
('T' << 24);
return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
}
-
- bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
- return true;
- }
};
}
@@ -1613,10 +1609,6 @@
unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
return HasAVX ? 32 : 16;
}
-
- bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
- return true;
- }
};
class PS4TargetCodeGenInfo : public X86_64TargetCodeGenInfo {
@@ -2210,20 +2202,9 @@
Ty = QualType(InnerTy, 0);
llvm::Type *IRType = CGT.ConvertType(Ty);
-
- // If the preferred type is a 16-byte vector, prefer to pass it.
- if (llvm::VectorType *VT = dyn_cast<llvm::VectorType>(IRType)){
- llvm::Type *EltTy = VT->getElementType();
- unsigned BitWidth = VT->getBitWidth();
- if ((BitWidth >= 128 && BitWidth <= 256) &&
- (EltTy->isFloatTy() || EltTy->isDoubleTy() ||
- EltTy->isIntegerTy(8) || EltTy->isIntegerTy(16) ||
- EltTy->isIntegerTy(32) || EltTy->isIntegerTy(64) ||
- EltTy->isIntegerTy(128)))
- return VT;
- }
-
- return llvm::VectorType::get(llvm::Type::getDoubleTy(getVMContext()), 2);
+ assert(isa<llvm::VectorType>(IRType) &&
+ "Trying to return a non-vector type in a vector register!");
+ return IRType;
}
/// BitsContainNoUserData - Return true if the specified [start,end) bit range
@@ -3134,10 +3115,6 @@
unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
return 16; // Natural alignment for Altivec vectors.
}
-
- bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
- return true;
- }
};
}
@@ -3287,13 +3264,42 @@
private:
static const unsigned GPRBits = 64;
ABIKind Kind;
+ bool HasQPX;
+
+ // A vector of float or double will be promoted to <4 x f32> or <4 x f64> and
+ // will be passed in a QPX register.
+ bool IsQPXVectorTy(const Type *Ty) const {
+ if (!HasQPX)
+ return false;
+
+ if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ unsigned NumElements = VT->getNumElements();
+ if (NumElements == 1)
+ return false;
+
+ if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double)) {
+ if (getContext().getTypeSize(Ty) <= 256)
+ return true;
+ } else if (VT->getElementType()->
+ isSpecificBuiltinType(BuiltinType::Float)) {
+ if (getContext().getTypeSize(Ty) <= 128)
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool IsQPXVectorTy(QualType Ty) const {
+ return IsQPXVectorTy(Ty.getTypePtr());
+ }
public:
- PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, ABIKind Kind)
- : DefaultABIInfo(CGT), Kind(Kind) {}
+ PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, ABIKind Kind, bool HasQPX)
+ : DefaultABIInfo(CGT), Kind(Kind), HasQPX(HasQPX) {}
bool isPromotableTypeForABI(QualType Ty) const;
- bool isAlignedParamType(QualType Ty) const;
+ bool isAlignedParamType(QualType Ty, bool &Align32) const;
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType Ty) const;
@@ -3318,7 +3324,8 @@
const Type *T = isSingleElementStruct(I.type, getContext());
if (T) {
const BuiltinType *BT = T->getAs<BuiltinType>();
- if ((T->isVectorType() && getContext().getTypeSize(T) == 128) ||
+ if (IsQPXVectorTy(T) ||
+ (T->isVectorType() && getContext().getTypeSize(T) == 128) ||
(BT && BT->isFloatingPoint())) {
QualType QT(T, 0);
I.info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT));
@@ -3334,10 +3341,13 @@
};
class PPC64_SVR4_TargetCodeGenInfo : public TargetCodeGenInfo {
+ bool HasQPX;
+
public:
PPC64_SVR4_TargetCodeGenInfo(CodeGenTypes &CGT,
- PPC64_SVR4_ABIInfo::ABIKind Kind)
- : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT, Kind)) {}
+ PPC64_SVR4_ABIInfo::ABIKind Kind, bool HasQPX)
+ : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT, Kind, HasQPX)),
+ HasQPX(HasQPX) {}
int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
// This is recovered from gcc output.
@@ -3347,12 +3357,13 @@
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const override;
- unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
- return 16; // Natural alignment for Altivec and VSX vectors.
- }
+ unsigned getOpenMPSimdDefaultAlignment(QualType QT) const override {
+ if (HasQPX)
+ if (const PointerType *PT = QT->getAs<PointerType>())
+ if (PT->getPointeeType()->isSpecificBuiltinType(BuiltinType::Double))
+ return 32; // Natural alignment for QPX doubles.
- bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
- return true;
+ return 16; // Natural alignment for Altivec and VSX vectors.
}
};
@@ -3371,10 +3382,6 @@
unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
return 16; // Natural alignment for Altivec vectors.
}
-
- bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
- return true;
- }
};
}
@@ -3408,15 +3415,23 @@
/// isAlignedParamType - Determine whether a type requires 16-byte
/// alignment in the parameter area.
bool
-PPC64_SVR4_ABIInfo::isAlignedParamType(QualType Ty) const {
+PPC64_SVR4_ABIInfo::isAlignedParamType(QualType Ty, bool &Align32) const {
+ Align32 = false;
+
// Complex types are passed just like their elements.
if (const ComplexType *CTy = Ty->getAs<ComplexType>())
Ty = CTy->getElementType();
// Only vector types of size 16 bytes need alignment (larger types are
// passed via reference, smaller types are not aligned).
- if (Ty->isVectorType())
+ if (IsQPXVectorTy(Ty)) {
+ if (getContext().getTypeSize(Ty) > 128)
+ Align32 = true;
+
+ return true;
+ } else if (Ty->isVectorType()) {
return getContext().getTypeSize(Ty) == 128;
+ }
// For single-element float/vector structs, we consider the whole type
// to have the same alignment requirements as its single element.
@@ -3424,7 +3439,7 @@
const Type *EltType = isSingleElementStruct(Ty, getContext());
if (EltType) {
const BuiltinType *BT = EltType->getAs<BuiltinType>();
- if ((EltType->isVectorType() &&
+ if (IsQPXVectorTy(EltType) || (EltType->isVectorType() &&
getContext().getTypeSize(EltType) == 128) ||
(BT && BT->isFloatingPoint()))
AlignAsType = EltType;
@@ -3438,13 +3453,22 @@
AlignAsType = Base;
// With special case aggregates, only vector base types need alignment.
- if (AlignAsType)
+ if (AlignAsType && IsQPXVectorTy(AlignAsType)) {
+ if (getContext().getTypeSize(AlignAsType) > 128)
+ Align32 = true;
+
+ return true;
+ } else if (AlignAsType) {
return AlignAsType->isVectorType();
+ }
// Otherwise, we only need alignment for any aggregate type that
// has an alignment requirement of >= 16 bytes.
- if (isAggregateTypeForABI(Ty) && getContext().getTypeAlign(Ty) >= 128)
+ if (isAggregateTypeForABI(Ty) && getContext().getTypeAlign(Ty) >= 128) {
+ if (HasQPX && getContext().getTypeAlign(Ty) >= 256)
+ Align32 = true;
return true;
+ }
return false;
}
@@ -3550,7 +3574,7 @@
return true;
}
if (const VectorType *VT = Ty->getAs<VectorType>()) {
- if (getContext().getTypeSize(VT) == 128)
+ if (getContext().getTypeSize(VT) == 128 || IsQPXVectorTy(Ty))
return true;
}
return false;
@@ -3576,7 +3600,7 @@
// Non-Altivec vector types are passed in GPRs (smaller than 16 bytes)
// or via reference (larger than 16 bytes).
- if (Ty->isVectorType()) {
+ if (Ty->isVectorType() && !IsQPXVectorTy(Ty)) {
uint64_t Size = getContext().getTypeSize(Ty);
if (Size > 128)
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
@@ -3590,7 +3614,9 @@
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
- uint64_t ABIAlign = isAlignedParamType(Ty)? 16 : 8;
+ bool Align32;
+ uint64_t ABIAlign = isAlignedParamType(Ty, Align32) ?
+ (Align32 ? 32 : 16) : 8;
uint64_t TyAlign = getContext().getTypeAlign(Ty) / 8;
// ELFv2 homogeneous aggregates are passed as array types.
@@ -3647,7 +3673,7 @@
// Non-Altivec vector types are returned in GPRs (smaller than 16 bytes)
// or via reference (larger than 16 bytes).
- if (RetTy->isVectorType()) {
+ if (RetTy->isVectorType() && !IsQPXVectorTy(RetTy)) {
uint64_t Size = getContext().getTypeSize(RetTy);
if (Size > 128)
return ABIArgInfo::getIndirect(0);
@@ -3704,10 +3730,13 @@
llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
// Handle types that require 16-byte alignment in the parameter save area.
- if (isAlignedParamType(Ty)) {
+ bool Align32;
+ if (isAlignedParamType(Ty, Align32)) {
llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int64Ty);
- AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt64(15));
- AddrAsInt = Builder.CreateAnd(AddrAsInt, Builder.getInt64(-16));
+ AddrAsInt = Builder.CreateAdd(AddrAsInt,
+ Builder.getInt64(Align32 ? 31 : 15));
+ AddrAsInt = Builder.CreateAnd(AddrAsInt,
+ Builder.getInt64(Align32 ? -32 : -16));
Addr = Builder.CreateIntToPtr(AddrAsInt, BP, "ap.align");
}
@@ -4485,12 +4514,6 @@
llvm::AttributeSet::FunctionIndex,
B));
}
-
- bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
- return false;
- // FIXME: backend implementation too restricted, even on Darwin.
- // return CGF.getTarget().getTriple().isOSDarwin();
- }
};
class WindowsARMTargetCodeGenInfo : public ARMTargetCodeGenInfo {
@@ -4646,14 +4669,11 @@
uint64_t ABIAlign = 4;
uint64_t TyAlign = getContext().getTypeAlign(Ty) / 8;
if (getABIKind() == ARMABIInfo::AAPCS_VFP ||
- getABIKind() == ARMABIInfo::AAPCS)
+ getABIKind() == ARMABIInfo::AAPCS)
ABIAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8);
+
if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64)) {
- // Update Allocated GPRs. Since this is only used when the size of the
- // argument is greater than 64 bytes, this will always use up any available
- // registers (of which there are 4). We also don't care about getting the
- // alignment right, because general-purpose registers cannot be back-filled.
- return ABIArgInfo::getIndirect(TyAlign, /*ByVal=*/true,
+ return ABIArgInfo::getIndirect(ABIAlign, /*ByVal=*/true,
/*Realign=*/TyAlign > ABIAlign);
}
@@ -6133,12 +6153,7 @@
// Check if Ty is a usable substitute for the coercion type.
bool isUsableType(llvm::StructType *Ty) const {
- if (Ty->getNumElements() != Elems.size())
- return false;
- for (unsigned i = 0, e = Elems.size(); i != e; ++i)
- if (Elems[i] != Ty->getElementType(i))
- return false;
- return true;
+ return llvm::makeArrayRef(Elems) == Ty->elements();
}
// Get the coercion type as a literal struct type.
@@ -6995,19 +7010,21 @@
PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv1;
if (getTarget().getABI() == "elfv2")
Kind = PPC64_SVR4_ABIInfo::ELFv2;
+ bool HasQPX = getTarget().getABI() == "elfv1-qpx";
return *(TheTargetCodeGenInfo =
- new PPC64_SVR4_TargetCodeGenInfo(Types, Kind));
+ new PPC64_SVR4_TargetCodeGenInfo(Types, Kind, HasQPX));
} else
return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types));
case llvm::Triple::ppc64le: {
assert(Triple.isOSBinFormatELF() && "PPC64 LE non-ELF not supported!");
PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv2;
- if (getTarget().getABI() == "elfv1")
+ if (getTarget().getABI() == "elfv1" || getTarget().getABI() == "elfv1-qpx")
Kind = PPC64_SVR4_ABIInfo::ELFv1;
+ bool HasQPX = getTarget().getABI() == "elfv1-qpx";
return *(TheTargetCodeGenInfo =
- new PPC64_SVR4_TargetCodeGenInfo(Types, Kind));
+ new PPC64_SVR4_TargetCodeGenInfo(Types, Kind, HasQPX));
}
case llvm::Triple::nvptx:
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index 87f1376..cc469d6 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -225,13 +225,6 @@
virtual unsigned getOpenMPSimdDefaultAlignment(QualType Type) const {
return 0;
}
-
- /// Control whether __builtin_longjmp / __builtin_setjmp are lowered to
- /// llvm.eh.sjlj.longjmp / llvm.eh.sjlj.setjmp or the normal library
- /// function.
- virtual bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const {
- return false;
- }
};
}
diff --git a/lib/Driver/CrossWindowsToolChain.cpp b/lib/Driver/CrossWindowsToolChain.cpp
index 03fe41b..82456e7 100644
--- a/lib/Driver/CrossWindowsToolChain.cpp
+++ b/lib/Driver/CrossWindowsToolChain.cpp
@@ -60,7 +60,7 @@
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
SmallString<128> ResourceDir(D.ResourceDir);
llvm::sys::path::append(ResourceDir, "include");
- addSystemInclude(DriverArgs, CC1Args, ResourceDir.str());
+ addSystemInclude(DriverArgs, CC1Args, ResourceDir);
}
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 61aaa97..0e99c58 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -57,7 +57,7 @@
CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true),
CCCUsePCH(true), SuppressMissingInputWarning(false) {
- Name = llvm::sys::path::stem(ClangExecutable);
+ Name = llvm::sys::path::filename(ClangExecutable);
Dir = llvm::sys::path::parent_path(ClangExecutable);
// Compute the path to the resource directory.
@@ -551,6 +551,9 @@
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating run script: " + Script + " " + EC.message();
} else {
+ ScriptOS << "# Crash reproducer for " << getClangFullVersion() << "\n"
+ << "# Original command: ";
+ Cmd.Print(ScriptOS, "\n", /*Quote=*/true);
Cmd.Print(ScriptOS, "\n", /*Quote=*/true, &CrashInfo);
Diag(clang::diag::note_drv_command_failed_diag_msg) << Script;
}
@@ -976,7 +979,7 @@
SmallString<64> Path(Value);
if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory)) {
- if (!llvm::sys::path::is_absolute(Path.str())) {
+ if (!llvm::sys::path::is_absolute(Path)) {
SmallString<64> Directory(WorkDir->getValue());
llvm::sys::path::append(Directory, Value);
Path.assign(Directory);
@@ -989,7 +992,7 @@
if (D.IsCLMode() && llvm::sys::Process::FindInEnvPath("LIB", Value))
return true;
- D.Diag(clang::diag::err_drv_no_such_file) << Path.str();
+ D.Diag(clang::diag::err_drv_no_such_file) << Path;
return false;
}
@@ -2027,6 +2030,9 @@
ToolChain *&TC = ToolChains[Target.str()];
if (!TC) {
switch (Target.getOS()) {
+ case llvm::Triple::CloudABI:
+ TC = new toolchains::CloudABI(*this, Target, Args);
+ break;
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
case llvm::Triple::IOS:
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 66434cf..6d18a41 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -34,7 +34,7 @@
Executable(_Executable), Arguments(_Arguments),
ResponseFile(nullptr) {}
-static int skipArgs(const char *Flag) {
+static int skipArgs(const char *Flag, bool HaveCrashVFS) {
// These flags are all of the form -Flag <Arg> and are treated as two
// arguments. Therefore, we need to skip the flag and the next argument.
bool Res = llvm::StringSwitch<bool>(Flag)
@@ -43,9 +43,11 @@
.Cases("-fdebug-compilation-dir", "-idirafter", true)
.Cases("-include", "-include-pch", "-internal-isystem", true)
.Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
- .Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true)
+ .Cases("-iwithprefixbefore", "-isystem", "-iquote", true)
.Cases("-resource-dir", "-serialize-diagnostic-file", true)
.Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
+ // Some include flags shouldn't be skipped if we have a crash VFS
+ .Case("-isysroot", !HaveCrashVFS)
.Default(false);
// Match found.
@@ -164,11 +166,12 @@
if (StringRef(Args[I]).equals("-main-file-name"))
MainFilename = Args[I + 1];
+ bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty();
for (size_t i = 0, e = Args.size(); i < e; ++i) {
const char *const Arg = Args[i];
if (CrashInfo) {
- if (int Skip = skipArgs(Arg)) {
+ if (int Skip = skipArgs(Arg, HaveCrashVFS)) {
i += Skip - 1;
continue;
} else if (llvm::sys::path::filename(Arg) == MainFilename &&
@@ -185,7 +188,7 @@
PrintArg(OS, Arg, Quote);
}
- if (CrashInfo && !CrashInfo->VFSPath.empty()) {
+ if (CrashInfo && HaveCrashVFS) {
OS << ' ';
PrintArg(OS, "-ivfsoverlay", Quote);
OS << ' ';
diff --git a/lib/Driver/MSVCToolChain.cpp b/lib/Driver/MSVCToolChain.cpp
index 874e540..7739cb0 100644
--- a/lib/Driver/MSVCToolChain.cpp
+++ b/lib/Driver/MSVCToolChain.cpp
@@ -424,7 +424,7 @@
const char *subfolder) const {
llvm::SmallString<128> path(folder);
llvm::sys::path::append(path, subfolder);
- addSystemInclude(DriverArgs, CC1Args, path.str());
+ addSystemInclude(DriverArgs, CC1Args, path);
}
void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
@@ -435,7 +435,7 @@
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
SmallString<128> P(getDriver().ResourceDir);
llvm::sys::path::append(P, "include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
+ addSystemInclude(DriverArgs, CC1Args, P);
}
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
diff --git a/lib/Driver/Multilib.cpp b/lib/Driver/Multilib.cpp
index 1f5d62f..8acda67 100644
--- a/lib/Driver/Multilib.cpp
+++ b/lib/Driver/Multilib.cpp
@@ -151,41 +151,23 @@
}
MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2) {
- std::vector<Multilib> Ms;
- Ms.push_back(M1);
- Ms.push_back(M2);
- return Either(Ms);
+ return Either({M1, M2});
}
MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
const Multilib &M3) {
- std::vector<Multilib> Ms;
- Ms.push_back(M1);
- Ms.push_back(M2);
- Ms.push_back(M3);
- return Either(Ms);
+ return Either({M1, M2, M3});
}
MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
const Multilib &M3, const Multilib &M4) {
- std::vector<Multilib> Ms;
- Ms.push_back(M1);
- Ms.push_back(M2);
- Ms.push_back(M3);
- Ms.push_back(M4);
- return Either(Ms);
+ return Either({M1, M2, M3, M4});
}
MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
const Multilib &M3, const Multilib &M4,
const Multilib &M5) {
- std::vector<Multilib> Ms;
- Ms.push_back(M1);
- Ms.push_back(M2);
- Ms.push_back(M3);
- Ms.push_back(M4);
- Ms.push_back(M5);
- return Either(Ms);
+ return Either({M1, M2, M3, M4, M5});
}
static Multilib compose(const Multilib &Base, const Multilib &New) {
@@ -197,7 +179,7 @@
llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
New.includeSuffix());
- Multilib Composed(GCCSuffix.str(), OSSuffix.str(), IncludeSuffix.str());
+ Multilib Composed(GCCSuffix, OSSuffix, IncludeSuffix);
Multilib::flags_list &Flags = Composed.flags();
@@ -207,8 +189,7 @@
return Composed;
}
-MultilibSet &
-MultilibSet::Either(const std::vector<Multilib> &MultilibSegments) {
+MultilibSet &MultilibSet::Either(ArrayRef<Multilib> MultilibSegments) {
multilib_list Composed;
if (Multilibs.empty())
@@ -229,30 +210,23 @@
return *this;
}
-MultilibSet &MultilibSet::FilterOut(const MultilibSet::FilterCallback &F) {
+MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
filterInPlace(F, Multilibs);
return *this;
}
-MultilibSet &MultilibSet::FilterOut(std::string Regex) {
- class REFilter : public MultilibSet::FilterCallback {
- mutable llvm::Regex R;
+MultilibSet &MultilibSet::FilterOut(const char *Regex) {
+ llvm::Regex R(Regex);
+#ifndef NDEBUG
+ std::string Error;
+ if (!R.isValid(Error)) {
+ llvm::errs() << Error;
+ llvm_unreachable("Invalid regex!");
+ }
+#endif
- public:
- REFilter(std::string Regex) : R(Regex) {}
- bool operator()(const Multilib &M) const override {
- std::string Error;
- if (!R.isValid(Error)) {
- llvm::errs() << Error;
- assert(false);
- return false;
- }
- return R.match(M.gccSuffix());
- }
- };
-
- REFilter REF(Regex);
- filterInPlace(REF, Multilibs);
+ filterInPlace([&R](const Multilib &M) { return R.match(M.gccSuffix()); },
+ Multilibs);
return *this;
}
@@ -262,38 +236,29 @@
Multilibs.insert(Multilibs.end(), Other.begin(), Other.end());
}
+static bool isFlagEnabled(StringRef Flag) {
+ char Indicator = Flag.front();
+ assert(Indicator == '+' || Indicator == '-');
+ return Indicator == '+';
+}
+
bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const {
- class FilterFlagsMismatch : public MultilibSet::FilterCallback {
- llvm::StringMap<bool> FlagSet;
+ llvm::StringMap<bool> FlagSet;
- public:
- FilterFlagsMismatch(const std::vector<std::string> &Flags) {
- // Stuff all of the flags into the FlagSet such that a true mappend
- // indicates the flag was enabled, and a false mappend indicates the
- // flag was disabled
- for (StringRef Flag : Flags)
- FlagSet[Flag.substr(1)] = isFlagEnabled(Flag);
- }
- bool operator()(const Multilib &M) const override {
- for (StringRef Flag : M.flags()) {
- llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1));
- if (SI != FlagSet.end())
- if (SI->getValue() != isFlagEnabled(Flag))
- return true;
- }
- return false;
- }
- private:
- bool isFlagEnabled(StringRef Flag) const {
- char Indicator = Flag.front();
- assert(Indicator == '+' || Indicator == '-');
- return Indicator == '+';
- }
- };
+ // Stuff all of the flags into the FlagSet such that a true mappend indicates
+ // the flag was enabled, and a false mappend indicates the flag was disabled.
+ for (StringRef Flag : Flags)
+ FlagSet[Flag.substr(1)] = isFlagEnabled(Flag);
- FilterFlagsMismatch FlagsMismatch(Flags);
-
- multilib_list Filtered = filterCopy(FlagsMismatch, Multilibs);
+ multilib_list Filtered = filterCopy([&FlagSet](const Multilib &M) {
+ for (StringRef Flag : M.flags()) {
+ llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1));
+ if (SI != FlagSet.end())
+ if (SI->getValue() != isFlagEnabled(Flag))
+ return true;
+ }
+ return false;
+ }, Multilibs);
if (Filtered.size() == 0) {
return false;
@@ -313,19 +278,15 @@
OS << M << "\n";
}
-MultilibSet::multilib_list
-MultilibSet::filterCopy(const MultilibSet::FilterCallback &F,
- const multilib_list &Ms) {
+MultilibSet::multilib_list MultilibSet::filterCopy(FilterCallback F,
+ const multilib_list &Ms) {
multilib_list Copy(Ms);
filterInPlace(F, Copy);
return Copy;
}
-void MultilibSet::filterInPlace(const MultilibSet::FilterCallback &F,
- multilib_list &Ms) {
- Ms.erase(std::remove_if(Ms.begin(), Ms.end(),
- [&F](const Multilib &M) { return F(M); }),
- Ms.end());
+void MultilibSet::filterInPlace(FilterCallback F, multilib_list &Ms) {
+ Ms.erase(std::remove_if(Ms.begin(), Ms.end(), F), Ms.end());
}
raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) {
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index 11b9288..fb907a7 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -24,7 +24,7 @@
namespace {
/// Assign ordinals to possible values of -fsanitize= flag.
/// We use the ordinal values as bit positions within \c SanitizeKind.
-enum SanitizeOrdinal {
+enum SanitizeOrdinal : uint64_t {
#define SANITIZER(NAME, ID) SO_##ID,
#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
#include "clang/Basic/Sanitizers.def"
@@ -35,26 +35,26 @@
/// 1) set of sanitizers each sanitizer group expands into.
/// 2) set of sanitizers sharing a specific property (e.g.
/// all sanitizers with zero-base shadow).
-enum SanitizeKind {
-#define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
+enum SanitizeKind : uint64_t {
+#define SANITIZER(NAME, ID) ID = 1ULL << SO_##ID,
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
-ID = ALIAS, ID##Group = 1 << SO_##ID##Group,
+ ID = ALIAS, ID##Group = 1ULL << SO_##ID##Group,
#include "clang/Basic/Sanitizers.def"
NeedsUbsanRt = Undefined | Integer,
NotAllowedWithTrap = Vptr,
RequiresPIE = Memory | DataFlow,
NeedsUnwindTables = Address | Thread | Memory | DataFlow,
- SupportsCoverage = Address | Memory | Leak | Undefined | Integer,
+ SupportsCoverage = Address | Memory | Leak | Undefined | Integer | DataFlow,
RecoverableByDefault = Undefined | Integer,
Unrecoverable = Address | Unreachable | Return,
LegacyFsanitizeRecoverMask = Undefined | Integer,
- NeedsLTO = CFIVptr,
+ NeedsLTO = CFIDerivedCast | CFIUnrelatedCast | CFIVptr,
};
}
/// Returns true if set of \p Sanitizers contain at least one sanitizer from
/// \p Kinds.
-static bool hasOneOf(const clang::SanitizerSet &Sanitizers, unsigned Kinds) {
+static bool hasOneOf(const clang::SanitizerSet &Sanitizers, uint64_t Kinds) {
#define SANITIZER(NAME, ID) \
if (Sanitizers.has(clang::SanitizerKind::ID) && (Kinds & ID)) \
return true;
@@ -63,14 +63,14 @@
}
/// Adds all sanitizers from \p Kinds to \p Sanitizers.
-static void addAllOf(clang::SanitizerSet &Sanitizers, unsigned Kinds) {
+static void addAllOf(clang::SanitizerSet &Sanitizers, uint64_t Kinds) {
#define SANITIZER(NAME, ID) \
if (Kinds & ID) \
Sanitizers.set(clang::SanitizerKind::ID, true);
#include "clang/Basic/Sanitizers.def"
}
-static unsigned toSanitizeKind(clang::SanitizerKind K) {
+static uint64_t toSanitizeKind(clang::SanitizerKind K) {
#define SANITIZER(NAME, ID) \
if (K == clang::SanitizerKind::ID) \
return ID;
@@ -81,11 +81,11 @@
/// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
/// Returns a member of the \c SanitizeKind enumeration, or \c 0
/// if \p Value is not known.
-static unsigned parseValue(const char *Value);
+static uint64_t parseValue(const char *Value);
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
/// invalid components. Returns OR of members of \c SanitizeKind enumeration.
-static unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A,
+static uint64_t parseArgValues(const Driver &D, const llvm::opt::Arg *A,
bool DiagnoseErrors);
/// Produce an argument string from ArgList \p Args, which shows how it
@@ -94,7 +94,7 @@
/// would produce "-fsanitize=vptr".
static std::string lastArgumentForMask(const Driver &D,
const llvm::opt::ArgList &Args,
- unsigned Mask);
+ uint64_t Mask);
static std::string lastArgumentForKind(const Driver &D,
const llvm::opt::ArgList &Args,
@@ -106,7 +106,7 @@
/// a value in \p Mask. For instance, the argument
/// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
/// "-fsanitize=alignment".
-static std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask);
+static std::string describeSanitizeArg(const llvm::opt::Arg *A, uint64_t Mask);
/// Produce a string containing comma-separated names of sanitizers in \p
/// Sanitizers set.
@@ -114,9 +114,9 @@
/// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
/// this group enables.
-static unsigned expandGroups(unsigned Kinds);
+static uint64_t expandGroups(uint64_t Kinds);
-static unsigned getToolchainUnsupportedKinds(const ToolChain &TC) {
+static uint64_t getToolchainUnsupportedKinds(const ToolChain &TC) {
bool IsFreeBSD = TC.getTriple().getOS() == llvm::Triple::FreeBSD;
bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux;
bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86;
@@ -124,7 +124,7 @@
bool IsMIPS64 = TC.getTriple().getArch() == llvm::Triple::mips64 ||
TC.getTriple().getArch() == llvm::Triple::mips64el;
- unsigned Unsupported = 0;
+ uint64_t Unsupported = 0;
if (!(IsLinux && (IsX86_64 || IsMIPS64))) {
Unsupported |= Memory | DataFlow;
}
@@ -137,6 +137,27 @@
return Unsupported;
}
+static bool getDefaultBlacklist(const Driver &D, uint64_t Kinds,
+ std::string &BLPath) {
+ const char *BlacklistFile = nullptr;
+ if (Kinds & SanitizeKind::Address)
+ BlacklistFile = "asan_blacklist.txt";
+ else if (Kinds & SanitizeKind::Memory)
+ BlacklistFile = "msan_blacklist.txt";
+ else if (Kinds & SanitizeKind::Thread)
+ BlacklistFile = "tsan_blacklist.txt";
+ else if (Kinds & SanitizeKind::DataFlow)
+ BlacklistFile = "dfsan_abilist.txt";
+
+ if (BlacklistFile) {
+ clang::SmallString<64> Path(D.ResourceDir);
+ llvm::sys::path::append(Path, BlacklistFile);
+ BLPath = Path.str();
+ return true;
+ }
+ return false;
+}
+
bool SanitizerArgs::needsUbsanRt() const {
return !UbsanTrapOnError && hasOneOf(Sanitizers, NeedsUbsanRt);
}
@@ -150,7 +171,7 @@
}
bool SanitizerArgs::needsLTO() const {
- return hasOneOf(Sanitizers, CFIVptr);
+ return hasOneOf(Sanitizers, NeedsLTO);
}
void SanitizerArgs::clear() {
@@ -169,13 +190,13 @@
SanitizerArgs::SanitizerArgs(const ToolChain &TC,
const llvm::opt::ArgList &Args) {
clear();
- unsigned AllRemove = 0; // During the loop below, the accumulated set of
+ uint64_t AllRemove = 0; // During the loop below, the accumulated set of
// sanitizers disabled by the current sanitizer
// argument or any argument after it.
- unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now.
+ uint64_t DiagnosedKinds = 0; // All Kinds we have diagnosed up to now.
// Used to deduplicate diagnostics.
- unsigned Kinds = 0;
- unsigned NotSupported = getToolchainUnsupportedKinds(TC);
+ uint64_t Kinds = 0;
+ uint64_t NotSupported = getToolchainUnsupportedKinds(TC);
ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
const Driver &D = TC.getDriver();
@@ -184,14 +205,14 @@
const auto *Arg = *I;
if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
Arg->claim();
- unsigned Add = parseArgValues(D, Arg, true);
+ uint64_t Add = parseArgValues(D, Arg, true);
// Avoid diagnosing any sanitizer which is disabled later.
Add &= ~AllRemove;
// At this point we have not expanded groups, so any unsupported
// sanitizers in Add are those which have been explicitly enabled.
// Diagnose them.
- if (unsigned KindsToDiagnose = Add & NotSupported & ~DiagnosedKinds) {
+ if (uint64_t KindsToDiagnose = Add & NotSupported & ~DiagnosedKinds) {
// Only diagnose the new kinds.
std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
D.Diag(diag::err_drv_unsupported_opt_for_target)
@@ -232,38 +253,73 @@
Kinds |= Add;
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
Arg->claim();
- unsigned Remove = parseArgValues(D, Arg, true);
+ uint64_t Remove = parseArgValues(D, Arg, true);
AllRemove |= expandGroups(Remove);
}
}
- addAllOf(Sanitizers, Kinds);
// We disable the vptr sanitizer if it was enabled by group expansion but RTTI
// is disabled.
- if (Sanitizers.has(SanitizerKind::Vptr) &&
+ if ((Kinds & SanitizeKind::Vptr) &&
(RTTIMode == ToolChain::RM_DisabledImplicitly ||
RTTIMode == ToolChain::RM_DisabledExplicitly)) {
Kinds &= ~SanitizeKind::Vptr;
- Sanitizers.set(SanitizerKind::Vptr, 0);
}
+ // Warn about undefined sanitizer options that require runtime support.
+ UbsanTrapOnError =
+ Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
+ options::OPT_fno_sanitize_undefined_trap_on_error, false);
+ if (UbsanTrapOnError && (Kinds & SanitizeKind::NotAllowedWithTrap)) {
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForMask(D, Args, NotAllowedWithTrap)
+ << "-fsanitize-undefined-trap-on-error";
+ Kinds &= ~SanitizeKind::NotAllowedWithTrap;
+ }
+
+ // Warn about incompatible groups of sanitizers.
+ std::pair<uint64_t, uint64_t> IncompatibleGroups[] = {
+ std::make_pair(SanitizeKind::Address, SanitizeKind::Thread),
+ std::make_pair(SanitizeKind::Address, SanitizeKind::Memory),
+ std::make_pair(SanitizeKind::Thread, SanitizeKind::Memory),
+ std::make_pair(SanitizeKind::Leak, SanitizeKind::Thread),
+ std::make_pair(SanitizeKind::Leak, SanitizeKind::Memory),
+ std::make_pair(SanitizeKind::NeedsUbsanRt, SanitizeKind::Thread),
+ std::make_pair(SanitizeKind::NeedsUbsanRt, SanitizeKind::Memory)};
+ for (auto G : IncompatibleGroups) {
+ uint64_t Group = G.first;
+ if (Kinds & Group) {
+ if (uint64_t Incompatible = Kinds & G.second) {
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForMask(D, Args, Group)
+ << lastArgumentForMask(D, Args, Incompatible);
+ Kinds &= ~Incompatible;
+ }
+ }
+ }
+ // FIXME: Currently -fsanitize=leak is silently ignored in the presence of
+ // -fsanitize=address. Perhaps it should print an error, or perhaps
+ // -f(-no)sanitize=leak should change whether leak detection is enabled by
+ // default in ASan?
+
// Parse -f(no-)?sanitize-recover flags.
- unsigned RecoverableKinds = RecoverableByDefault;
- unsigned DiagnosedUnrecoverableKinds = 0;
+ uint64_t RecoverableKinds = RecoverableByDefault;
+ uint64_t DiagnosedUnrecoverableKinds = 0;
for (const auto *Arg : Args) {
+ const char *DeprecatedReplacement = nullptr;
if (Arg->getOption().matches(options::OPT_fsanitize_recover)) {
- // FIXME: Add deprecation notice, and then remove this flag.
+ DeprecatedReplacement = "-fsanitize-recover=undefined,integer";
RecoverableKinds |= expandGroups(LegacyFsanitizeRecoverMask);
Arg->claim();
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) {
- // FIXME: Add deprecation notice, and then remove this flag.
+ DeprecatedReplacement = "-fno-sanitize-recover=undefined,integer";
RecoverableKinds &= ~expandGroups(LegacyFsanitizeRecoverMask);
Arg->claim();
} else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
- unsigned Add = parseArgValues(D, Arg, true);
+ uint64_t Add = parseArgValues(D, Arg, true);
// Report error if user explicitly tries to recover from unrecoverable
// sanitizer.
- if (unsigned KindsToDiagnose =
+ if (uint64_t KindsToDiagnose =
Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) {
SanitizerSet SetToDiagnose;
addAllOf(SetToDiagnose, KindsToDiagnose);
@@ -277,57 +333,19 @@
RecoverableKinds &= ~expandGroups(parseArgValues(D, Arg, true));
Arg->claim();
}
+ if (DeprecatedReplacement) {
+ D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
+ << DeprecatedReplacement;
+ }
}
RecoverableKinds &= Kinds;
RecoverableKinds &= ~Unrecoverable;
- addAllOf(RecoverableSanitizers, RecoverableKinds);
-
- UbsanTrapOnError =
- Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
- options::OPT_fno_sanitize_undefined_trap_on_error, false);
-
- // Warn about undefined sanitizer options that require runtime support.
- if (UbsanTrapOnError && hasOneOf(Sanitizers, NotAllowedWithTrap)) {
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << lastArgumentForMask(D, Args, NotAllowedWithTrap)
- << "-fsanitize-undefined-trap-on-error";
- }
-
- // Check for incompatible sanitizers.
- bool NeedsAsan = Sanitizers.has(SanitizerKind::Address);
- bool NeedsTsan = Sanitizers.has(SanitizerKind::Thread);
- bool NeedsMsan = Sanitizers.has(SanitizerKind::Memory);
- bool NeedsLsan = Sanitizers.has(SanitizerKind::Leak);
- if (NeedsAsan && NeedsTsan)
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, SanitizerKind::Address)
- << lastArgumentForKind(D, Args, SanitizerKind::Thread);
- if (NeedsAsan && NeedsMsan)
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, SanitizerKind::Address)
- << lastArgumentForKind(D, Args, SanitizerKind::Memory);
- if (NeedsTsan && NeedsMsan)
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, SanitizerKind::Thread)
- << lastArgumentForKind(D, Args, SanitizerKind::Memory);
- if (NeedsLsan && NeedsTsan)
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, SanitizerKind::Leak)
- << lastArgumentForKind(D, Args, SanitizerKind::Thread);
- if (NeedsLsan && NeedsMsan)
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, SanitizerKind::Leak)
- << lastArgumentForKind(D, Args, SanitizerKind::Memory);
- // FIXME: Currently -fsanitize=leak is silently ignored in the presence of
- // -fsanitize=address. Perhaps it should print an error, or perhaps
- // -f(-no)sanitize=leak should change whether leak detection is enabled by
- // default in ASan?
// Setup blacklist files.
// Add default blacklist from resource directory.
{
std::string BLPath;
- if (getDefaultBlacklist(D, BLPath) && llvm::sys::fs::exists(BLPath))
+ if (getDefaultBlacklist(D, Kinds, BLPath) && llvm::sys::fs::exists(BLPath))
BlacklistFiles.push_back(BLPath);
}
// Parse -f(no-)sanitize-blacklist options.
@@ -354,7 +372,7 @@
}
// Parse -f[no-]sanitize-memory-track-origins[=level] options.
- if (NeedsMsan) {
+ if (Kinds & SanitizeKind::Memory) {
if (Arg *A =
Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
options::OPT_fsanitize_memory_track_origins,
@@ -375,7 +393,7 @@
}
// Parse -fsanitize-coverage=N. Currently one of asan/msan/lsan is required.
- if (hasOneOf(Sanitizers, SupportsCoverage)) {
+ if (Kinds & SanitizeKind::SupportsCoverage) {
if (Arg *A = Args.getLastArg(options::OPT_fsanitize_coverage)) {
StringRef S = A->getValue();
// Legal values are 0..4.
@@ -385,7 +403,7 @@
}
}
- if (NeedsAsan) {
+ if (Kinds & SanitizeKind::Address) {
AsanSharedRuntime =
Args.hasArg(options::OPT_shared_libasan) ||
(TC.getTriple().getEnvironment() == llvm::Triple::Android);
@@ -420,6 +438,10 @@
// Parse -link-cxx-sanitizer flag.
LinkCXXRuntimes =
Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();
+
+ // Finally, initialize the set of available and recoverable sanitizers.
+ addAllOf(Sanitizers, Kinds);
+ addAllOf(RecoverableSanitizers, RecoverableKinds);
}
static std::string toString(const clang::SanitizerSet &Sanitizers) {
@@ -472,28 +494,8 @@
CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
}
-bool SanitizerArgs::getDefaultBlacklist(const Driver &D, std::string &BLPath) {
- const char *BlacklistFile = nullptr;
- if (Sanitizers.has(SanitizerKind::Address))
- BlacklistFile = "asan_blacklist.txt";
- else if (Sanitizers.has(SanitizerKind::Memory))
- BlacklistFile = "msan_blacklist.txt";
- else if (Sanitizers.has(SanitizerKind::Thread))
- BlacklistFile = "tsan_blacklist.txt";
- else if (Sanitizers.has(SanitizerKind::DataFlow))
- BlacklistFile = "dfsan_abilist.txt";
-
- if (BlacklistFile) {
- SmallString<64> Path(D.ResourceDir);
- llvm::sys::path::append(Path, BlacklistFile);
- BLPath = Path.str();
- return true;
- }
- return false;
-}
-
-unsigned parseValue(const char *Value) {
- unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
+uint64_t parseValue(const char *Value) {
+ uint64_t ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
#define SANITIZER(NAME, ID) .Case(NAME, ID)
#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group)
#include "clang/Basic/Sanitizers.def"
@@ -501,24 +503,24 @@
return ParsedKind;
}
-unsigned expandGroups(unsigned Kinds) {
+uint64_t expandGroups(uint64_t Kinds) {
#define SANITIZER(NAME, ID)
#define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID;
#include "clang/Basic/Sanitizers.def"
return Kinds;
}
-unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A,
+uint64_t parseArgValues(const Driver &D, const llvm::opt::Arg *A,
bool DiagnoseErrors) {
assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) &&
"Invalid argument in parseArgValues!");
- unsigned Kinds = 0;
- for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
- const char *Value = A->getValue(I);
- unsigned Kind;
+ uint64_t Kinds = 0;
+ for (int i = 0, n = A->getNumValues(); i != n; ++i) {
+ const char *Value = A->getValue(i);
+ uint64_t Kind;
// Special case: don't accept -fsanitize=all.
if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
0 == strcmp("all", Value))
@@ -536,33 +538,33 @@
}
std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
- unsigned Mask) {
+ uint64_t Mask) {
for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
E = Args.rend();
I != E; ++I) {
const auto *Arg = *I;
if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
- unsigned AddKinds = expandGroups(parseArgValues(D, Arg, false));
+ uint64_t AddKinds = expandGroups(parseArgValues(D, Arg, false));
if (AddKinds & Mask)
return describeSanitizeArg(Arg, Mask);
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
- unsigned RemoveKinds = expandGroups(parseArgValues(D, Arg, false));
+ uint64_t RemoveKinds = expandGroups(parseArgValues(D, Arg, false));
Mask &= ~RemoveKinds;
}
}
llvm_unreachable("arg list didn't provide expected value");
}
-std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask) {
+std::string describeSanitizeArg(const llvm::opt::Arg *A, uint64_t Mask) {
assert(A->getOption().matches(options::OPT_fsanitize_EQ)
&& "Invalid argument in describeSanitizerArg!");
std::string Sanitizers;
- for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
- if (expandGroups(parseValue(A->getValue(I))) & Mask) {
+ for (int i = 0, n = A->getNumValues(); i != n; ++i) {
+ if (expandGroups(parseValue(A->getValue(i))) & Mask) {
if (!Sanitizers.empty())
Sanitizers += ",";
- Sanitizers += A->getValue(I);
+ Sanitizers += A->getValue(i);
}
}
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 5feeda4..52e8603 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -48,7 +48,7 @@
// On the PS4, turning on c++ exceptions turns on rtti.
// We're assuming that, if we see -fexceptions, rtti gets turned on.
- Arg *Exceptions = Args.getLastArg(
+ Arg *Exceptions = Args.getLastArgNoClaim(
options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions,
options::OPT_fexceptions, options::OPT_fno_exceptions);
if (Exceptions &&
@@ -297,10 +297,7 @@
// '-mbig-endian'/'-EB'.
if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
options::OPT_mbig_endian)) {
- if (A->getOption().matches(options::OPT_mlittle_endian))
- IsBigEndian = false;
- else
- IsBigEndian = true;
+ IsBigEndian = !A->getOption().matches(options::OPT_mlittle_endian);
}
// Thumb2 is the default for V7 on Darwin.
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 93e6db8..9606df6 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -302,8 +302,8 @@
// For now, allow missing resource libraries to support developers who may
// not have compiler-rt checked out or integrated into their build (unless
// we explicitly force linking with this library).
- if (AlwaysLink || llvm::sys::fs::exists(P.str()))
- CmdArgs.push_back(Args.MakeArgString(P.str()));
+ if (AlwaysLink || llvm::sys::fs::exists(P))
+ CmdArgs.push_back(Args.MakeArgString(P));
// Adding the rpaths might negatively interact when other rpaths are involved,
// so we should make sure we add the rpaths last, after all user-specified
@@ -320,10 +320,26 @@
// Add the path to the resource dir to rpath to support using the dylib
// from the default location without copying.
CmdArgs.push_back("-rpath");
- CmdArgs.push_back(Args.MakeArgString(Dir.str()));
+ CmdArgs.push_back(Args.MakeArgString(Dir));
}
}
+void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ StringRef Sanitizer) const {
+ if (!Args.hasArg(options::OPT_dynamiclib) &&
+ !Args.hasArg(options::OPT_bundle)) {
+ // Sanitizer runtime libraries requires C++.
+ AddCXXStdlibLibArgs(Args, CmdArgs);
+ }
+ assert(isTargetMacOS() || isTargetIOSSimulator());
+ StringRef OS = isTargetMacOS() ? "osx" : "iossim";
+ AddLinkRuntimeLib(Args, CmdArgs, (Twine("libclang_rt.") + Sanitizer + "_" +
+ OS + "_dynamic.dylib").str(),
+ /*AlwaysLink*/ true, /*IsEmbedded*/ false,
+ /*AddRPath*/ true);
+}
+
void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Darwin only supports the compiler-rt based runtime libraries.
@@ -368,47 +384,26 @@
const SanitizerArgs &Sanitize = getSanitizerArgs();
- // Add Ubsan runtime library, if required.
- if (Sanitize.needsUbsanRt()) {
- // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds.
- if (isTargetIOSBased()) {
+ if (Sanitize.needsAsanRt()) {
+ if (!isTargetMacOS() && !isTargetIOSSimulator()) {
+ // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds.
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
- << "-fsanitize=undefined";
+ << "-fsanitize=address";
} else {
- assert(isTargetMacOS() && "unexpected non OS X target");
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ubsan_osx.a", true);
-
- // The Ubsan runtime library requires C++.
- AddCXXStdlibLibArgs(Args, CmdArgs);
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
}
}
- // Add ASAN runtime library, if required. Dynamic libraries and bundles
- // should not be linked with the runtime library.
- if (Sanitize.needsAsanRt()) {
- // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds.
- if (isTargetIPhoneOS()) {
+ if (Sanitize.needsUbsanRt()) {
+ if (!isTargetMacOS() && !isTargetIOSSimulator()) {
+ // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds.
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
- << "-fsanitize=address";
+ << "-fsanitize=undefined";
} else {
- if (!Args.hasArg(options::OPT_dynamiclib) &&
- !Args.hasArg(options::OPT_bundle)) {
- // The ASAN runtime library requires C++.
- AddCXXStdlibLibArgs(Args, CmdArgs);
- }
- if (isTargetMacOS()) {
- AddLinkRuntimeLib(Args, CmdArgs,
- "libclang_rt.asan_osx_dynamic.dylib",
- /*AlwaysLink*/ true, /*IsEmbedded*/ false,
- /*AddRPath*/ true);
- } else {
- if (isTargetIOSSimulator()) {
- AddLinkRuntimeLib(Args, CmdArgs,
- "libclang_rt.asan_iossim_dynamic.dylib",
- /*AlwaysLink*/ true, /*IsEmbedded*/ false,
- /*AddRPath*/ true);
- }
- }
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan");
+ // Add explicit dependcy on -lc++abi, as -lc++ doesn't re-export
+ // all RTTI-related symbols that UBSan uses.
+ CmdArgs.push_back("-lc++abi");
}
}
@@ -599,11 +594,11 @@
SmallString<128> P(A->getValue());
llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib");
- if (!llvm::sys::fs::exists(P.str())) {
+ if (!llvm::sys::fs::exists(P)) {
llvm::sys::path::remove_filename(P);
llvm::sys::path::append(P, "libstdc++.6.dylib");
- if (llvm::sys::fs::exists(P.str())) {
- CmdArgs.push_back(Args.MakeArgString(P.str()));
+ if (llvm::sys::fs::exists(P)) {
+ CmdArgs.push_back(Args.MakeArgString(P));
return;
}
}
@@ -646,8 +641,8 @@
// For now, allow missing resource libraries to support developers who may
// not have compiler-rt checked out or integrated into their build.
- if (llvm::sys::fs::exists(P.str()))
- CmdArgs.push_back(Args.MakeArgString(P.str()));
+ if (llvm::sys::fs::exists(P))
+ CmdArgs.push_back(Args.MakeArgString(P));
}
DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args,
@@ -1498,11 +1493,12 @@
namespace {
// Filter to remove Multilibs that don't exist as a suffix to Path
-class FilterNonExistent : public MultilibSet::FilterCallback {
- std::string Base;
+class FilterNonExistent {
+ StringRef Base;
+
public:
- FilterNonExistent(std::string Base) : Base(Base) {}
- bool operator()(const Multilib &M) const override {
+ FilterNonExistent(StringRef Base) : Base(Base) {}
+ bool operator()(const Multilib &M) {
return !llvm::sys::fs::exists(Base + M.gccSuffix() + "/crtbegin.o");
}
};
@@ -2249,7 +2245,7 @@
llvm::sys::path::append(IncludeDir, "hexagon/include/c++/");
llvm::sys::path::append(IncludeDir, Ver);
- addSystemInclude(DriverArgs, CC1Args, IncludeDir.str());
+ addSystemInclude(DriverArgs, CC1Args, IncludeDir);
}
ToolChain::CXXStdlibType
@@ -2344,6 +2340,36 @@
return false;
}
+// CloudABI - CloudABI tool chain which can call ld(1) directly.
+
+CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ SmallString<128> P(getDriver().Dir);
+ llvm::sys::path::append(P, "..", getTriple().str(), "lib");
+ getFilePaths().push_back(P.str());
+}
+
+void CloudABI::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) &&
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ SmallString<128> P(getDriver().Dir);
+ llvm::sys::path::append(P, "..", getTriple().str(), "include/c++/v1");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+}
+
+void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
+ CmdArgs.push_back("-lunwind");
+}
+
+Tool *CloudABI::buildLinker() const { return new tools::cloudabi::Link(*this); }
+
/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.
OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
@@ -3147,7 +3173,7 @@
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
SmallString<128> P(D.ResourceDir);
llvm::sys::path::append(P, "include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
+ addSystemInclude(DriverArgs, CC1Args, P);
}
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
@@ -3171,7 +3197,7 @@
// Add include directories specific to the selected multilib set and multilib.
if (GCCInstallation.isValid()) {
- auto Callback = Multilibs.includeDirsCallback();
+ const auto &Callback = Multilibs.includeDirsCallback();
if (Callback) {
const auto IncludePaths = Callback(GCCInstallation.getInstallPath(),
GCCInstallation.getTriple().str(),
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 90893c3..ebd23d1 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -494,6 +494,11 @@
AddLinkARCArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
/// }
+
+private:
+ void AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ StringRef Sanitizer) const;
};
class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
@@ -507,6 +512,31 @@
llvm::opt::ArgStringList &CC1Args) const override;
};
+class LLVM_LIBRARY_VISIBILITY CloudABI : public Generic_ELF {
+public:
+ CloudABI(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ bool HasNativeLLVMSupport() const override { return true; }
+
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
+
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args)
+ const override {
+ return ToolChain::CST_Libcxx;
+ }
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ bool isPIEDefault() const override { return false; }
+
+protected:
+ Tool *buildLinker() const override;
+};
+
class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC {
public:
Solaris(const Driver &D, const llvm::Triple &Triple,
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index b0e581b..ed1bd3e 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -24,6 +24,7 @@
#include "clang/Driver/SanitizerArgs.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Util.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
@@ -323,8 +324,9 @@
if (A->getOption().matches(options::OPT_M) ||
A->getOption().matches(options::OPT_MD))
CmdArgs.push_back("-sys-header-deps");
-
- if (isa<PrecompileJobAction>(JA))
+ if ((isa<PrecompileJobAction>(JA) &&
+ !Args.hasArg(options::OPT_fno_module_file_deps)) ||
+ Args.hasArg(options::OPT_fmodule_file_deps))
CmdArgs.push_back("-module-file-deps");
}
@@ -381,19 +383,19 @@
P += ".dummy";
if (UsePCH) {
llvm::sys::path::replace_extension(P, "pch");
- if (llvm::sys::fs::exists(P.str()))
+ if (llvm::sys::fs::exists(P))
FoundPCH = true;
}
if (!FoundPCH) {
llvm::sys::path::replace_extension(P, "pth");
- if (llvm::sys::fs::exists(P.str()))
+ if (llvm::sys::fs::exists(P))
FoundPTH = true;
}
if (!FoundPCH && !FoundPTH) {
llvm::sys::path::replace_extension(P, "gch");
- if (llvm::sys::fs::exists(P.str())) {
+ if (llvm::sys::fs::exists(P)) {
FoundPCH = UsePCH;
FoundPTH = !UsePCH;
}
@@ -406,12 +408,12 @@
CmdArgs.push_back("-include-pch");
else
CmdArgs.push_back("-include-pth");
- CmdArgs.push_back(Args.MakeArgString(P.str()));
+ CmdArgs.push_back(Args.MakeArgString(P));
continue;
} else {
// Ignore the PCH if not first on command line and emit warning.
D.Diag(diag::warn_drv_pch_not_first_include)
- << P.str() << A->getAsString(Args);
+ << P << A->getAsString(Args);
}
}
}
@@ -1315,9 +1317,22 @@
ABIName = A->getValue();
} else if (getToolChain().getTriple().isOSLinux())
switch(getToolChain().getArch()) {
- case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64: {
+ // When targeting a processor that supports QPX, or if QPX is
+ // specifically enabled, default to using the ABI that supports QPX (so
+ // long as it is not specifically disabled).
+ bool HasQPX = false;
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ HasQPX = A->getValue() == StringRef("a2q");
+ HasQPX = Args.hasFlag(options::OPT_mqpx, options::OPT_mno_qpx, HasQPX);
+ if (HasQPX) {
+ ABIName = "elfv1-qpx";
+ break;
+ }
+
ABIName = "elfv1";
break;
+ }
case llvm::Triple::ppc64le:
ABIName = "elfv2";
break;
@@ -1548,8 +1563,7 @@
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU));
}
-static void getX86TargetFeatures(const Driver & D,
- const llvm::Triple &Triple,
+static void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<const char *> &Features) {
if (Triple.getArchName() == "x86_64h") {
@@ -1563,7 +1577,7 @@
Features.push_back("-fsgsbase");
}
- // Add features to comply with gcc on Android
+ // Add features to be compatible with gcc for Android.
if (Triple.getEnvironment() == llvm::Triple::Android) {
if (Triple.getArch() == llvm::Triple::x86_64) {
Features.push_back("+sse4.2");
@@ -1572,7 +1586,7 @@
Features.push_back("+ssse3");
}
- // Set features according to the -arch flag on MSVC
+ // Set features according to the -arch flag on MSVC.
if (Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) {
StringRef Arch = A->getValue();
bool ArchUsed = false;
@@ -2269,13 +2283,16 @@
StaticRuntimes.push_back("tsan");
// WARNING: UBSan should always go last.
if (SanArgs.needsUbsanRt()) {
- // If UBSan is not combined with another sanitizer, we need to pull in
- // sanitizer_common explicitly.
- if (StaticRuntimes.empty())
- HelperStaticRuntimes.push_back("san");
- StaticRuntimes.push_back("ubsan");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("ubsan_cxx");
+ // Check if UBSan is combined with another sanitizers.
+ if (StaticRuntimes.empty()) {
+ StaticRuntimes.push_back("ubsan_standalone");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("ubsan_standalone_cxx");
+ } else {
+ StaticRuntimes.push_back("ubsan");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("ubsan_cxx");
+ }
}
}
@@ -2468,24 +2485,17 @@
CmdArgs.push_back(types::getTypeName(Input.getType()));
}
-static std::string getMSCompatibilityVersion(const char *VersionStr) {
- unsigned Version;
- if (StringRef(VersionStr).getAsInteger(10, Version))
- return "0";
-
+static VersionTuple getMSCompatibilityVersion(unsigned Version) {
if (Version < 100)
- return llvm::utostr_32(Version) + ".0";
+ return VersionTuple(Version);
if (Version < 10000)
- return llvm::utostr_32(Version / 100) + "." +
- llvm::utostr_32(Version % 100);
+ return VersionTuple(Version / 100, Version % 100);
unsigned Build = 0, Factor = 1;
for ( ; Version > 10000; Version = Version / 10, Factor = Factor * 10)
Build = Build + (Version % 10) * Factor;
- return llvm::utostr_32(Version / 100) + "." +
- llvm::utostr_32(Version % 100) + "." +
- llvm::utostr_32(Build);
+ return VersionTuple(Version / 100, Version % 100, Build);
}
// Claim options we don't want to warn if they are unused. We do this for
@@ -2850,6 +2860,8 @@
else
CmdArgs.push_back(Args.MakeArgString(getToolChain().getThreadModel()));
+ Args.AddLastArg(CmdArgs, options::OPT_fveclib);
+
if (!Args.hasFlag(options::OPT_fmerge_all_constants,
options::OPT_fno_merge_all_constants))
CmdArgs.push_back("-fno-merge-all-constants");
@@ -3306,13 +3318,16 @@
CmdArgs.push_back("-generate-type-units");
}
+ // CloudABI uses -ffunction-sections and -fdata-sections by default.
+ bool UseSeparateSections = Triple.getOS() == llvm::Triple::CloudABI;
+
if (Args.hasFlag(options::OPT_ffunction_sections,
- options::OPT_fno_function_sections, false)) {
+ options::OPT_fno_function_sections, UseSeparateSections)) {
CmdArgs.push_back("-ffunction-sections");
}
if (Args.hasFlag(options::OPT_fdata_sections,
- options::OPT_fno_data_sections, false)) {
+ options::OPT_fno_data_sections, UseSeparateSections)) {
CmdArgs.push_back("-fdata-sections");
}
@@ -3361,10 +3376,10 @@
} else {
CoverageFilename = llvm::sys::path::filename(Output.getBaseInput());
}
- if (llvm::sys::path::is_relative(CoverageFilename.str())) {
+ if (llvm::sys::path::is_relative(CoverageFilename)) {
SmallString<128> Pwd;
if (!llvm::sys::fs::current_path(Pwd)) {
- llvm::sys::path::append(Pwd, CoverageFilename.str());
+ llvm::sys::path::append(Pwd, CoverageFilename);
CoverageFilename.swap(Pwd);
}
}
@@ -3447,6 +3462,7 @@
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_all);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readonly_property);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readwrite_property);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property_dot_syntax);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_annotation);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_instancetype);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_nsmacros);
@@ -4032,8 +4048,9 @@
ToolChain::RTTIMode RTTIMode = getToolChain().getRTTIMode();
- if (RTTIMode == ToolChain::RM_DisabledExplicitly ||
- RTTIMode == ToolChain::RM_DisabledImplicitly)
+ if (KernelOrKext || (types::isCXX(InputType) &&
+ (RTTIMode == ToolChain::RM_DisabledExplicitly ||
+ RTTIMode == ToolChain::RM_DisabledImplicitly)))
CmdArgs.push_back("-fno-rtti");
// -fshort-enums=0 is default for all architectures except Hexagon.
@@ -4048,11 +4065,6 @@
isSignedCharDefault(getToolChain().getTriple())))
CmdArgs.push_back("-fno-signed-char");
- // -fthreadsafe-static is default.
- if (!Args.hasFlag(options::OPT_fthreadsafe_statics,
- options::OPT_fno_threadsafe_statics))
- CmdArgs.push_back("-fno-threadsafe-statics");
-
// -fuse-cxa-atexit is default.
if (!Args.hasFlag(options::OPT_fuse_cxa_atexit,
options::OPT_fno_use_cxa_atexit,
@@ -4080,9 +4092,11 @@
true))))
CmdArgs.push_back("-fms-compatibility");
- // -fms-compatibility-version=17.00 is default.
+ // -fms-compatibility-version=18.00 is default.
+ VersionTuple MSVT;
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
- IsWindowsMSVC) || Args.hasArg(options::OPT_fmsc_version) ||
+ IsWindowsMSVC) ||
+ Args.hasArg(options::OPT_fmsc_version) ||
Args.hasArg(options::OPT_fms_compatibility_version)) {
const Arg *MSCVersion = Args.getLastArg(options::OPT_fmsc_version);
const Arg *MSCompatibilityVersion =
@@ -4093,16 +4107,23 @@
<< MSCVersion->getAsString(Args)
<< MSCompatibilityVersion->getAsString(Args);
- std::string Ver;
- if (MSCompatibilityVersion)
- Ver = Args.getLastArgValue(options::OPT_fms_compatibility_version);
- else if (MSCVersion)
- Ver = getMSCompatibilityVersion(MSCVersion->getValue());
+ if (MSCompatibilityVersion) {
+ if (MSVT.tryParse(MSCompatibilityVersion->getValue()))
+ D.Diag(diag::err_drv_invalid_value)
+ << MSCompatibilityVersion->getAsString(Args)
+ << MSCompatibilityVersion->getValue();
+ } else if (MSCVersion) {
+ unsigned Version = 0;
+ if (StringRef(MSCVersion->getValue()).getAsInteger(10, Version))
+ D.Diag(diag::err_drv_invalid_value) << MSCVersion->getAsString(Args)
+ << MSCVersion->getValue();
+ MSVT = getMSCompatibilityVersion(Version);
+ } else {
+ MSVT = VersionTuple(18);
+ }
- if (Ver.empty())
- CmdArgs.push_back("-fms-compatibility-version=18.00");
- else
- CmdArgs.push_back(Args.MakeArgString("-fms-compatibility-version=" + Ver));
+ CmdArgs.push_back(
+ Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString()));
}
// -fno-borland-extensions is default.
@@ -4110,6 +4131,13 @@
options::OPT_fno_borland_extensions, false))
CmdArgs.push_back("-fborland-extensions");
+ // -fthreadsafe-static is default, except for MSVC compatibility versions less
+ // than 19.
+ if (!Args.hasFlag(options::OPT_fthreadsafe_statics,
+ options::OPT_fno_threadsafe_statics,
+ !IsWindowsMSVC || MSVT.getMajor() >= 19))
+ CmdArgs.push_back("-fno-threadsafe-statics");
+
// -fno-delayed-template-parsing is default, except for Windows where MSVC STL
// needs it.
if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
@@ -4215,6 +4243,10 @@
}
}
+ if (Args.hasFlag(options::OPT_fapplication_extension,
+ options::OPT_fno_application_extension, false))
+ CmdArgs.push_back("-fapplication-extension");
+
// Handle GCC-style exception args.
if (!C.getDriver().IsCLMode())
addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext,
@@ -4228,6 +4260,12 @@
options::OPT_fno_assume_sane_operator_new))
CmdArgs.push_back("-fno-assume-sane-operator-new");
+ // -fsized-deallocation is off by default, as it is an ABI-breaking change for
+ // most platforms.
+ if (Args.hasFlag(options::OPT_fsized_deallocation,
+ options::OPT_fno_sized_deallocation, false))
+ CmdArgs.push_back("-fsized-deallocation");
+
// -fconstant-cfstrings is default, and may be subject to argument translation
// on Darwin.
if (!Args.hasFlag(options::OPT_fconstant_cfstrings,
@@ -4582,7 +4620,7 @@
Flags += EscapedArg;
}
CmdArgs.push_back("-dwarf-debug-flags");
- CmdArgs.push_back(Args.MakeArgString(Flags.str()));
+ CmdArgs.push_back(Args.MakeArgString(Flags));
}
// Add the split debug info name to the command lines here so we
@@ -5042,7 +5080,7 @@
Flags += EscapedArg;
}
CmdArgs.push_back("-dwarf-debug-flags");
- CmdArgs.push_back(Args.MakeArgString(Flags.str()));
+ CmdArgs.push_back(Args.MakeArgString(Flags));
}
// FIXME: Add -static support, once we have it.
@@ -5542,8 +5580,9 @@
.Cases("arm9e", "arm926ej-s", "arm946e-s", "v5e")
.Cases("arm966e-s", "arm968e-s", "arm10e", "v5e")
.Cases("arm1020e", "arm1022e", "xscale", "iwmmxt", "v5e")
- .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
- .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
+ .Cases("arm1136j-s", "arm1136jf-s", "v6")
+ .Cases("arm1176jz-s", "arm1176jzf-s", "v6k")
+ .Cases("mpcorenovfp", "mpcore", "v6k")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
.Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
.Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait", "v7")
@@ -5564,7 +5603,7 @@
StringRef Suffix = getLLVMArchSuffixForARM(getARMCPUForMArch(Args, Triple));
const char *LinkFlag = llvm::StringSwitch<const char *>(Suffix)
.Cases("v4", "v4t", "v5", "v5e", nullptr)
- .Cases("v6", "v6t2", nullptr)
+ .Cases("v6", "v6k", "v6t2", nullptr)
.Default("--be8");
if (LinkFlag)
@@ -5689,6 +5728,76 @@
return Args.MakeArgString(Res + ".d");
}
+void cloudabi::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const ToolChain &ToolChain = getToolChain();
+ const Driver &D = ToolChain.getDriver();
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ // CloudABI only supports static linkage.
+ CmdArgs.push_back("-Bstatic");
+ CmdArgs.push_back("--eh-frame-hdr");
+ CmdArgs.push_back("--gc-sections");
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ const ToolChain::path_list &Paths = ToolChain.getFilePaths();
+ for (const auto &Path : Paths)
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_s);
+ Args.AddAllArgs(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_r);
+
+ if (D.IsUsingLTO(ToolChain, Args))
+ AddGoldPlugin(ToolChain, Args, CmdArgs);
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (D.CCCIsCXX())
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lcompiler_rt");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
+}
+
void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -5810,6 +5919,12 @@
if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137)
CmdArgs.push_back("-export_dynamic");
+ // If we are using App Extension restrictions, pass a flag to the linker
+ // telling it that the compiled code has been audited.
+ if (Args.hasFlag(options::OPT_fapplication_extension,
+ options::OPT_fno_application_extension, false))
+ CmdArgs.push_back("-application_extension");
+
// If we are using LTO, then automatically create a temporary file path for
// the linker to use, so that it's lifetime will extend past a possible
// dsymutil step.
@@ -6110,6 +6225,16 @@
CmdArgs.push_back(Args.MakeArgString(std::string("-F") +
(*it)->getValue()));
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (Arg *A = Args.getLastArg(options::OPT_fveclib)) {
+ if (A->getValue() == StringRef("Accelerate")) {
+ CmdArgs.push_back("-framework");
+ CmdArgs.push_back("Accelerate");
+ }
+ }
+ }
+
const char *Exec =
Args.MakeArgString(getToolChain().GetLinkerPath());
std::unique_ptr<Command> Cmd =
@@ -7209,47 +7334,64 @@
ArgStringList CmdArgs;
bool NeedsKPIC = false;
+ switch (getToolChain().getArch()) {
+ default:
+ break;
// Add --32/--64 to make sure we get the format we want.
// This is incomplete
- if (getToolChain().getArch() == llvm::Triple::x86) {
+ case llvm::Triple::x86:
CmdArgs.push_back("--32");
- } else if (getToolChain().getArch() == llvm::Triple::x86_64) {
+ break;
+ case llvm::Triple::x86_64:
if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32)
CmdArgs.push_back("--x32");
else
CmdArgs.push_back("--64");
- } else if (getToolChain().getArch() == llvm::Triple::ppc) {
+ break;
+ case llvm::Triple::ppc:
CmdArgs.push_back("-a32");
CmdArgs.push_back("-mppc");
CmdArgs.push_back("-many");
- } else if (getToolChain().getArch() == llvm::Triple::ppc64) {
+ break;
+ case llvm::Triple::ppc64:
CmdArgs.push_back("-a64");
CmdArgs.push_back("-mppc64");
CmdArgs.push_back("-many");
- } else if (getToolChain().getArch() == llvm::Triple::ppc64le) {
+ break;
+ case llvm::Triple::ppc64le:
CmdArgs.push_back("-a64");
CmdArgs.push_back("-mppc64");
CmdArgs.push_back("-many");
CmdArgs.push_back("-mlittle-endian");
- } else if (getToolChain().getArch() == llvm::Triple::sparc) {
+ break;
+ case llvm::Triple::sparc:
CmdArgs.push_back("-32");
CmdArgs.push_back("-Av8plusa");
NeedsKPIC = true;
- } else if (getToolChain().getArch() == llvm::Triple::sparcv9) {
+ break;
+ case llvm::Triple::sparcv9:
CmdArgs.push_back("-64");
CmdArgs.push_back("-Av9a");
NeedsKPIC = true;
- } else if (getToolChain().getArch() == llvm::Triple::arm ||
- getToolChain().getArch() == llvm::Triple::armeb) {
- StringRef MArch = getToolChain().getArchName();
- if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb: {
+ const llvm::Triple &Triple = getToolChain().getTriple();
+ switch (Triple.getSubArch()) {
+ case llvm::Triple::ARMSubArch_v7:
CmdArgs.push_back("-mfpu=neon");
- if (MArch == "armv8" || MArch == "armv8a" || MArch == "armv8-a" ||
- MArch == "armebv8" || MArch == "armebv8a" || MArch == "armebv8-a")
+ break;
+ case llvm::Triple::ARMSubArch_v8:
CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8");
+ break;
+ default:
+ break;
+ }
StringRef ARMFloatABI = tools::arm::getARMFloatABI(
- getToolChain().getDriver(), Args, getToolChain().getTriple());
+ getToolChain().getDriver(), Args, Triple);
CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=" + ARMFloatABI));
Args.AddLastArg(CmdArgs, options::OPT_march_EQ);
@@ -7264,10 +7406,12 @@
else
Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ);
Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ);
- } else if (getToolChain().getArch() == llvm::Triple::mips ||
- getToolChain().getArch() == llvm::Triple::mipsel ||
- getToolChain().getArch() == llvm::Triple::mips64 ||
- getToolChain().getArch() == llvm::Triple::mips64el) {
+ break;
+ }
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el: {
StringRef CPUName;
StringRef ABIName;
mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
@@ -7351,11 +7495,15 @@
options::OPT_mno_odd_spreg);
NeedsKPIC = true;
- } else if (getToolChain().getArch() == llvm::Triple::systemz) {
+ break;
+ }
+ case llvm::Triple::systemz: {
// Always pass an -march option, since our default of z10 is later
// than the GNU assembler's default.
StringRef CPUName = getSystemZTargetCPU(Args);
CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
+ break;
+ }
}
if (NeedsKPIC)
@@ -7564,11 +7712,7 @@
const bool IsPIE =
!Args.hasArg(options::OPT_shared) &&
!Args.hasArg(options::OPT_static) &&
- (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault() ||
- // On Android every code is PIC so every executable is PIE
- // Cannot use isPIEDefault here since otherwise
- // PIE only logic will be enabled during compilation
- isAndroid);
+ (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault());
ArgStringList CmdArgs;
@@ -7696,6 +7840,8 @@
CmdArgs.push_back("-Bdynamic");
CmdArgs.push_back("-lm");
}
+ // Silence warnings when linking C code with a C++ '-stdlib' argument.
+ Args.ClaimAllArgs(options::OPT_stdlib_EQ);
if (!Args.hasArg(options::OPT_nostdlib)) {
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
@@ -8055,8 +8201,8 @@
if (!llvm::sys::Process::GetEnv("LIB")) {
// If the VC environment hasn't been configured (perhaps because the user
// did not run vcvarsall), try to build a consistent link environment. If
- // the environment variable is set however, assume the user knows what he's
- // doing.
+ // the environment variable is set however, assume the user knows what
+ // they're doing.
std::string VisualStudioDir;
const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
if (MSVC.getVisualStudioInstallDir(VisualStudioDir)) {
@@ -8090,14 +8236,16 @@
if (Args.hasArg(options::OPT_g_Group))
CmdArgs.push_back("-debug");
- bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd);
+ bool DLL = Args.hasArg(options::OPT__SLASH_LD,
+ options::OPT__SLASH_LDd,
+ options::OPT_shared);
if (DLL) {
CmdArgs.push_back(Args.MakeArgString("-dll"));
SmallString<128> ImplibName(Output.getFilename());
llvm::sys::path::replace_extension(ImplibName, "lib");
CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") +
- ImplibName.str()));
+ ImplibName));
}
if (TC.getSanitizerArgs().needsAsanRt()) {
@@ -8214,7 +8362,7 @@
}
}
- // Flags for which clang-cl have an alias.
+ // Flags for which clang-cl has an alias.
// FIXME: How can we ensure this stays in sync with relevant clang-cl options?
if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR,
@@ -8234,7 +8382,8 @@
if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only))
CmdArgs.push_back("/Z7");
- std::vector<std::string> Includes = Args.getAllArgValues(options::OPT_include);
+ std::vector<std::string> Includes =
+ Args.getAllArgValues(options::OPT_include);
for (const auto &Include : Includes)
CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Include));
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 93a19fb..5161557 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -248,6 +248,22 @@
bool hasPPCAbiArg(const llvm::opt::ArgList &Args, const char *Value);
}
+ /// cloudabi -- Directly call GNU Binutils linker
+namespace cloudabi {
+class LLVM_LIBRARY_VISIBILITY Link : public GnuTool {
+public:
+ Link(const ToolChain &TC) : GnuTool("cloudabi::Link", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace cloudabi
+
namespace darwin {
llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str);
void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str);
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 6ee764c..7b28145 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -85,7 +85,7 @@
case TY_Asm:
case TY_C: case TY_PP_C:
case TY_CL:
- case TY_CUDA:
+ case TY_CUDA: case TY_PP_CUDA:
case TY_ObjC: case TY_PP_ObjC: case TY_PP_ObjC_Alias:
case TY_CXX: case TY_PP_CXX:
case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias:
@@ -122,7 +122,7 @@
case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias:
case TY_CXXHeader: case TY_PP_CXXHeader:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
- case TY_CUDA:
+ case TY_CUDA: case TY_PP_CUDA:
return true;
}
}
@@ -153,6 +153,7 @@
.Case("cl", TY_CL)
.Case("cp", TY_CXX)
.Case("cu", TY_CUDA)
+ .Case("cui", TY_PP_CUDA)
.Case("hh", TY_CXXHeader)
.Case("ll", TY_LLVM_IR)
.Case("hpp", TY_CXXHeader)
diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp
index 1c66cb8..a5b5875 100644
--- a/lib/Edit/EditedSource.cpp
+++ b/lib/Edit/EditedSource.cpp
@@ -135,7 +135,7 @@
StrVec += text;
}
- return commitInsert(OrigLoc, Offs, StrVec.str(), beforePreviousInsertions);
+ return commitInsert(OrigLoc, Offs, StrVec, beforePreviousInsertions);
}
void EditedSource::commitRemove(SourceLocation OrigLoc,
@@ -360,14 +360,14 @@
continue;
}
- applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts);
+ applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts);
CurOffs = offs;
StrVec = act.Text;
CurLen = act.RemoveLen;
CurEnd = CurOffs.getWithOffset(CurLen);
}
- applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts);
+ applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts);
}
void EditedSource::clearRewrites() {
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 7c2d916..83fd6ee 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -221,8 +221,7 @@
if (startsSegmentOfBuilderTypeCall(Current) &&
(State.Stack.back().CallContinuation != 0 ||
- (State.Stack.back().BreakBeforeParameter &&
- State.Stack.back().ContainsUnwrappedBuilder)))
+ State.Stack.back().BreakBeforeParameter))
return true;
// The following could be precomputed as they do not depend on the state.
@@ -307,7 +306,9 @@
else if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
State.Column + Spaces + Current.ColumnWidth)
State.Stack.back().ColonPos =
- State.Stack.back().Indent + Current.LongestObjCSelectorName;
+ std::max(State.FirstIndent + Style.ContinuationIndentWidth,
+ State.Stack.back().Indent) +
+ Current.LongestObjCSelectorName;
else
State.Stack.back().ColonPos = State.Column + Spaces + Current.ColumnWidth;
}
@@ -321,6 +322,8 @@
if (startsSegmentOfBuilderTypeCall(Current))
State.Stack.back().ContainsUnwrappedBuilder = true;
+ if (Current.is(TT_LambdaArrow))
+ State.Stack.back().NoLineBreak = true;
if (Current.isMemberAccess() && Previous.is(tok::r_paren) &&
(Previous.MatchingParen &&
(Previous.TotalLength - Previous.MatchingParen->TotalLength > 10))) {
@@ -580,7 +583,7 @@
return State.Stack.back().StartOfArraySubscripts;
return ContinuationIndent;
}
- if (NextNonComment->is(TT_StartOfName) ||
+ if (NextNonComment->isOneOf(TT_StartOfName, TT_PointerOrReference) ||
Previous.isOneOf(tok::coloncolon, tok::equal)) {
return ContinuationIndent;
}
@@ -648,12 +651,6 @@
State.Stack.back().BreakBeforeParameter = false;
}
- // In ObjC method declaration we align on the ":" of parameters, but we need
- // to ensure that we indent parameters on subsequent lines by at least our
- // continuation indent width.
- if (Current.is(TT_ObjCMethodSpecifier))
- State.Stack.back().Indent += Style.ContinuationIndentWidth;
-
// Insert scopes created by fake parenthesis.
const FormatToken *Previous = Current.getPreviousNonComment();
@@ -722,7 +719,8 @@
// 'return', assignments or opening <({[. The indentation for these cases
// is special cased.
bool SkipFirstExtraIndent =
- (Previous && (Previous->opensScope() || Previous->is(tok::kw_return) ||
+ (Previous && (Previous->opensScope() ||
+ Previous->isOneOf(tok::semi, tok::kw_return) ||
(Previous->getPrecedence() == prec::Assignment &&
Style.AlignOperands) ||
Previous->is(TT_ObjCMethodExpr)));
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 035dc73..b44ea5d 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -642,11 +642,12 @@
if (tryMergeTemplateString())
return;
- static tok::TokenKind JSIdentity[] = {tok::equalequal, tok::equal};
- static tok::TokenKind JSNotIdentity[] = {tok::exclaimequal, tok::equal};
- static tok::TokenKind JSShiftEqual[] = {tok::greater, tok::greater,
- tok::greaterequal};
- static tok::TokenKind JSRightArrow[] = {tok::equal, tok::greater};
+ static const tok::TokenKind JSIdentity[] = {tok::equalequal, tok::equal};
+ static const tok::TokenKind JSNotIdentity[] = {tok::exclaimequal,
+ tok::equal};
+ static const tok::TokenKind JSShiftEqual[] = {tok::greater, tok::greater,
+ tok::greaterequal};
+ static const tok::TokenKind JSRightArrow[] = {tok::equal, tok::greater};
// FIXME: We probably need to change token type to mimic operator with the
// correct priority.
if (tryMergeTokens(JSIdentity))
@@ -861,6 +862,8 @@
String->OriginalColumn = Macro->OriginalColumn;
String->ColumnWidth = encoding::columnWidthWithTabs(
String->TokenText, String->OriginalColumn, Style.TabWidth, Encoding);
+ String->NewlinesBefore = Macro->NewlinesBefore;
+ String->HasUnescapedNewline = Macro->HasUnescapedNewline;
Tokens.pop_back();
Tokens.pop_back();
@@ -1527,7 +1530,8 @@
static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
if (FileName.endswith(".java")) {
return FormatStyle::LK_Java;
- } else if (FileName.endswith_lower(".js")) {
+ } else if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts")) {
+ // JavaScript or TypeScript.
return FormatStyle::LK_JavaScript;
} else if (FileName.endswith_lower(".proto") ||
FileName.endswith_lower(".protodevel")) {
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index 14f45a4..cef7a63 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -321,7 +321,8 @@
/// \brief Returns \c true if this is a "." or "->" accessing a member.
bool isMemberAccess() const {
return isOneOf(tok::arrow, tok::period, tok::arrowstar) &&
- !isOneOf(TT_DesignatedInitializerPeriod, TT_TrailingReturnArrow);
+ !isOneOf(TT_DesignatedInitializerPeriod, TT_TrailingReturnArrow,
+ TT_LambdaArrow);
}
bool isUnaryOperator() const {
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index fa086a9..e0da80c 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -526,8 +526,10 @@
Tok->Type = TT_ObjCForIn;
break;
case tok::comma:
- if (Contexts.back().FirstStartOfName)
+ if (Contexts.back().FirstStartOfName && Contexts.size() == 1) {
Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;
+ Line.IsMultiVariableDeclStmt = true;
+ }
if (Contexts.back().InCtorInitializer)
Tok->Type = TT_CtorInitializerComma;
if (Contexts.back().IsForEachMacro)
@@ -765,6 +767,8 @@
if (!Previous)
break;
}
+ if (Previous->opensScope())
+ break;
if (Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator) &&
Previous->isOneOf(tok::star, tok::amp, tok::ampamp) &&
Previous->Previous && Previous->Previous->isNot(tok::equal))
@@ -1117,8 +1121,8 @@
const AdditionalKeywords &Keywords;
};
-static int PrecedenceUnaryOperator = prec::PointerToMember + 1;
-static int PrecedenceArrowAndPeriod = prec::PointerToMember + 2;
+static const int PrecedenceUnaryOperator = prec::PointerToMember + 1;
+static const int PrecedenceArrowAndPeriod = prec::PointerToMember + 2;
/// \brief Parses binary expressions by inserting fake parenthesis based on
/// operator precedence.
@@ -1533,6 +1537,10 @@
return Style.PenaltyReturnTypeOnItsOwnLine;
return 200;
}
+ if (Right.is(TT_PointerOrReference))
+ return 190;
+ if (Right.is(TT_TrailingReturnArrow))
+ return 110;
if (Left.is(tok::equal) && Right.is(tok::l_brace))
return 150;
if (Left.is(TT_CastRParen))
@@ -1616,7 +1624,6 @@
if (Left.is(TT_ConditionalExpr))
return prec::Conditional;
prec::Level Level = Left.getPrecedence();
-
if (Level != prec::Unknown)
return Level;
@@ -1671,15 +1678,19 @@
TT_FunctionDeclarationName)))) &&
(Left.Tok.isLiteral() ||
(!Left.isOneOf(TT_PointerOrReference, tok::l_paren) &&
- Style.PointerAlignment != FormatStyle::PAS_Left));
+ (Style.PointerAlignment != FormatStyle::PAS_Left ||
+ Line.IsMultiVariableDeclStmt)));
if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) &&
(!Left.is(TT_PointerOrReference) ||
- Style.PointerAlignment != FormatStyle::PAS_Right))
+ (Style.PointerAlignment != FormatStyle::PAS_Right &&
+ !Line.IsMultiVariableDeclStmt)))
return true;
if (Left.is(TT_PointerOrReference))
return Right.Tok.isLiteral() || Right.is(TT_BlockComment) ||
(!Right.isOneOf(TT_PointerOrReference, tok::l_paren) &&
- Style.PointerAlignment != FormatStyle::PAS_Right && Left.Previous &&
+ (Style.PointerAlignment != FormatStyle::PAS_Right &&
+ !Line.IsMultiVariableDeclStmt) &&
+ Left.Previous &&
!Left.Previous->isOneOf(tok::l_paren, tok::coloncolon));
if (Right.is(tok::star) && Left.is(tok::l_paren))
return false;
@@ -1767,6 +1778,13 @@
if ((Left.is(tok::l_brace) || Right.is(tok::r_brace)) &&
Line.First->isOneOf(Keywords.kw_import, tok::kw_export))
return false;
+ if (Left.is(TT_TemplateCloser) &&
+ !Right.isOneOf(tok::l_brace, tok::comma, tok::l_square,
+ Keywords.kw_implements, Keywords.kw_extends))
+ // Type assertions ('<type>expr') are not followed by whitespace. Other
+ // locations that should have whitespace following are identified by the
+ // above set of follower tokens.
+ return false;
} else if (Style.Language == FormatStyle::LK_Java) {
if (Left.is(tok::r_square) && Right.is(tok::l_brace))
return true;
@@ -1870,9 +1888,12 @@
// intention is to insert a line break after it in order to make shuffling
// around entries easier.
const FormatToken *BeforeClosingBrace = nullptr;
- if (Left.is(tok::l_brace) && Left.BlockKind != BK_Block && Left.MatchingParen)
+ if (Left.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) &&
+ Left.BlockKind != BK_Block && Left.MatchingParen)
BeforeClosingBrace = Left.MatchingParen->Previous;
- else if (Right.is(tok::r_brace) && Right.BlockKind != BK_Block)
+ else if (Right.MatchingParen &&
+ Right.MatchingParen->isOneOf(tok::l_brace,
+ TT_ArrayInitializerLSquare))
BeforeClosingBrace = &Left;
if (BeforeClosingBrace && (BeforeClosingBrace->is(tok::comma) ||
BeforeClosingBrace->isTrailingComment()))
@@ -1937,7 +1958,13 @@
Left.Previous->is(tok::char_constant))
return true;
if (Left.is(TT_DictLiteral) && Left.is(tok::l_brace) &&
- Left.NestingLevel == 0)
+ Left.NestingLevel == 0 && Left.Previous &&
+ Left.Previous->is(tok::equal) &&
+ Line.First->isOneOf(tok::identifier, Keywords.kw_import,
+ tok::kw_export) &&
+ // kw_var is a pseudo-token that's a tok::identifier, so matches above.
+ !Line.First->is(Keywords.kw_var))
+ // Enum style object literal.
return true;
} else if (Style.Language == FormatStyle::LK_Java) {
if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next &&
@@ -1967,9 +1994,15 @@
return false;
if (Left.isOneOf(TT_JavaAnnotation, TT_LeadingJavaAnnotation))
return !Right.is(tok::l_paren);
+ if (Right.is(TT_PointerOrReference))
+ return Line.IsMultiVariableDeclStmt ||
+ (Style.PointerAlignment == FormatStyle::PAS_Right &&
+ (!Right.Next || Right.Next->isNot(TT_FunctionDeclarationName)));
if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) ||
Right.is(tok::kw_operator))
return true;
+ if (Left.is(TT_PointerOrReference))
+ return false;
if (Right.isTrailingComment())
// We rely on MustBreakBefore being set correctly here as we should not
// change the "binding" behavior of a comment.
@@ -2003,8 +2036,7 @@
return true;
if (Right.is(TT_RangeBasedForLoopColon))
return false;
- if (Left.isOneOf(TT_PointerOrReference, TT_TemplateCloser,
- TT_UnaryOperator) ||
+ if (Left.isOneOf(TT_TemplateCloser, TT_UnaryOperator) ||
Left.is(tok::kw_operator))
return false;
if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
@@ -2065,8 +2097,9 @@
return true;
return Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
tok::kw_class, tok::kw_struct) ||
- Right.isMemberAccess() || Right.is(TT_TrailingReturnArrow) ||
- Right.isOneOf(tok::lessless, tok::colon, tok::l_square, tok::at) ||
+ Right.isMemberAccess() ||
+ Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow, tok::lessless,
+ tok::colon, tok::l_square, tok::at) ||
(Left.is(tok::r_paren) &&
Right.isOneOf(tok::identifier, tok::kw_const)) ||
(Left.is(tok::l_paren) && !Right.is(tok::r_paren));
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index 94ed1d1..a948cdb 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -42,8 +42,8 @@
: First(Line.Tokens.front().Tok), Level(Line.Level),
InPPDirective(Line.InPPDirective),
MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
- Affected(false), LeadingEmptyLinesAffected(false),
- ChildrenAffected(false) {
+ IsMultiVariableDeclStmt(false), Affected(false),
+ LeadingEmptyLinesAffected(false), ChildrenAffected(false) {
assert(!Line.Tokens.empty());
// Calculate Next and Previous for all tokens. Note that we must overwrite
@@ -90,6 +90,7 @@
bool InPPDirective;
bool MustBeDeclaration;
bool MightBeFunctionDecl;
+ bool IsMultiVariableDeclStmt;
/// \c True if this line should be formatted, i.e. intersects directly or
/// indirectly with one of the input ranges.
diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp
index 8e6809f..6c92d79 100644
--- a/lib/Format/UnwrappedLineFormatter.cpp
+++ b/lib/Format/UnwrappedLineFormatter.cpp
@@ -35,10 +35,18 @@
tryFitMultipleLinesInOne(unsigned Indent,
SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
+ // Can't join the last line with anything.
+ if (I + 1 == E)
+ return 0;
// We can never merge stuff if there are trailing line comments.
const AnnotatedLine *TheLine = *I;
if (TheLine->Last->is(TT_LineComment))
return 0;
+ if (I[1]->Type == LT_Invalid || I[1]->First->MustBreakBefore)
+ return 0;
+ if (TheLine->InPPDirective &&
+ (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline))
+ return 0;
if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
return 0;
@@ -51,9 +59,6 @@
? 0
: Limit - TheLine->Last->TotalLength;
- if (I + 1 == E || I[1]->Type == LT_Invalid || I[1]->First->MustBreakBefore)
- return 0;
-
// FIXME: TheLine->Level != 0 might or might not be the right check to do.
// If necessary, change to something smarter.
bool MergeShortFunctions =
@@ -121,8 +126,6 @@
unsigned Limit) {
if (Limit == 0)
return 0;
- if (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline)
- return 0;
if (I + 2 != E && I[2]->InPPDirective && !I[2]->First->HasUnescapedNewline)
return 0;
if (1 + I[1]->Last->TotalLength > Limit)
@@ -512,7 +515,8 @@
++Newlines;
// Remove empty lines after access specifiers.
- if (PreviousLine && PreviousLine->First->isAccessSpecifier())
+ if (PreviousLine && PreviousLine->First->isAccessSpecifier() &&
+ (!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline))
Newlines = std::min(1u, Newlines);
Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 7bab55c..10ce0e9 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -14,7 +14,9 @@
//===----------------------------------------------------------------------===//
#include "UnwrappedLineParser.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
#define DEBUG_TYPE "format-parser"
@@ -604,7 +606,7 @@
// Here we blacklist certain tokens that are not usually the first token in an
// unwrapped line. This is used in attempt to distinguish macro calls without
// trailing semicolons from other constructs split to several lines.
-bool tokenCanStartNewLine(clang::Token Tok) {
+static bool tokenCanStartNewLine(const clang::Token &Tok) {
// Semicolon can be a null-statement, l_square can be a start of a macro or
// a C++11 attribute, but this doesn't seem to be common.
return Tok.isNot(tok::semi) && Tok.isNot(tok::l_brace) &&
@@ -867,6 +869,9 @@
case tok::l_square:
parseSquare();
break;
+ case tok::kw_new:
+ parseNew();
+ break;
default:
nextToken();
break;
@@ -1273,6 +1278,31 @@
// FIXME: Add error handling.
}
+void UnwrappedLineParser::parseNew() {
+ assert(FormatTok->is(tok::kw_new) && "'new' expected");
+ nextToken();
+ if (Style.Language != FormatStyle::LK_Java)
+ return;
+
+ // In Java, we can parse everything up to the parens, which aren't optional.
+ do {
+ // There should not be a ;, { or } before the new's open paren.
+ if (FormatTok->isOneOf(tok::semi, tok::l_brace, tok::r_brace))
+ return;
+
+ // Consume the parens.
+ if (FormatTok->is(tok::l_paren)) {
+ parseParens();
+
+ // If there is a class body of an anonymous class, consume that as child.
+ if (FormatTok->is(tok::l_brace))
+ parseChildBlock();
+ return;
+ }
+ nextToken();
+ } while (!eof());
+}
+
void UnwrappedLineParser::parseForOrWhileLoop() {
assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while) ||
FormatTok->IsForEachMacro) &&
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 4b953ea..76c62cd 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -95,6 +95,7 @@
void parseCaseLabel();
void parseSwitch();
void parseNamespace();
+ void parseNew();
void parseAccessSpecifier();
void parseEnum();
void parseJavaEnumBody();
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 44e5f69..4896ad7 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -36,7 +36,9 @@
PreviousLinePostfix(PreviousLinePostfix),
CurrentLinePrefix(CurrentLinePrefix), Kind(Kind),
ContinuesPPDirective(ContinuesPPDirective), IndentLevel(IndentLevel),
- Spaces(Spaces) {}
+ Spaces(Spaces), IsTrailingComment(false), TokenLength(0),
+ PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
+ StartOfBlockComment(nullptr), IndentationOffset(0) {}
void WhitespaceManager::reset() {
Changes.clear();
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index bfb1efe..692edc4 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -513,8 +513,8 @@
return false;
}
- bool ReadTargetOptions(const TargetOptions &TargetOpts,
- bool Complain) override {
+ bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain,
+ bool AllowCompatibleDifferences) override {
// If we've already initialized the target, don't do it again.
if (Target)
return false;
@@ -714,6 +714,13 @@
*AST->PP, Context, AST->ASTFileLangOpts, AST->TargetOpts, AST->Target,
Counter));
+ // Attach the AST reader to the AST context as an external AST
+ // source, so that declarations will be deserialized from the
+ // AST file as needed.
+ // We need the external source to be set up before we read the AST, because
+ // eagerly-deserialized declarations may use it.
+ Context.setExternalSource(AST->Reader);
+
switch (AST->Reader->ReadAST(Filename, serialization::MK_MainFile,
SourceLocation(), ASTReader::ARR_None)) {
case ASTReader::Success:
@@ -733,11 +740,6 @@
PP.setCounterValue(Counter);
- // Attach the AST reader to the AST context as an external AST
- // source, so that declarations will be deserialized from the
- // AST file as needed.
- Context.setExternalSource(AST->Reader);
-
// Create an AST consumer, even though it isn't used.
AST->Consumer.reset(new ASTConsumer);
@@ -2431,7 +2433,7 @@
TempPath = File;
TempPath += "-%%%%%%%%";
int fd;
- if (llvm::sys::fs::createUniqueFile(TempPath.str(), fd, TempPath))
+ if (llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath))
return true;
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
@@ -2445,8 +2447,8 @@
return true;
}
- if (llvm::sys::fs::rename(TempPath.str(), File)) {
- llvm::sys::fs::remove(TempPath.str());
+ if (llvm::sys::fs::rename(TempPath, File)) {
+ llvm::sys::fs::remove(TempPath);
return true;
}
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index cb260b4..be99b78 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -43,6 +43,7 @@
Selector GetExternalSelector(uint32_t ID) override;
uint32_t GetNumExternalSelectors() override;
Stmt *GetExternalDeclStmt(uint64_t Offset) override;
+ CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) override;
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) override;
@@ -232,6 +233,10 @@
ChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
return getFinalReader().GetExternalCXXBaseSpecifiers(Offset);
}
+CXXCtorInitializer **
+ChainedIncludesSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
+ return getFinalReader().GetExternalCXXCtorInitializers(Offset);
+}
bool
ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 07812bd..1c5b322 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -536,7 +536,7 @@
// relative to that.
FileMgr->FixupRelativePath(NewOutFile);
if (std::error_code ec =
- llvm::sys::fs::rename(it->TempFilename, NewOutFile.str())) {
+ llvm::sys::fs::rename(it->TempFilename, NewOutFile)) {
getDiagnostics().Report(diag::err_unable_to_rename_temp)
<< it->TempFilename << it->Filename << ec.message();
@@ -641,14 +641,14 @@
TempPath += "-%%%%%%%%";
int fd;
std::error_code EC =
- llvm::sys::fs::createUniqueFile(TempPath.str(), fd, TempPath);
+ llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath);
if (CreateMissingDirectories &&
EC == llvm::errc::no_such_file_or_directory) {
StringRef Parent = llvm::sys::path::parent_path(OutputPath);
EC = llvm::sys::fs::create_directories(Parent);
if (!EC) {
- EC = llvm::sys::fs::createUniqueFile(TempPath.str(), fd, TempPath);
+ EC = llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath);
}
}
@@ -1191,8 +1191,7 @@
std::error_code EC;
SmallString<128> ModuleCachePathNative;
llvm::sys::path::native(HSOpts.ModuleCachePath, ModuleCachePathNative);
- for (llvm::sys::fs::directory_iterator
- Dir(ModuleCachePathNative.str(), EC), DirEnd;
+ for (llvm::sys::fs::directory_iterator Dir(ModuleCachePathNative, EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
// If we don't have a directory, there's nothing to look into.
if (!llvm::sys::fs::is_directory(Dir->path()))
@@ -1240,9 +1239,10 @@
if (!hasASTContext())
createASTContext();
- // If we're not recursively building a module, check whether we
- // need to prune the module cache.
- if (getSourceManager().getModuleBuildStack().empty() &&
+ // If we're implicitly building modules but not currently recursively
+ // building a module, check whether we need to prune the module cache.
+ if (getLangOpts().ImplicitModules &&
+ getSourceManager().getModuleBuildStack().empty() &&
getHeaderSearchOpts().ModuleCachePruneInterval > 0 &&
getHeaderSearchOpts().ModuleCachePruneAfter > 0) {
pruneModuleCache(getHeaderSearchOpts());
@@ -1279,6 +1279,7 @@
struct ReadModuleNames : ASTReaderListener {
CompilerInstance &CI;
std::vector<StringRef> ModuleFileStack;
+ std::vector<StringRef> ModuleNameStack;
bool Failed;
bool TopFileIsModule;
@@ -1295,20 +1296,29 @@
}
ModuleFileStack.push_back(FileName);
+ ModuleNameStack.push_back(StringRef());
if (ASTReader::readASTFileControlBlock(FileName, CI.getFileManager(),
*this)) {
- CI.getDiagnostics().Report(SourceLocation(),
- diag::err_module_file_not_found)
+ CI.getDiagnostics().Report(
+ SourceLocation(), CI.getFileManager().getBufferForFile(FileName)
+ ? diag::err_module_file_invalid
+ : diag::err_module_file_not_found)
<< FileName;
- // FIXME: Produce a note stack explaining how we got here.
+ for (int I = ModuleFileStack.size() - 2; I >= 0; --I)
+ CI.getDiagnostics().Report(SourceLocation(),
+ diag::note_module_file_imported_by)
+ << ModuleFileStack[I]
+ << !ModuleNameStack[I].empty() << ModuleNameStack[I];
Failed = true;
}
+ ModuleNameStack.pop_back();
ModuleFileStack.pop_back();
}
void ReadModuleName(StringRef ModuleName) override {
if (ModuleFileStack.size() == 1)
TopFileIsModule = true;
+ ModuleNameStack.back() = ModuleName;
auto &ModuleFile = CI.ModuleFileOverrides[ModuleName];
if (!ModuleFile.empty() &&
@@ -1321,6 +1331,19 @@
}
} RMN(*this);
+ // If we don't already have an ASTReader, create one now.
+ if (!ModuleManager)
+ createModuleManager();
+
+ // Tell the module manager about this module file.
+ if (getModuleManager()->getModuleManager().addKnownModuleFile(FileName)) {
+ getDiagnostics().Report(SourceLocation(), diag::err_module_file_not_found)
+ << FileName;
+ return false;
+ }
+
+ // Build our mapping of module names to module files from this file
+ // and its imports.
RMN.visitImport(FileName);
if (RMN.Failed)
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 2098dec..5d2cdae 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -367,6 +367,16 @@
Opts.setInlining(Args.hasArg(OPT_fno_inline_functions) ?
CodeGenOptions::OnlyAlwaysInlining : Opts.getInlining());
+ if (Arg *A = Args.getLastArg(OPT_fveclib)) {
+ StringRef Name = A->getValue();
+ if (Name == "Accelerate")
+ Opts.setVecLib(CodeGenOptions::Accelerate);
+ else if (Name == "none")
+ Opts.setVecLib(CodeGenOptions::NoLibrary);
+ else
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+ }
+
if (Args.hasArg(OPT_gline_tables_only)) {
Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly);
} else if (Args.hasArg(OPT_g_Flag) || Args.hasArg(OPT_gdwarf_2) ||
@@ -423,7 +433,6 @@
Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping);
Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions);
- Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device);
Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
Opts.CodeModel = getCodeModel(Args, Diags);
@@ -494,6 +503,8 @@
Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum);
Opts.CoverageNoFunctionNamesInData =
Args.hasArg(OPT_coverage_no_function_names_in_data);
+ Opts.CoverageExitBlockBeforeBody =
+ Args.hasArg(OPT_coverage_exit_block_before_body);
if (Args.hasArg(OPT_coverage_version_EQ)) {
StringRef CoverageVersion = Args.getLastArgValue(OPT_coverage_version_EQ);
if (CoverageVersion.size() != 4) {
@@ -978,6 +989,7 @@
.Case("cpp-output", IK_PreprocessedC)
.Case("assembler-with-cpp", IK_Asm)
.Case("c++-cpp-output", IK_PreprocessedCXX)
+ .Case("cuda-cpp-output", IK_PreprocessedCuda)
.Case("objective-c-cpp-output", IK_PreprocessedObjC)
.Case("objc-cpp-output", IK_PreprocessedObjC)
.Case("objective-c++-cpp-output", IK_PreprocessedObjCXX)
@@ -1181,6 +1193,7 @@
LangStd = LangStandard::lang_opencl;
break;
case IK_CUDA:
+ case IK_PreprocessedCuda:
LangStd = LangStandard::lang_cuda;
break;
case IK_Asm:
@@ -1233,7 +1246,8 @@
Opts.NativeHalfType = 1;
}
- Opts.CUDA = LangStd == LangStandard::lang_cuda || IK == IK_CUDA;
+ Opts.CUDA = IK == IK_CUDA || IK == IK_PreprocessedCuda ||
+ LangStd == LangStandard::lang_cuda;
// OpenCL and C++ both have bool, true, false keywords.
Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
@@ -1248,9 +1262,6 @@
Opts.CXXOperatorNames = Opts.CPlusPlus;
Opts.DollarIdents = !Opts.AsmPreprocessor;
-
- // C++14 onwards has sized global deallocation functions.
- Opts.SizedDeallocation = Opts.CPlusPlus14;
}
/// Attempt to parse a visibility value out of the given argument.
@@ -1271,43 +1282,6 @@
return DefaultVisibility;
}
-static unsigned parseMSCVersion(ArgList &Args, DiagnosticsEngine &Diags) {
- auto Arg = Args.getLastArg(OPT_fms_compatibility_version);
- if (!Arg)
- return 0;
-
- // The MSC versioning scheme involves four versioning components:
- // - Major
- // - Minor
- // - Build
- // - Patch
- //
- // We accept either the old style (_MSC_VER) value, or a _MSC_FULL_VER value.
- // Additionally, the value may be provided in the form of a more readable
- // MM.mm.bbbbb.pp version.
- //
- // Unfortunately, due to the bit-width limitations, we cannot currently encode
- // the value for the patch level.
-
- unsigned VC[4] = {0};
- StringRef Value = Arg->getValue();
- SmallVector<StringRef, 4> Components;
-
- Value.split(Components, ".", llvm::array_lengthof(VC));
- for (unsigned CI = 0,
- CE = std::min(Components.size(), llvm::array_lengthof(VC));
- CI < CE; ++CI) {
- if (Components[CI].getAsInteger(10, VC[CI])) {
- Diags.Report(diag::err_drv_invalid_value)
- << Arg->getAsString(Args) << Value;
- return 0;
- }
- }
-
- // FIXME we cannot encode the patch level
- return VC[0] * 10000000 + VC[1] * 100000 + VC[2];
-}
-
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
// FIXME: Cleanup per-file based stuff.
@@ -1348,6 +1322,7 @@
<< A->getAsString(Args) << "OpenCL";
break;
case IK_CUDA:
+ case IK_PreprocessedCuda:
if (!Std.isCPlusPlus())
Diags.Report(diag::err_drv_argument_not_allowed_with)
<< A->getAsString(Args) << "CUDA";
@@ -1477,7 +1452,16 @@
Opts.MSVCCompat = Args.hasArg(OPT_fms_compatibility);
Opts.MicrosoftExt = Opts.MSVCCompat || Args.hasArg(OPT_fms_extensions);
Opts.AsmBlocks = Args.hasArg(OPT_fasm_blocks) || Opts.MicrosoftExt;
- Opts.MSCompatibilityVersion = parseMSCVersion(Args, Diags);
+ Opts.MSCompatibilityVersion = 0;
+ if (const Arg *A = Args.getLastArg(OPT_fms_compatibility_version)) {
+ VersionTuple VT;
+ if (VT.tryParse(A->getValue()))
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
+ << A->getValue();
+ Opts.MSCompatibilityVersion = VT.getMajor() * 10000000 +
+ VT.getMinor().getValueOr(0) * 100000 +
+ VT.getSubminor().getValueOr(0);
+ }
// Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
// is specified, or -std is set to a conforming mode.
@@ -1528,10 +1512,7 @@
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin);
Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
- Opts.SizedDeallocation |= Args.hasArg(OPT_fsized_deallocation);
- Opts.SizedDeallocation &= !Args.hasArg(OPT_fno_sized_deallocation);
- Opts.DefineSizedDeallocation = Opts.SizedDeallocation &&
- Args.hasArg(OPT_fdefine_sized_deallocation);
+ Opts.SizedDeallocation = Args.hasArg(OPT_fsized_deallocation);
Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);
Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
@@ -1578,6 +1559,7 @@
Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal);
Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name);
+ Opts.AppExt = Args.hasArg(OPT_fapplication_extension);
Opts.ImplementationOfModule =
Args.getLastArgValue(OPT_fmodule_implementation_of);
Opts.ModuleFeatures = Args.getAllArgValues(OPT_fmodule_feature);
@@ -2024,7 +2006,7 @@
llvm::sys::path::append(systemVersionFile, "SystemVersion.plist");
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
- llvm::MemoryBuffer::getFile(systemVersionFile.str());
+ llvm::MemoryBuffer::getFile(systemVersionFile);
if (buffer) {
code = hash_combine(code, buffer.get()->getBuffer());
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 75670d9..fd251ac 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -268,7 +268,7 @@
SmallString<128> DirNative;
llvm::sys::path::native(PCHDir->getName(), DirNative);
bool Found = false;
- for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+ for (llvm::sys::fs::directory_iterator Dir(DirNative, EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
// Check whether this is an acceptable AST file.
if (ASTReader::isAcceptableASTFile(Dir->path(), FileMgr,
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index a55a325..bc11929 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -209,7 +209,7 @@
std::error_code EC;
SmallString<128> DirNative;
llvm::sys::path::native(UmbrellaDir->getName(), DirNative);
- for (llvm::sys::fs::recursive_directory_iterator Dir(DirNative.str(), EC),
+ for (llvm::sys::fs::recursive_directory_iterator Dir(DirNative, EC),
DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
// Check whether this entry has an extension typically associated with
@@ -462,8 +462,8 @@
return false;
}
- bool ReadTargetOptions(const TargetOptions &TargetOpts,
- bool Complain) override {
+ bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain,
+ bool AllowCompatibleDifferences) override {
Out.indent(2) << "Target options:\n";
Out.indent(4) << " Triple: " << TargetOpts.Triple << "\n";
Out.indent(4) << " CPU: " << TargetOpts.CPU << "\n";
@@ -690,6 +690,7 @@
case IK_None:
case IK_Asm:
case IK_PreprocessedC:
+ case IK_PreprocessedCuda:
case IK_PreprocessedCXX:
case IK_PreprocessedObjC:
case IK_PreprocessedObjCXX:
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
index 1869d0c..9ede674 100644
--- a/lib/Frontend/FrontendOptions.cpp
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -18,6 +18,7 @@
.Cases("S", "s", IK_Asm)
.Case("i", IK_PreprocessedC)
.Case("ii", IK_PreprocessedCXX)
+ .Case("cui", IK_PreprocessedCuda)
.Case("m", IK_ObjC)
.Case("mi", IK_PreprocessedObjC)
.Cases("mm", "M", IK_ObjCXX)
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index a518a0a..9b4f7e5 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -227,6 +227,7 @@
if (HSOpts.UseStandardSystemIncludes) {
switch (os) {
+ case llvm::Triple::CloudABI:
case llvm::Triple::FreeBSD:
case llvm::Triple::NetBSD:
case llvm::Triple::OpenBSD:
@@ -246,7 +247,7 @@
// supplied path.
SmallString<128> P = StringRef(HSOpts.ResourceDir);
llvm::sys::path::append(P, "include");
- AddUnmappedPath(P.str(), ExternCSystem, false);
+ AddUnmappedPath(P, ExternCSystem, false);
}
// All remaining additions are for system include directories, early exit if
@@ -270,6 +271,14 @@
case llvm::Triple::Linux:
llvm_unreachable("Include management is handled in the driver.");
+ case llvm::Triple::CloudABI: {
+ // <sysroot>/<triple>/include
+ SmallString<128> P = StringRef(HSOpts.ResourceDir);
+ llvm::sys::path::append(P, "../../..", triple.str(), "include");
+ AddPath(P, System, false);
+ break;
+ }
+
case llvm::Triple::Haiku:
AddPath("/boot/common/include", System, false);
AddPath("/boot/develop/headers/os", System, false);
@@ -317,18 +326,18 @@
// <sysroot>/i686-w64-mingw32/include
SmallString<128> P = StringRef(HSOpts.ResourceDir);
llvm::sys::path::append(P, "../../../i686-w64-mingw32/include");
- AddPath(P.str(), System, false);
+ AddPath(P, System, false);
// <sysroot>/x86_64-w64-mingw32/include
P.resize(HSOpts.ResourceDir.size());
llvm::sys::path::append(P, "../../../x86_64-w64-mingw32/include");
- AddPath(P.str(), System, false);
+ AddPath(P, System, false);
// mingw.org crt include paths
// <sysroot>/include
P.resize(HSOpts.ResourceDir.size());
llvm::sys::path::append(P, "../../../include");
- AddPath(P.str(), System, false);
+ AddPath(P, System, false);
AddPath("/mingw/include", System, false);
#if defined(LLVM_ON_WIN32)
AddPath("c:/mingw/include", System, false);
@@ -340,8 +349,14 @@
break;
}
- if ( os != llvm::Triple::RTEMS )
+ switch (os) {
+ case llvm::Triple::CloudABI:
+ case llvm::Triple::RTEMS:
+ break;
+ default:
AddPath("/usr/include", ExternCSystem, false);
+ break;
+ }
}
void InitHeaderSearch::
@@ -488,7 +503,7 @@
// Get foo/include/c++/v1
llvm::sys::path::append(P, "include", "c++", "v1");
- AddUnmappedPath(P.str(), CXXSystem, false);
+ AddUnmappedPath(P, CXXSystem, false);
}
}
// On Solaris, include the support directory for things like xlocale and
@@ -699,7 +714,7 @@
// Set up the builtin include directory in the module map.
SmallString<128> P = StringRef(HSOpts.ResourceDir);
llvm::sys::path::append(P, "include");
- if (const DirectoryEntry *Dir = HS.getFileMgr().getDirectory(P.str()))
+ if (const DirectoryEntry *Dir = HS.getFileMgr().getDirectory(P))
HS.getModuleMap().setBuiltinIncludeDir(Dir);
}
diff --git a/lib/Frontend/ModuleDependencyCollector.cpp b/lib/Frontend/ModuleDependencyCollector.cpp
index 62865e9..67852dc 100644
--- a/lib/Frontend/ModuleDependencyCollector.cpp
+++ b/lib/Frontend/ModuleDependencyCollector.cpp
@@ -77,10 +77,10 @@
if (std::error_code EC = fs::create_directories(path::parent_path(Dest),
/*IgnoreExisting=*/true))
return EC;
- if (std::error_code EC = fs::copy_file(AbsoluteSrc.str(), Dest.str()))
+ if (std::error_code EC = fs::copy_file(AbsoluteSrc, Dest))
return EC;
// Use the absolute path under the root for the file mapping.
- Collector.addFileMapping(AbsoluteSrc.str(), Dest.str());
+ Collector.addFileMapping(AbsoluteSrc, Dest);
return std::error_code();
}
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 3c4fed1..007ddc2 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -99,6 +99,8 @@
void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D) override;
void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override;
+ void ResolvedOperatorDelete(const CXXDestructorDecl *DD,
+ const FunctionDecl *Delete) override;
void CompletedImplicitDefinition(const FunctionDecl *D) override;
void StaticDataMemberInstantiated(const VarDecl *D) override;
void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
@@ -108,6 +110,8 @@
const ObjCCategoryDecl *ClassExt) override;
void DeclarationMarkedUsed(const Decl *D) override;
void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
+ void RedefinedHiddenDefinition(const NamedDecl *D,
+ SourceLocation Loc) override;
private:
std::vector<ASTMutationListener*> Listeners;
@@ -154,6 +158,11 @@
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->DeducedReturnType(FD, ReturnType);
}
+void MultiplexASTMutationListener::ResolvedOperatorDelete(
+ const CXXDestructorDecl *DD, const FunctionDecl *Delete) {
+ for (auto *L : Listeners)
+ L->ResolvedOperatorDelete(DD, Delete);
+}
void MultiplexASTMutationListener::CompletedImplicitDefinition(
const FunctionDecl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
@@ -186,6 +195,11 @@
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D);
}
+void MultiplexASTMutationListener::RedefinedHiddenDefinition(
+ const NamedDecl *D, SourceLocation Loc) {
+ for (auto *L : Listeners)
+ L->RedefinedHiddenDefinition(D, Loc);
+}
} // end namespace clang
diff --git a/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index 47f8189..12c57cd 100644
--- a/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -886,15 +886,15 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get(D->getNameAsString()),
- IvarT, nullptr,
- /*BitWidth=*/nullptr, /*Mutable=*/true,
- ICIS_NoInit);
- MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
- FD->getType(), VK_LValue,
- OK_Ordinary);
- IvarT = Context->getDecltypeType(ME, ME->getType());
- }
- }
+ IvarT, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
+ ICIS_NoInit);
+ MemberExpr *ME = new (Context)
+ MemberExpr(PE, true, SourceLocation(), FD, SourceLocation(),
+ FD->getType(), VK_LValue, OK_Ordinary);
+ IvarT = Context->getDecltypeType(ME, ME->getType());
+ }
+ }
convertObjCTypeToCStyleType(IvarT);
QualType castT = Context->getPointerType(IvarT);
std::string TypeString(castT.getAsString(Context->getPrintingPolicy()));
@@ -2764,17 +2764,15 @@
FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("arr"),
- Context->getPointerType(Context->VoidPtrTy),
- nullptr, /*BitWidth=*/nullptr,
- /*Mutable=*/true, ICIS_NoInit);
- MemberExpr *ArrayLiteralME =
- new (Context) MemberExpr(NSArrayCallExpr, false, ARRFD,
- SourceLocation(),
- ARRFD->getType(), VK_LValue,
- OK_Ordinary);
- QualType ConstIdT = Context->getObjCIdType().withConst();
- CStyleCastExpr * ArrayLiteralObjects =
- NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->VoidPtrTy),
+ nullptr, /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
+ MemberExpr *ArrayLiteralME = new (Context)
+ MemberExpr(NSArrayCallExpr, false, SourceLocation(), ARRFD,
+ SourceLocation(), ARRFD->getType(), VK_LValue, OK_Ordinary);
+ QualType ConstIdT = Context->getObjCIdType().withConst();
+ CStyleCastExpr * ArrayLiteralObjects =
+ NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(ConstIdT),
CK_BitCast,
ArrayLiteralME);
@@ -2901,34 +2899,30 @@
FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("arr"),
- Context->getPointerType(Context->VoidPtrTy),
- nullptr, /*BitWidth=*/nullptr,
- /*Mutable=*/true, ICIS_NoInit);
- MemberExpr *DictLiteralValueME =
- new (Context) MemberExpr(NSValueCallExpr, false, ARRFD,
- SourceLocation(),
- ARRFD->getType(), VK_LValue,
- OK_Ordinary);
- QualType ConstIdT = Context->getObjCIdType().withConst();
- CStyleCastExpr * DictValueObjects =
- NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->VoidPtrTy),
+ nullptr, /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
+ MemberExpr *DictLiteralValueME = new (Context)
+ MemberExpr(NSValueCallExpr, false, SourceLocation(), ARRFD,
+ SourceLocation(), ARRFD->getType(), VK_LValue, OK_Ordinary);
+ QualType ConstIdT = Context->getObjCIdType().withConst();
+ CStyleCastExpr * DictValueObjects =
+ NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(ConstIdT),
CK_BitCast,
DictLiteralValueME);
// (const id <NSCopying> [])keys
- Expr *NSKeyCallExpr =
- new (Context) CallExpr(*Context, NSDictDRE, KeyExprs,
- NSDictFType, VK_LValue, SourceLocation());
-
- MemberExpr *DictLiteralKeyME =
- new (Context) MemberExpr(NSKeyCallExpr, false, ARRFD,
- SourceLocation(),
- ARRFD->getType(), VK_LValue,
- OK_Ordinary);
-
- CStyleCastExpr * DictKeyObjects =
- NoTypeInfoCStyleCastExpr(Context,
- Context->getPointerType(ConstIdT),
+ Expr *NSKeyCallExpr =
+ new (Context) CallExpr(*Context, NSDictDRE, KeyExprs,
+ NSDictFType, VK_LValue, SourceLocation());
+
+ MemberExpr *DictLiteralKeyME = new (Context)
+ MemberExpr(NSKeyCallExpr, false, SourceLocation(), ARRFD,
+ SourceLocation(), ARRFD->getType(), VK_LValue, OK_Ordinary);
+
+ CStyleCastExpr * DictKeyObjects =
+ NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(ConstIdT),
CK_BitCast,
DictLiteralKeyME);
@@ -3231,15 +3225,15 @@
FieldDecl *FieldD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("s"),
- returnType, nullptr,
- /*BitWidth=*/nullptr,
- /*Mutable=*/true, ICIS_NoInit);
- MemberExpr *ME = new (Context) MemberExpr(STCE, false, FieldD, SourceLocation(),
- FieldD->getType(), VK_LValue,
- OK_Ordinary);
-
- return ME;
-}
+ returnType, nullptr,
+ /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
+ MemberExpr *ME = new (Context)
+ MemberExpr(STCE, false, SourceLocation(), FieldD, SourceLocation(),
+ FieldD->getType(), VK_LValue, OK_Ordinary);
+
+ return ME;
+}
Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SourceLocation StartLoc,
@@ -4729,17 +4723,16 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("FuncPtr"),
- Context->VoidPtrTy, nullptr,
- /*BitWidth=*/nullptr, /*Mutable=*/true,
- ICIS_NoInit);
- MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
- FD->getType(), VK_LValue,
- OK_Ordinary);
-
-
- CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,
- CK_BitCast, ME);
- PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
+ ICIS_NoInit);
+ MemberExpr *ME =
+ new (Context) MemberExpr(PE, true, SourceLocation(), FD, SourceLocation(),
+ FD->getType(), VK_LValue, OK_Ordinary);
+
+ CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,
+ CK_BitCast, ME);
+ PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
SmallVector<Expr*, 8> BlkExprs;
// Add the implicit argument.
@@ -4778,28 +4771,26 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("__forwarding"),
- Context->VoidPtrTy, nullptr,
- /*BitWidth=*/nullptr, /*Mutable=*/true,
- ICIS_NoInit);
- MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
- FD, SourceLocation(),
- FD->getType(), VK_LValue,
- OK_Ordinary);
-
- StringRef Name = VD->getName();
- FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(),
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
+ ICIS_NoInit);
+ MemberExpr *ME = new (Context)
+ MemberExpr(DeclRefExp, isArrow, SourceLocation(), FD, SourceLocation(),
+ FD->getType(), VK_LValue, OK_Ordinary);
+
+ StringRef Name = VD->getName();
+ FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(),
&Context->Idents.get(Name),
- Context->VoidPtrTy, nullptr,
- /*BitWidth=*/nullptr, /*Mutable=*/true,
- ICIS_NoInit);
- ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
- DeclRefExp->getType(), VK_LValue, OK_Ordinary);
-
-
-
- // Need parens to enforce precedence.
- ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(),
- DeclRefExp->getExprLoc(),
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
+ ICIS_NoInit);
+ ME =
+ new (Context) MemberExpr(ME, true, SourceLocation(), FD, SourceLocation(),
+ DeclRefExp->getType(), VK_LValue, OK_Ordinary);
+
+ // Need parens to enforce precedence.
+ ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(),
+ DeclRefExp->getExprLoc(),
ME);
ReplaceStmt(DeclRefExp, PE);
return PE;
@@ -7691,15 +7682,15 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get(D->getNameAsString()),
- IvarT, nullptr,
- /*BitWidth=*/nullptr,
- /*Mutable=*/true, ICIS_NoInit);
- MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
- FD->getType(), VK_LValue,
- OK_Ordinary);
- IvarT = Context->getDecltypeType(ME, ME->getType());
- }
- }
+ IvarT, nullptr,
+ /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
+ MemberExpr *ME = new (Context)
+ MemberExpr(PE, true, SourceLocation(), FD, SourceLocation(),
+ FD->getType(), VK_LValue, OK_Ordinary);
+ IvarT = Context->getDecltypeType(ME, ME->getType());
+ }
+ }
convertObjCTypeToCStyleType(IvarT);
QualType castT = Context->getPointerType(IvarT);
@@ -7720,15 +7711,15 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get(D->getNameAsString()),
- D->getType(), nullptr,
- /*BitWidth=*/D->getBitWidth(),
- /*Mutable=*/true, ICIS_NoInit);
- MemberExpr *ME = new (Context) MemberExpr(PE, /*isArrow*/false, FD, SourceLocation(),
- FD->getType(), VK_LValue,
- OK_Ordinary);
- Replacement = ME;
-
- }
+ D->getType(), nullptr,
+ /*BitWidth=*/D->getBitWidth(),
+ /*Mutable=*/true, ICIS_NoInit);
+ MemberExpr *ME = new (Context)
+ MemberExpr(PE, /*isArrow*/ false, SourceLocation(), FD,
+ SourceLocation(), FD->getType(), VK_LValue, OK_Ordinary);
+ Replacement = ME;
+
+ }
else
Replacement = PE;
}
diff --git a/lib/Frontend/Rewrite/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp
index 5196810..5802ba7 100644
--- a/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -3818,17 +3818,16 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("FuncPtr"),
- Context->VoidPtrTy, nullptr,
- /*BitWidth=*/nullptr, /*Mutable=*/true,
- ICIS_NoInit);
- MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
- FD->getType(), VK_LValue,
- OK_Ordinary);
-
-
- CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,
- CK_BitCast, ME);
- PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
+ ICIS_NoInit);
+ MemberExpr *ME =
+ new (Context) MemberExpr(PE, true, SourceLocation(), FD, SourceLocation(),
+ FD->getType(), VK_LValue, OK_Ordinary);
+
+ CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,
+ CK_BitCast, ME);
+ PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
SmallVector<Expr*, 8> BlkExprs;
// Add the implicit argument.
@@ -3867,28 +3866,26 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("__forwarding"),
- Context->VoidPtrTy, nullptr,
- /*BitWidth=*/nullptr, /*Mutable=*/true,
- ICIS_NoInit);
- MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
- FD, SourceLocation(),
- FD->getType(), VK_LValue,
- OK_Ordinary);
-
- StringRef Name = VD->getName();
- FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(),
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
+ ICIS_NoInit);
+ MemberExpr *ME = new (Context)
+ MemberExpr(DeclRefExp, isArrow, SourceLocation(), FD, SourceLocation(),
+ FD->getType(), VK_LValue, OK_Ordinary);
+
+ StringRef Name = VD->getName();
+ FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(),
&Context->Idents.get(Name),
- Context->VoidPtrTy, nullptr,
- /*BitWidth=*/nullptr, /*Mutable=*/true,
- ICIS_NoInit);
- ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
- DeclRefExp->getType(), VK_LValue, OK_Ordinary);
-
-
-
- // Need parens to enforce precedence.
- ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(),
- DeclRefExp->getExprLoc(),
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
+ ICIS_NoInit);
+ ME =
+ new (Context) MemberExpr(ME, true, SourceLocation(), FD, SourceLocation(),
+ DeclRefExp->getType(), VK_LValue, OK_Ordinary);
+
+ // Need parens to enforce precedence.
+ ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(),
+ DeclRefExp->getExprLoc(),
ME);
ReplaceStmt(DeclRefExp, PE);
return PE;
@@ -5877,16 +5874,15 @@
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(OldRange.getBegin(),
OldRange.getEnd(),
- castExpr);
- if (IV->isFreeIvar() &&
- declaresSameEntity(CurMethodDef->getClassInterface(), iFaceDecl->getDecl())) {
- MemberExpr *ME = new (Context) MemberExpr(PE, true, D,
- IV->getLocation(),
- D->getType(),
- VK_LValue, OK_Ordinary);
- Replacement = ME;
- } else {
- IV->setBase(PE);
+ castExpr);
+ if (IV->isFreeIvar() &&
+ declaresSameEntity(CurMethodDef->getClassInterface(), iFaceDecl->getDecl())) {
+ MemberExpr *ME = new (Context)
+ MemberExpr(PE, true, SourceLocation(), D, IV->getLocation(),
+ D->getType(), VK_LValue, OK_Ordinary);
+ Replacement = ME;
+ } else {
+ IV->setBase(PE);
}
}
} else { // we are outside a method.
diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp
index f701f72..5dcacfa 100644
--- a/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -20,6 +20,7 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
@@ -631,7 +632,7 @@
"Unexpected diagnostic with valid location outside of a source file");
SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
- State->diagBuf.str(),
+ State->diagBuf,
Info.getRanges(),
Info.getFixItHints(),
&Info.getSourceManager(),
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index b8a8869..252bf36 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -1387,6 +1387,21 @@
__builtin_altivec_vcmpequw((vector int)__a, (vector int)__b);
}
+#ifdef __POWER8_VECTOR__
+static vector bool long long __ATTRS_o_ai
+vec_cmpeq(vector signed long long __a, vector signed long long __b)
+{
+ return (vector bool long long) __builtin_altivec_vcmpequd(__a, __b);
+}
+
+static vector bool long long __ATTRS_o_ai
+vec_cmpeq(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return (vector bool long long)
+ __builtin_altivec_vcmpequd((vector long long)__a, (vector long long) __b);
+}
+#endif
+
static vector bool int __ATTRS_o_ai
vec_cmpeq(vector float __a, vector float __b)
{
@@ -1447,6 +1462,20 @@
return (vector bool int)__builtin_altivec_vcmpgtuw(__a, __b);
}
+#ifdef __POWER8_VECTOR__
+static vector bool long long __ATTRS_o_ai
+vec_cmpgt(vector signed long long __a, vector signed long long __b)
+{
+ return (vector bool long long)__builtin_altivec_vcmpgtsd(__a, __b);
+}
+
+static vector bool long long __ATTRS_o_ai
+vec_cmpgt(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return (vector bool long long)__builtin_altivec_vcmpgtud(__a, __b);
+}
+#endif
+
static vector bool int __ATTRS_o_ai
vec_cmpgt(vector float __a, vector float __b)
{
@@ -2679,6 +2708,20 @@
return __builtin_altivec_vmaxuw(__a, (vector unsigned int)__b);
}
+#ifdef __POWER8_VECTOR__
+static vector signed long long __ATTRS_o_ai
+vec_max(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vmaxsd(__a, __b);
+}
+
+static vector unsigned long long __ATTRS_o_ai
+vec_max(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vmaxud(__a, __b);
+}
+#endif
+
static vector float __ATTRS_o_ai
vec_max(vector float __a, vector float __b)
{
@@ -3327,6 +3370,20 @@
return __builtin_altivec_vminuw(__a, (vector unsigned int)__b);
}
+#ifdef __POWER8_VECTOR__
+static vector signed long long __ATTRS_o_ai
+vec_min(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vminsd(__a, __b);
+}
+
+static vector unsigned long long __ATTRS_o_ai
+vec_min(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vminud(__a, __b);
+}
+#endif
+
static vector float __ATTRS_o_ai
vec_min(vector float __a, vector float __b)
{
@@ -3762,6 +3819,28 @@
#endif
}
+#ifdef __POWER8_VECTOR__
+static vector signed long long __ATTRS_o_ai
+vec_mule(vector signed int __a, vector signed int __b)
+{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulosw(__a, __b);
+#else
+ return __builtin_altivec_vmulesw(__a, __b);
+#endif
+}
+
+static vector unsigned long long __ATTRS_o_ai
+vec_mule(vector unsigned int __a, vector unsigned int __b)
+{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulouw(__a, __b);
+#else
+ return __builtin_altivec_vmuleuw(__a, __b);
+#endif
+}
+#endif
+
/* vec_vmulesb */
static vector short __attribute__((__always_inline__))
@@ -3852,6 +3931,28 @@
#endif
}
+#ifdef __POWER8_VECTOR__
+static vector signed long long __ATTRS_o_ai
+vec_mulo(vector signed int __a, vector signed int __b)
+{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulesw(__a, __b);
+#else
+ return __builtin_altivec_vmulosw(__a, __b);
+#endif
+}
+
+static vector unsigned long long __ATTRS_o_ai
+vec_mulo(vector unsigned int __a, vector unsigned int __b)
+{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmuleuw(__a, __b);
+#else
+ return __builtin_altivec_vmulouw(__a, __b);
+#endif
+}
+#endif
+
/* vec_vmulosb */
static vector short __attribute__((__always_inline__))
@@ -5095,6 +5196,20 @@
return (vector unsigned int)__builtin_altivec_vrlw((vector int)__a, __b);
}
+#ifdef __POWER8_VECTOR__
+static vector signed long long __ATTRS_o_ai
+vec_rl(vector signed long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vrld(__a, __b);
+}
+
+static vector unsigned long long __ATTRS_o_ai
+vec_rl(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vrld(__a, __b);
+}
+#endif
+
/* vec_vrlb */
static vector signed char __ATTRS_o_ai
@@ -5465,6 +5580,20 @@
return __a << __b;
}
+#ifdef __POWER8_VECTOR__
+static vector signed long long __ATTRS_o_ai
+vec_sl(vector signed long long __a, vector unsigned long long __b)
+{
+ return __a << (vector long long)__b;
+}
+
+static vector unsigned long long __ATTRS_o_ai
+vec_sl(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __a << __b;
+}
+#endif
+
/* vec_vslb */
#define __builtin_altivec_vslb vec_vslb
@@ -6566,6 +6695,20 @@
return __a >> __b;
}
+#ifdef __POWER8_VECTOR__
+static vector signed long long __ATTRS_o_ai
+vec_sr(vector signed long long __a, vector unsigned long long __b)
+{
+ return __a >> (vector long long)__b;
+}
+
+static vector unsigned long long __ATTRS_o_ai
+vec_sr(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __a >> __b;
+}
+#endif
+
/* vec_vsrb */
#define __builtin_altivec_vsrb vec_vsrb
@@ -6652,6 +6795,20 @@
return (vector unsigned int)__builtin_altivec_vsraw((vector int)__a, __b);
}
+#ifdef __POWER8_VECTOR__
+static vector signed long long __ATTRS_o_ai
+vec_sra(vector signed long long __a, vector unsigned long long __b)
+{
+ return __a >> __b;
+}
+
+static vector unsigned long long __ATTRS_o_ai
+vec_sra(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return (vector unsigned long long) ( (vector signed long long) __a >> __b);
+}
+#endif
+
/* vec_vsrab */
static vector signed char __ATTRS_o_ai
@@ -10887,6 +11044,55 @@
return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)__a, (vector int)__b);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_all_eq(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_LT, __a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_all_eq(vector long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_LT, __a, (vector long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_eq(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_LT, (vector long long)__a,
+ (vector long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_eq(vector unsigned long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_LT, (vector long long)__a,
+ (vector long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_eq(vector bool long long __a, vector long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_LT, (vector long long)__a,
+ (vector long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_eq(vector bool long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_LT, (vector long long)__a,
+ (vector long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_eq(vector bool long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_LT, (vector long long)__a,
+ (vector long long)__b);
+}
+#endif
+
static int __ATTRS_o_ai
vec_all_eq(vector float __a, vector float __b)
{
@@ -11033,6 +11239,56 @@
(vector unsigned int)__a);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_all_ge(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_EQ, __b, __a);
+}
+static int __ATTRS_o_ai
+vec_all_ge(vector signed long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_EQ, (vector signed long long)__b,
+ __a);
+}
+
+static int __ATTRS_o_ai
+vec_all_ge(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ, __b, __a);
+}
+
+static int __ATTRS_o_ai
+vec_all_ge(vector unsigned long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ, (vector unsigned long long)__b,
+ __a);
+}
+
+static int __ATTRS_o_ai
+vec_all_ge(vector bool long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ,
+ (vector unsigned long long)__b,
+ (vector unsigned long long)__a);
+}
+
+static int __ATTRS_o_ai
+vec_all_ge(vector bool long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ, __b,
+ (vector unsigned long long)__a);
+}
+
+static int __ATTRS_o_ai
+vec_all_ge(vector bool long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ,
+ (vector unsigned long long)__b,
+ (vector unsigned long long)__a);
+}
+#endif
+
static int __ATTRS_o_ai
vec_all_ge(vector float __a, vector float __b)
{
@@ -11179,6 +11435,56 @@
(vector unsigned int)__b);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_all_gt(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_LT, __a, __b);
+}
+static int __ATTRS_o_ai
+vec_all_gt(vector signed long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_LT, __a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_gt(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT, __a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_all_gt(vector unsigned long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT, __a,
+ (vector unsigned long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_gt(vector bool long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT,
+ (vector unsigned long long)__a,
+ (vector unsigned long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_gt(vector bool long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT, (vector unsigned long long)__a,
+ __b);
+}
+
+static int __ATTRS_o_ai
+vec_all_gt(vector bool long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT,
+ (vector unsigned long long)__a,
+ (vector unsigned long long)__b);
+}
+#endif
+
static int __ATTRS_o_ai
vec_all_gt(vector float __a, vector float __b)
{
@@ -11333,6 +11639,57 @@
(vector unsigned int)__b);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_all_le(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_EQ, __a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_all_le(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ, __a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_all_le(vector signed long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_EQ, __a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_le(vector unsigned long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ, __a,
+ (vector unsigned long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_le(vector bool long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ,
+ (vector unsigned long long)__a,
+ (vector unsigned long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_le(vector bool long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ, (vector unsigned long long)__a,
+ __b);
+}
+
+static int __ATTRS_o_ai
+vec_all_le(vector bool long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ,
+ (vector unsigned long long)__a,
+ (vector unsigned long long)__b);
+}
+#endif
+
static int __ATTRS_o_ai
vec_all_le(vector float __a, vector float __b)
{
@@ -11479,6 +11836,57 @@
(vector unsigned int)__a);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_all_lt(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_LT, __b, __a);
+}
+
+static int __ATTRS_o_ai
+vec_all_lt(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT, __b, __a);
+}
+
+static int __ATTRS_o_ai
+vec_all_lt(vector signed long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_LT, (vector signed long long)__b,
+ __a);
+}
+
+static int __ATTRS_o_ai
+vec_all_lt(vector unsigned long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT, (vector unsigned long long)__b,
+ __a);
+}
+
+static int __ATTRS_o_ai
+vec_all_lt(vector bool long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT,
+ (vector unsigned long long)__b,
+ (vector unsigned long long)__a);
+}
+
+static int __ATTRS_o_ai
+vec_all_lt(vector bool long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT, __b,
+ (vector unsigned long long)__a);
+}
+
+static int __ATTRS_o_ai
+vec_all_lt(vector bool long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT,
+ (vector unsigned long long)__b,
+ (vector unsigned long long)__a);
+}
+#endif
+
static int __ATTRS_o_ai
vec_all_lt(vector float __a, vector float __b)
{
@@ -11633,6 +12041,56 @@
return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)__a, (vector int)__b);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_all_ne(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_EQ, __a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_all_ne(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_EQ, (vector long long)__a,
+ (vector long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_ne(vector signed long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_EQ, __a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_ne(vector unsigned long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_EQ, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_ne(vector bool long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_EQ, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_ne(vector bool long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_EQ, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_all_ne(vector bool long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_EQ, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+#endif
+
static int __ATTRS_o_ai
vec_all_ne(vector float __a, vector float __b)
{
@@ -11837,6 +12295,61 @@
__builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)__a, (vector int)__b);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_any_eq(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_EQ_REV, __a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_any_eq(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return
+ __builtin_altivec_vcmpequd_p(__CR6_EQ_REV, (vector long long)__a,
+ (vector long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_eq(vector signed long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_EQ_REV, __a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_eq(vector unsigned long long __a, vector bool long long __b)
+{
+ return
+ __builtin_altivec_vcmpequd_p(__CR6_EQ_REV, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_eq(vector bool long long __a, vector signed long long __b)
+{
+ return
+ __builtin_altivec_vcmpequd_p(__CR6_EQ_REV, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_eq(vector bool long long __a, vector unsigned long long __b)
+{
+ return
+ __builtin_altivec_vcmpequd_p(__CR6_EQ_REV, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_eq(vector bool long long __a, vector bool long long __b)
+{
+ return
+ __builtin_altivec_vcmpequd_p(__CR6_EQ_REV, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+#endif
+
static int __ATTRS_o_ai
vec_any_eq(vector float __a, vector float __b)
{
@@ -11985,6 +12498,57 @@
(vector unsigned int)__a);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_any_ge(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_LT_REV, __b, __a);
+}
+
+static int __ATTRS_o_ai
+vec_any_ge(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT_REV, __b, __a);
+}
+
+static int __ATTRS_o_ai
+vec_any_ge(vector signed long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_LT_REV,
+ (vector signed long long)__b, __a);
+}
+
+static int __ATTRS_o_ai
+vec_any_ge(vector unsigned long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT_REV,
+ (vector unsigned long long)__b, __a);
+}
+
+static int __ATTRS_o_ai
+vec_any_ge(vector bool long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT_REV,
+ (vector unsigned long long)__b,
+ (vector unsigned long long)__a);
+}
+
+static int __ATTRS_o_ai
+vec_any_ge(vector bool long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT_REV, __b,
+ (vector unsigned long long)__a);
+}
+
+static int __ATTRS_o_ai
+vec_any_ge(vector bool long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT_REV,
+ (vector unsigned long long)__b,
+ (vector unsigned long long)__a);
+}
+#endif
+
static int __ATTRS_o_ai
vec_any_ge(vector float __a, vector float __b)
{
@@ -12135,6 +12699,58 @@
(vector unsigned int)__b);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_any_gt(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_EQ_REV, __a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_any_gt(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ_REV, __a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_any_gt(vector signed long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_EQ_REV, __a,
+ (vector signed long long)__b);
+}
+
+
+static int __ATTRS_o_ai
+vec_any_gt(vector unsigned long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ_REV, __a,
+ (vector unsigned long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_gt(vector bool long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ_REV,
+ (vector unsigned long long)__a,
+ (vector unsigned long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_gt(vector bool long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ_REV,
+ (vector unsigned long long)__a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_any_gt(vector bool long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ_REV,
+ (vector unsigned long long)__a,
+ (vector unsigned long long)__b);
+}
+#endif
+
static int __ATTRS_o_ai
vec_any_gt(vector float __a, vector float __b)
{
@@ -12285,6 +12901,57 @@
(vector unsigned int)__b);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_any_le(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_LT_REV, __a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_any_le(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT_REV, __a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_any_le(vector signed long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_LT_REV, __a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_le(vector unsigned long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT_REV, __a,
+ (vector unsigned long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_le(vector bool long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT_REV,
+ (vector unsigned long long)__a,
+ (vector unsigned long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_le(vector bool long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT_REV,
+ (vector unsigned long long)__a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_any_le(vector bool long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_LT_REV,
+ (vector unsigned long long)__a,
+ (vector unsigned long long)__b);
+}
+#endif
+
static int __ATTRS_o_ai
vec_any_le(vector float __a, vector float __b)
{
@@ -12435,6 +13102,57 @@
(vector unsigned int)__a);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_any_lt(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_EQ_REV, __b, __a);
+}
+
+static int __ATTRS_o_ai
+vec_any_lt(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ_REV, __b, __a);
+}
+
+static int __ATTRS_o_ai
+vec_any_lt(vector signed long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtsd_p(__CR6_EQ_REV,
+ (vector signed long long)__b, __a);
+}
+
+static int __ATTRS_o_ai
+vec_any_lt(vector unsigned long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ_REV,
+ (vector unsigned long long)__b, __a);
+}
+
+static int __ATTRS_o_ai
+vec_any_lt(vector bool long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ_REV,
+ (vector unsigned long long)__b,
+ (vector unsigned long long)__a);
+}
+
+static int __ATTRS_o_ai
+vec_any_lt(vector bool long long __a, vector unsigned long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ_REV, __b,
+ (vector unsigned long long)__a);
+}
+
+static int __ATTRS_o_ai
+vec_any_lt(vector bool long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpgtud_p(__CR6_EQ_REV,
+ (vector unsigned long long)__b,
+ (vector unsigned long long)__a);
+}
+#endif
+
static int __ATTRS_o_ai
vec_any_lt(vector float __a, vector float __b)
{
@@ -12607,6 +13325,61 @@
__builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)__a, (vector int)__b);
}
+#ifdef __POWER8_VECTOR__
+static int __ATTRS_o_ai
+vec_any_ne(vector signed long long __a, vector signed long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_LT_REV, __a, __b);
+}
+
+static int __ATTRS_o_ai
+vec_any_ne(vector unsigned long long __a, vector unsigned long long __b)
+{
+ return
+ __builtin_altivec_vcmpequd_p(__CR6_LT_REV, (vector long long)__a,
+ (vector long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_ne(vector signed long long __a, vector bool long long __b)
+{
+ return __builtin_altivec_vcmpequd_p(__CR6_LT_REV, __a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_ne(vector unsigned long long __a, vector bool long long __b)
+{
+ return
+ __builtin_altivec_vcmpequd_p(__CR6_LT_REV, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_ne(vector bool long long __a, vector signed long long __b)
+{
+ return
+ __builtin_altivec_vcmpequd_p(__CR6_LT_REV, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_ne(vector bool long long __a, vector unsigned long long __b)
+{
+ return
+ __builtin_altivec_vcmpequd_p(__CR6_LT_REV, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+
+static int __ATTRS_o_ai
+vec_any_ne(vector bool long long __a, vector bool long long __b)
+{
+ return
+ __builtin_altivec_vcmpequd_p(__CR6_LT_REV, (vector signed long long)__a,
+ (vector signed long long)__b);
+}
+#endif
+
static int __ATTRS_o_ai
vec_any_ne(vector float __a, vector float __b)
{
@@ -12661,6 +13434,133 @@
return __builtin_altivec_vcmpbfp_p(__CR6_EQ_REV, __a, __b);
}
+/* Power 8 Crypto functions
+Note: We diverge from the current GCC implementation with regard
+to cryptography and related functions as follows:
+- Only the SHA and AES instructions and builtins are disabled by -mno-crypto
+- The remaining ones are only available on Power8 and up so
+ require -mpower8-vector
+The justification for this is that export requirements require that
+Category:Vector.Crypto is optional (i.e. compliant hardware may not provide
+support). As a result, we need to be able to turn off support for those.
+The remaining ones (currently controlled by -mcrypto for GCC) still
+need to be provided on compliant hardware even if Vector.Crypto is not
+provided.
+FIXME: the naming convention for the builtins will be adjusted due
+to the inconsistency (__builtin_crypto_ prefix on builtins that cannot be
+removed with -mno-crypto). This is under development.
+*/
+#ifdef __CRYPTO__
+static vector unsigned long long __attribute__((__always_inline__))
+__builtin_crypto_vsbox (vector unsigned long long __a)
+{
+ return __builtin_altivec_crypto_vsbox(__a);
+}
+
+static vector unsigned long long __attribute__((__always_inline__))
+__builtin_crypto_vcipher (vector unsigned long long __a,
+ vector unsigned long long __b)
+{
+ return __builtin_altivec_crypto_vcipher(__a, __b);
+}
+
+static vector unsigned long long __attribute__((__always_inline__))
+__builtin_crypto_vcipherlast (vector unsigned long long __a,
+ vector unsigned long long __b)
+{
+ return __builtin_altivec_crypto_vcipherlast(__a, __b);
+}
+
+static vector unsigned long long __attribute__((__always_inline__))
+__builtin_crypto_vncipher (vector unsigned long long __a,
+ vector unsigned long long __b)
+{
+ return __builtin_altivec_crypto_vncipher(__a, __b);
+}
+
+static vector unsigned long long __attribute__((__always_inline__))
+__builtin_crypto_vncipherlast (vector unsigned long long __a,
+ vector unsigned long long __b)
+{
+ return __builtin_altivec_crypto_vncipherlast(__a, __b);
+}
+
+
+#define __builtin_crypto_vshasigmad __builtin_altivec_crypto_vshasigmad
+#define __builtin_crypto_vshasigmaw __builtin_altivec_crypto_vshasigmaw
+#endif
+
+#ifdef __POWER8_VECTOR__
+static vector unsigned char __ATTRS_o_ai
+__builtin_crypto_vpermxor (vector unsigned char __a,
+ vector unsigned char __b,
+ vector unsigned char __c)
+{
+ return __builtin_altivec_crypto_vpermxor(__a, __b, __c);
+}
+
+static vector unsigned short __ATTRS_o_ai
+__builtin_crypto_vpermxor (vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned short __c)
+{
+ return (vector unsigned short)
+ __builtin_altivec_crypto_vpermxor((vector unsigned char) __a,
+ (vector unsigned char) __b,
+ (vector unsigned char) __c);
+}
+
+static vector unsigned int __ATTRS_o_ai
+__builtin_crypto_vpermxor (vector unsigned int __a,
+ vector unsigned int __b,
+ vector unsigned int __c)
+{
+ return (vector unsigned int)
+ __builtin_altivec_crypto_vpermxor((vector unsigned char) __a,
+ (vector unsigned char) __b,
+ (vector unsigned char) __c);
+}
+
+static vector unsigned long long __ATTRS_o_ai
+__builtin_crypto_vpermxor (vector unsigned long long __a,
+ vector unsigned long long __b,
+ vector unsigned long long __c)
+{
+ return (vector unsigned long long)
+ __builtin_altivec_crypto_vpermxor((vector unsigned char) __a,
+ (vector unsigned char) __b,
+ (vector unsigned char) __c);
+}
+
+static vector unsigned char __ATTRS_o_ai
+__builtin_crypto_vpmsumb (vector unsigned char __a,
+ vector unsigned char __b)
+{
+ return __builtin_altivec_crypto_vpmsumb(__a, __b);
+}
+
+static vector unsigned short __ATTRS_o_ai
+__builtin_crypto_vpmsumb (vector unsigned short __a,
+ vector unsigned short __b)
+{
+ return __builtin_altivec_crypto_vpmsumh(__a, __b);
+}
+
+static vector unsigned int __ATTRS_o_ai
+__builtin_crypto_vpmsumb (vector unsigned int __a,
+ vector unsigned int __b)
+{
+ return __builtin_altivec_crypto_vpmsumw(__a, __b);
+}
+
+static vector unsigned long long __ATTRS_o_ai
+__builtin_crypto_vpmsumb (vector unsigned long long __a,
+ vector unsigned long long __b)
+{
+ return __builtin_altivec_crypto_vpmsumd(__a, __b);
+}
+#endif
+
#undef __ATTRS_o_ai
#endif /* __ALTIVEC_H */
diff --git a/lib/Headers/avx2intrin.h b/lib/Headers/avx2intrin.h
index 394fdfe..7485bdd 100644
--- a/lib/Headers/avx2intrin.h
+++ b/lib/Headers/avx2intrin.h
@@ -771,7 +771,7 @@
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
_mm256_broadcastsi128_si256(__m128i __X)
{
- return (__m256i)__builtin_ia32_vbroadcastsi256(__X);
+ return (__m256i)__builtin_shufflevector(__X, __X, 0, 1, 0, 1);
}
#define _mm_blend_epi32(V1, V2, M) __extension__ ({ \
@@ -874,14 +874,21 @@
__m256i __V2 = (V2); \
(__m256i)__builtin_ia32_permti256(__V1, __V2, (M)); })
-#define _mm256_extracti128_si256(A, O) __extension__ ({ \
- __m256i __A = (A); \
- (__m128i)__builtin_ia32_extract128i256(__A, (O)); })
+#define _mm256_extracti128_si256(V, M) __extension__ ({ \
+ (__m128i)__builtin_shufflevector( \
+ (__v4di)(V), \
+ (__v4di)(_mm256_setzero_si256()), \
+ (((M) & 1) ? 2 : 0), \
+ (((M) & 1) ? 3 : 1) );})
-#define _mm256_inserti128_si256(V1, V2, O) __extension__ ({ \
- __m256i __V1 = (V1); \
- __m128i __V2 = (V2); \
- (__m256i)__builtin_ia32_insert128i256(__V1, __V2, (O)); })
+#define _mm256_inserti128_si256(V1, V2, M) __extension__ ({ \
+ (__m256i)__builtin_shufflevector( \
+ (__v4di)(V1), \
+ (__v4di)_mm256_castsi128_si256((__m128i)(V2)), \
+ (((M) & 1) ? 0 : 4), \
+ (((M) & 1) ? 1 : 5), \
+ (((M) & 1) ? 4 : 2), \
+ (((M) & 1) ? 5 : 3) );})
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
_mm256_maskload_epi32(int const *__X, __m256i __M)
diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h
index d7c7f46..f30a5ad 100644
--- a/lib/Headers/avxintrin.h
+++ b/lib/Headers/avxintrin.h
@@ -429,19 +429,6 @@
__m128 __b = (b); \
(__m128)__builtin_ia32_cmpss((__v4sf)__a, (__v4sf)__b, (c)); })
-/* Vector extract */
-#define _mm256_extractf128_pd(A, O) __extension__ ({ \
- __m256d __A = (A); \
- (__m128d)__builtin_ia32_vextractf128_pd256((__v4df)__A, (O)); })
-
-#define _mm256_extractf128_ps(A, O) __extension__ ({ \
- __m256 __A = (A); \
- (__m128)__builtin_ia32_vextractf128_ps256((__v8sf)__A, (O)); })
-
-#define _mm256_extractf128_si256(A, O) __extension__ ({ \
- __m256i __A = (A); \
- (__m128i)__builtin_ia32_vextractf128_si256((__v8si)__A, (O)); })
-
static __inline int __attribute__((__always_inline__, __nodebug__))
_mm256_extract_epi32(__m256i __a, const int __imm)
{
@@ -472,22 +459,6 @@
}
#endif
-/* Vector insert */
-#define _mm256_insertf128_pd(V1, V2, O) __extension__ ({ \
- __m256d __V1 = (V1); \
- __m128d __V2 = (V2); \
- (__m256d)__builtin_ia32_vinsertf128_pd256((__v4df)__V1, (__v2df)__V2, (O)); })
-
-#define _mm256_insertf128_ps(V1, V2, O) __extension__ ({ \
- __m256 __V1 = (V1); \
- __m128 __V2 = (V2); \
- (__m256)__builtin_ia32_vinsertf128_ps256((__v8sf)__V1, (__v4sf)__V2, (O)); })
-
-#define _mm256_insertf128_si256(V1, V2, O) __extension__ ({ \
- __m256i __V1 = (V1); \
- __m128i __V2 = (V2); \
- (__m256i)__builtin_ia32_vinsertf128_si256((__v8si)__V1, (__v4si)__V2, (O)); })
-
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
_mm256_insert_epi32(__m256i __a, int __b, int const __imm)
{
@@ -1166,6 +1137,70 @@
return __builtin_shufflevector(__a, __a, 0, 1, -1, -1);
}
+/*
+ Vector insert.
+ We use macros rather than inlines because we only want to accept
+ invocations where the immediate M is a constant expression.
+*/
+#define _mm256_insertf128_ps(V1, V2, M) __extension__ ({ \
+ (__m256)__builtin_shufflevector( \
+ (__v8sf)(V1), \
+ (__v8sf)_mm256_castps128_ps256((__m128)(V2)), \
+ (((M) & 1) ? 0 : 8), \
+ (((M) & 1) ? 1 : 9), \
+ (((M) & 1) ? 2 : 10), \
+ (((M) & 1) ? 3 : 11), \
+ (((M) & 1) ? 8 : 4), \
+ (((M) & 1) ? 9 : 5), \
+ (((M) & 1) ? 10 : 6), \
+ (((M) & 1) ? 11 : 7) );})
+
+#define _mm256_insertf128_pd(V1, V2, M) __extension__ ({ \
+ (__m256d)__builtin_shufflevector( \
+ (__v4df)(V1), \
+ (__v4df)_mm256_castpd128_pd256((__m128d)(V2)), \
+ (((M) & 1) ? 0 : 4), \
+ (((M) & 1) ? 1 : 5), \
+ (((M) & 1) ? 4 : 2), \
+ (((M) & 1) ? 5 : 3) );})
+
+#define _mm256_insertf128_si256(V1, V2, M) __extension__ ({ \
+ (__m256i)__builtin_shufflevector( \
+ (__v4di)(V1), \
+ (__v4di)_mm256_castsi128_si256((__m128i)(V2)), \
+ (((M) & 1) ? 0 : 4), \
+ (((M) & 1) ? 1 : 5), \
+ (((M) & 1) ? 4 : 2), \
+ (((M) & 1) ? 5 : 3) );})
+
+/*
+ Vector extract.
+ We use macros rather than inlines because we only want to accept
+ invocations where the immediate M is a constant expression.
+*/
+#define _mm256_extractf128_ps(V, M) __extension__ ({ \
+ (__m128)__builtin_shufflevector( \
+ (__v8sf)(V), \
+ (__v8sf)(_mm256_setzero_ps()), \
+ (((M) & 1) ? 4 : 0), \
+ (((M) & 1) ? 5 : 1), \
+ (((M) & 1) ? 6 : 2), \
+ (((M) & 1) ? 7 : 3) );})
+
+#define _mm256_extractf128_pd(V, M) __extension__ ({ \
+ (__m128d)__builtin_shufflevector( \
+ (__v4df)(V), \
+ (__v4df)(_mm256_setzero_pd()), \
+ (((M) & 1) ? 2 : 0), \
+ (((M) & 1) ? 3 : 1) );})
+
+#define _mm256_extractf128_si256(V, M) __extension__ ({ \
+ (__m128i)__builtin_shufflevector( \
+ (__v4di)(V), \
+ (__v4di)(_mm256_setzero_si256()), \
+ (((M) & 1) ? 2 : 0), \
+ (((M) & 1) ? 3 : 1) );})
+
/* SIMD load ops (unaligned) */
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
_mm256_loadu2_m128(float const *__addr_hi, float const *__addr_lo)
diff --git a/lib/Headers/htmintrin.h b/lib/Headers/htmintrin.h
new file mode 100644
index 0000000..4598ee0
--- /dev/null
+++ b/lib/Headers/htmintrin.h
@@ -0,0 +1,131 @@
+/*===---- htmintrin.h - Standard header for PowerPC HTM ---------------===*\
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+\*===----------------------------------------------------------------------===*/
+
+#ifndef __HTMINTRIN_H
+#define __HTMINTRIN_H
+
+#ifndef __HTM__
+#error "HTM instruction set not enabled"
+#endif
+
+#ifdef __powerpc__
+
+#include <stdint.h>
+
+typedef uint64_t texasr_t;
+typedef uint32_t texasru_t;
+typedef uint32_t texasrl_t;
+typedef uintptr_t tfiar_t;
+typedef uintptr_t tfhar_t;
+
+#define _HTM_STATE(CR0) ((CR0 >> 1) & 0x3)
+#define _HTM_NONTRANSACTIONAL 0x0
+#define _HTM_SUSPENDED 0x1
+#define _HTM_TRANSACTIONAL 0x2
+
+#define _TEXASR_EXTRACT_BITS(TEXASR,BITNUM,SIZE) \
+ (((TEXASR) >> (63-(BITNUM))) & ((1<<(SIZE))-1))
+#define _TEXASRU_EXTRACT_BITS(TEXASR,BITNUM,SIZE) \
+ (((TEXASR) >> (31-(BITNUM))) & ((1<<(SIZE))-1))
+
+#define _TEXASR_FAILURE_CODE(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 7, 8)
+#define _TEXASRU_FAILURE_CODE(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 7, 8)
+
+#define _TEXASR_FAILURE_PERSISTENT(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 7, 1)
+#define _TEXASRU_FAILURE_PERSISTENT(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 7, 1)
+
+#define _TEXASR_DISALLOWED(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 8, 1)
+#define _TEXASRU_DISALLOWED(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 8, 1)
+
+#define _TEXASR_NESTING_OVERFLOW(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 9, 1)
+#define _TEXASRU_NESTING_OVERFLOW(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 9, 1)
+
+#define _TEXASR_FOOTPRINT_OVERFLOW(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 10, 1)
+#define _TEXASRU_FOOTPRINT_OVERFLOW(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 10, 1)
+
+#define _TEXASR_SELF_INDUCED_CONFLICT(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 11, 1)
+#define _TEXASRU_SELF_INDUCED_CONFLICT(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 11, 1)
+
+#define _TEXASR_NON_TRANSACTIONAL_CONFLICT(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 12, 1)
+#define _TEXASRU_NON_TRANSACTIONAL_CONFLICT(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 12, 1)
+
+#define _TEXASR_TRANSACTION_CONFLICT(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 13, 1)
+#define _TEXASRU_TRANSACTION_CONFLICT(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 13, 1)
+
+#define _TEXASR_TRANSLATION_INVALIDATION_CONFLICT(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 14, 1)
+#define _TEXASRU_TRANSLATION_INVALIDATION_CONFLICT(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 14, 1)
+
+#define _TEXASR_IMPLEMENTAION_SPECIFIC(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 15, 1)
+#define _TEXASRU_IMPLEMENTAION_SPECIFIC(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 15, 1)
+
+#define _TEXASR_INSTRUCTION_FETCH_CONFLICT(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 16, 1)
+#define _TEXASRU_INSTRUCTION_FETCH_CONFLICT(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 16, 1)
+
+#define _TEXASR_ABORT(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 31, 1)
+#define _TEXASRU_ABORT(TEXASRU) \
+ _TEXASRU_EXTRACT_BITS(TEXASRU, 31, 1)
+
+
+#define _TEXASR_SUSPENDED(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 32, 1)
+
+#define _TEXASR_PRIVILEGE(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 35, 2)
+
+#define _TEXASR_FAILURE_SUMMARY(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 36, 1)
+
+#define _TEXASR_TFIAR_EXACT(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 37, 1)
+
+#define _TEXASR_ROT(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 38, 1)
+
+#define _TEXASR_TRANSACTION_LEVEL(TEXASR) \
+ _TEXASR_EXTRACT_BITS(TEXASR, 63, 12)
+
+#endif /* __powerpc */
+
+#endif /* __HTMINTRIN_H */
diff --git a/lib/Headers/htmxlintrin.h b/lib/Headers/htmxlintrin.h
new file mode 100644
index 0000000..8791afe
--- /dev/null
+++ b/lib/Headers/htmxlintrin.h
@@ -0,0 +1,215 @@
+/*===---- htmxlintrin.h - XL compiler HTM execution intrinsics-------------===*\
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+\*===----------------------------------------------------------------------===*/
+
+#ifndef __HTMXLINTRIN_H
+#define __HTMXLINTRIN_H
+
+#ifndef __HTM__
+#error "HTM instruction set not enabled"
+#endif
+
+#include <htmintrin.h>
+
+#ifdef __powerpc__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define _TEXASR_PTR(TM_BUF) \
+ ((texasr_t *)((TM_BUF)+0))
+#define _TEXASRU_PTR(TM_BUF) \
+ ((texasru_t *)((TM_BUF)+0))
+#define _TEXASRL_PTR(TM_BUF) \
+ ((texasrl_t *)((TM_BUF)+4))
+#define _TFIAR_PTR(TM_BUF) \
+ ((tfiar_t *)((TM_BUF)+8))
+
+typedef char TM_buff_type[16];
+
+/* This macro can be used to determine whether a transaction was successfully
+ started from the __TM_begin() and __TM_simple_begin() intrinsic functions
+ below. */
+#define _HTM_TBEGIN_STARTED 1
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_simple_begin (void)
+{
+ if (__builtin_expect (__builtin_tbegin (0), 1))
+ return _HTM_TBEGIN_STARTED;
+ return 0;
+}
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_begin (void* const TM_buff)
+{
+ *_TEXASRL_PTR (TM_buff) = 0;
+ if (__builtin_expect (__builtin_tbegin (0), 1))
+ return _HTM_TBEGIN_STARTED;
+#ifdef __powerpc64__
+ *_TEXASR_PTR (TM_buff) = __builtin_get_texasr ();
+#else
+ *_TEXASRU_PTR (TM_buff) = __builtin_get_texasru ();
+ *_TEXASRL_PTR (TM_buff) = __builtin_get_texasr ();
+#endif
+ *_TFIAR_PTR (TM_buff) = __builtin_get_tfiar ();
+ return 0;
+}
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_end (void)
+{
+ if (__builtin_expect (__builtin_tend (0), 1))
+ return 1;
+ return 0;
+}
+
+extern __inline void
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_abort (void)
+{
+ __builtin_tabort (0);
+}
+
+extern __inline void
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_named_abort (unsigned char const code)
+{
+ __builtin_tabort (code);
+}
+
+extern __inline void
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_resume (void)
+{
+ __builtin_tresume ();
+}
+
+extern __inline void
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_suspend (void)
+{
+ __builtin_tsuspend ();
+}
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_is_user_abort (void* const TM_buff)
+{
+ texasru_t texasru = *_TEXASRU_PTR (TM_buff);
+ return _TEXASRU_ABORT (texasru);
+}
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_is_named_user_abort (void* const TM_buff, unsigned char *code)
+{
+ texasru_t texasru = *_TEXASRU_PTR (TM_buff);
+
+ *code = _TEXASRU_FAILURE_CODE (texasru);
+ return _TEXASRU_ABORT (texasru);
+}
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_is_illegal (void* const TM_buff)
+{
+ texasru_t texasru = *_TEXASRU_PTR (TM_buff);
+ return _TEXASRU_DISALLOWED (texasru);
+}
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_is_footprint_exceeded (void* const TM_buff)
+{
+ texasru_t texasru = *_TEXASRU_PTR (TM_buff);
+ return _TEXASRU_FOOTPRINT_OVERFLOW (texasru);
+}
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_nesting_depth (void* const TM_buff)
+{
+ texasrl_t texasrl;
+
+ if (_HTM_STATE (__builtin_ttest ()) == _HTM_NONTRANSACTIONAL)
+ {
+ texasrl = *_TEXASRL_PTR (TM_buff);
+ if (!_TEXASR_FAILURE_SUMMARY (texasrl))
+ texasrl = 0;
+ }
+ else
+ texasrl = (texasrl_t) __builtin_get_texasr ();
+
+ return _TEXASR_TRANSACTION_LEVEL (texasrl);
+}
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_is_nested_too_deep(void* const TM_buff)
+{
+ texasru_t texasru = *_TEXASRU_PTR (TM_buff);
+ return _TEXASRU_NESTING_OVERFLOW (texasru);
+}
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_is_conflict(void* const TM_buff)
+{
+ texasru_t texasru = *_TEXASRU_PTR (TM_buff);
+ /* Return TEXASR bits 11 (Self-Induced Conflict) through
+ 14 (Translation Invalidation Conflict). */
+ return (_TEXASRU_EXTRACT_BITS (texasru, 14, 4)) ? 1 : 0;
+}
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_is_failure_persistent(void* const TM_buff)
+{
+ texasru_t texasru = *_TEXASRU_PTR (TM_buff);
+ return _TEXASRU_FAILURE_PERSISTENT (texasru);
+}
+
+extern __inline long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_failure_address(void* const TM_buff)
+{
+ return *_TFIAR_PTR (TM_buff);
+}
+
+extern __inline long long
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__TM_failure_code(void* const TM_buff)
+{
+ return *_TEXASR_PTR (TM_buff);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __powerpc__ */
+
+#endif /* __HTMXLINTRIN_H */
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index b94cdbd..3e59cdb 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -149,7 +149,7 @@
SmallString<128> HashStr;
llvm::APInt(64, size_t(Hash)).toStringUnsigned(HashStr, /*Radix*/36);
- llvm::sys::path::append(Result, ModuleName + "-" + HashStr.str() + ".pcm");
+ llvm::sys::path::append(Result, ModuleName + "-" + HashStr + ".pcm");
}
return Result.str().str();
}
@@ -297,7 +297,7 @@
RelativePath->append(Filename.begin(), Filename.end());
}
- return getFileAndSuggestModule(HS, TmpDir.str(), getDir(),
+ return getFileAndSuggestModule(HS, TmpDir, getDir(),
isSystemHeaderDirectory(),
SuggestedModule);
}
@@ -438,7 +438,7 @@
HS.IncrementFrameworkLookupCount();
// If the framework dir doesn't exist, we fail.
- const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str());
+ const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName);
if (!Dir) return nullptr;
// Otherwise, if it does, remember that this is the right direntry for this
@@ -450,7 +450,7 @@
if (getDirCharacteristic() == SrcMgr::C_User) {
SmallString<1024> SystemFrameworkMarker(FrameworkName);
SystemFrameworkMarker += ".system_framework";
- if (llvm::sys::fs::exists(SystemFrameworkMarker.str())) {
+ if (llvm::sys::fs::exists(SystemFrameworkMarker)) {
CacheEntry.IsUserSpecifiedSystemFramework = true;
}
}
@@ -476,7 +476,7 @@
}
FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
- const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
+ const FileEntry *FE = FileMgr.getFile(FrameworkName,
/*openFile=*/!SuggestedModule);
if (!FE) {
// Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
@@ -487,7 +487,7 @@
SearchPath->insert(SearchPath->begin()+OrigSize, Private,
Private+strlen(Private));
- FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!SuggestedModule);
+ FE = FileMgr.getFile(FrameworkName, /*openFile=*/!SuggestedModule);
}
// If we found the header and are allowed to suggest a module, do so now.
@@ -628,7 +628,7 @@
bool IncluderIsSystemHeader =
Includer && getFileInfo(Includer).DirInfo != SrcMgr::C_User;
if (const FileEntry *FE = getFileAndSuggestModule(
- *this, TmpDir.str(), IncluderAndDir.second,
+ *this, TmpDir, IncluderAndDir.second,
IncluderIsSystemHeader, SuggestedModule)) {
if (!Includer) {
assert(First && "only first includer can have no file");
@@ -865,7 +865,7 @@
++NumSubFrameworkLookups;
// If the framework dir doesn't exist, we fail.
- const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str());
+ const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName);
if (!Dir) return nullptr;
// Otherwise, if it does, remember that this is the right direntry for this
@@ -890,7 +890,7 @@
}
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
- if (!(FE = FileMgr.getFile(HeadersFilename.str(), /*openFile=*/true))) {
+ if (!(FE = FileMgr.getFile(HeadersFilename, /*openFile=*/true))) {
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
HeadersFilename = FrameworkName;
@@ -902,7 +902,7 @@
}
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
- if (!(FE = FileMgr.getFile(HeadersFilename.str(), /*openFile=*/true)))
+ if (!(FE = FileMgr.getFile(HeadersFilename, /*openFile=*/true)))
return nullptr;
}
@@ -1284,7 +1284,7 @@
DirNative);
// Search each of the ".framework" directories to load them as modules.
- for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+ for (llvm::sys::fs::directory_iterator Dir(DirNative, EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
if (llvm::sys::path::extension(Dir->path()) != ".framework")
continue;
@@ -1351,7 +1351,7 @@
std::error_code EC;
SmallString<128> DirNative;
llvm::sys::path::native(SearchDir.getDir()->getName(), DirNative);
- for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+ for (llvm::sys::fs::directory_iterator Dir(DirNative, EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
bool IsFramework = llvm::sys::path::extension(Dir->path()) == ".framework";
if (IsFramework == SearchDir.isFramework())
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index ca5252e..a3b520b 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -143,14 +143,8 @@
/// range will outlive it, so it doesn't take ownership of it.
Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile,
const SourceManager &SM, const LangOptions &langOpts)
- : FileLoc(SM.getLocForStartOfFile(FID)), LangOpts(langOpts) {
-
- InitLexer(FromFile->getBufferStart(), FromFile->getBufferStart(),
- FromFile->getBufferEnd());
-
- // We *are* in raw mode.
- LexingRawMode = true;
-}
+ : Lexer(SM.getLocForStartOfFile(FID), langOpts, FromFile->getBufferStart(),
+ FromFile->getBufferStart(), FromFile->getBufferEnd()) {}
/// Create_PragmaLexer: Lexer constructor - Create a new lexer object for
/// _Pragma expansion. This has a variety of magic semantics that this method
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 03331fb..af3e27f 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -144,7 +144,8 @@
int CharVal = llvm::hexDigitValue(ThisTokBuf[0]);
if (CharVal == -1) break;
// About to shift out a digit?
- Overflow |= (ResultChar & 0xF0000000) ? true : false;
+ if (ResultChar & 0xF0000000)
+ Overflow = true;
ResultChar <<= 4;
ResultChar |= CharVal;
}
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 0bb9856..a4f1c05 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -205,35 +205,32 @@
return KnownHeader();
}
-// Returns true if RequestingModule directly uses RequestedModule.
-static bool directlyUses(const Module *RequestingModule,
- const Module *RequestedModule) {
- return std::find(RequestingModule->DirectUses.begin(),
- RequestingModule->DirectUses.end(),
- RequestedModule) != RequestingModule->DirectUses.end();
-}
-
static bool violatesPrivateInclude(Module *RequestingModule,
const FileEntry *IncFileEnt,
ModuleMap::ModuleHeaderRole Role,
Module *RequestedModule) {
bool IsPrivateRole = Role & ModuleMap::PrivateHeader;
#ifndef NDEBUG
- // Check for consistency between the module header role
- // as obtained from the lookup and as obtained from the module.
- // This check is not cheap, so enable it only for debugging.
- bool IsPrivate = false;
- SmallVectorImpl<Module::Header> *HeaderList[] =
- {&RequestedModule->Headers[Module::HK_Private],
- &RequestedModule->Headers[Module::HK_PrivateTextual]};
- for (auto *Hdrs : HeaderList)
- IsPrivate |=
- std::find_if(Hdrs->begin(), Hdrs->end(), [&](const Module::Header &H) {
- return H.Entry == IncFileEnt;
- }) != Hdrs->end();
- assert(IsPrivate == IsPrivateRole && "inconsistent headers and roles");
+ if (IsPrivateRole) {
+ // Check for consistency between the module header role
+ // as obtained from the lookup and as obtained from the module.
+ // This check is not cheap, so enable it only for debugging.
+ bool IsPrivate = false;
+ SmallVectorImpl<Module::Header> *HeaderList[] = {
+ &RequestedModule->Headers[Module::HK_Private],
+ &RequestedModule->Headers[Module::HK_PrivateTextual]};
+ for (auto *Hs : HeaderList)
+ IsPrivate |=
+ std::find_if(Hs->begin(), Hs->end(), [&](const Module::Header &H) {
+ return H.Entry == IncFileEnt;
+ }) != Hs->end();
+ assert((!IsPrivateRole || IsPrivate) && "inconsistent headers and roles");
+ }
#endif
return IsPrivateRole &&
+ // FIXME: Should we map RequestingModule to its top-level module here
+ // too? This check is redundant with the isSubModuleOf check in
+ // diagnoseHeaderInclusion.
RequestedModule->getTopLevelModule() != RequestingModule;
}
@@ -261,7 +258,8 @@
if (Known != Headers.end()) {
for (const KnownHeader &Header : Known->second) {
// If 'File' is part of 'RequestingModule' we can definitely include it.
- if (Header.getModule() == RequestingModule)
+ if (Header.getModule() &&
+ Header.getModule()->isSubModuleOf(RequestingModule))
return;
// Remember private headers for later printing of a diagnostic.
@@ -274,7 +272,7 @@
// If uses need to be specified explicitly, we are only allowed to return
// modules that are explicitly used by the requesting module.
if (RequestingModule && LangOpts.ModulesDeclUse &&
- !directlyUses(RequestingModule, Header.getModule())) {
+ !RequestingModule->directlyUses(Header.getModule())) {
NotUsed = Header.getModule();
continue;
}
@@ -363,7 +361,7 @@
// If uses need to be specified explicitly, we are only allowed to return
// modules that are explicitly used by the requesting module.
if (RequestingModule && LangOpts.ModulesDeclUse &&
- !directlyUses(RequestingModule, I->getModule()))
+ !RequestingModule->directlyUses(I->getModule()))
continue;
if (!Result || isBetterKnownHeader(*I, Result))
@@ -728,8 +726,7 @@
= StringRef(FrameworkDir->getName());
llvm::sys::path::append(SubframeworksDirName, "Frameworks");
llvm::sys::path::native(SubframeworksDirName);
- for (llvm::sys::fs::directory_iterator
- Dir(SubframeworksDirName.str(), EC), DirEnd;
+ for (llvm::sys::fs::directory_iterator Dir(SubframeworksDirName, EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
if (!StringRef(Dir->path()).endswith(".framework"))
continue;
@@ -1582,7 +1579,7 @@
if (llvm::sys::path::is_relative(FileNameRef)) {
ModuleMapFileName += Directory->getName();
llvm::sys::path::append(ModuleMapFileName, FileName);
- FileNameRef = ModuleMapFileName.str();
+ FileNameRef = ModuleMapFileName;
}
if (const FileEntry *File = SourceMgr.getFileManager().getFile(FileNameRef))
Map.parseModuleMapFile(
@@ -1729,7 +1726,7 @@
// Check whether this file is in the public headers.
llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);
- llvm::sys::path::append(FullPathName, RelativePathName.str());
+ llvm::sys::path::append(FullPathName, RelativePathName);
File = SourceMgr.getFileManager().getFile(FullPathName);
if (!File) {
@@ -1739,13 +1736,13 @@
FullPathName.resize(FullPathLength);
llvm::sys::path::append(RelativePathName, "PrivateHeaders",
Header.FileName);
- llvm::sys::path::append(FullPathName, RelativePathName.str());
+ llvm::sys::path::append(FullPathName, RelativePathName);
File = SourceMgr.getFileManager().getFile(FullPathName);
}
} else {
// Lookup for normal headers.
llvm::sys::path::append(RelativePathName, Header.FileName);
- llvm::sys::path::append(FullPathName, RelativePathName.str());
+ llvm::sys::path::append(FullPathName, RelativePathName);
File = SourceMgr.getFileManager().getFile(FullPathName);
// If this is a system module with a top-level header, this header
@@ -1914,18 +1911,21 @@
ActiveModule->UnresolvedExports.push_back(Unresolved);
}
-/// \brief Parse a module uses declaration.
+/// \brief Parse a module use declaration.
///
-/// uses-declaration:
-/// 'uses' wildcard-module-id
+/// use-declaration:
+/// 'use' wildcard-module-id
void ModuleMapParser::parseUseDecl() {
assert(Tok.is(MMToken::UseKeyword));
- consumeToken();
+ auto KWLoc = consumeToken();
// Parse the module-id.
ModuleId ParsedModuleId;
parseModuleId(ParsedModuleId);
- ActiveModule->UnresolvedDirectUses.push_back(ParsedModuleId);
+ if (ActiveModule->Parent)
+ Diags.Report(KWLoc, diag::err_mmap_use_decl_submodule);
+ else
+ ActiveModule->UnresolvedDirectUses.push_back(ParsedModuleId);
}
/// \brief Parse a link declaration.
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index bf0ce72..a50c8a8 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1233,7 +1233,7 @@
// Find the first non-whitespace character, so that we can make the
// diagnostic more succinct.
- StringRef Msg = Message.str().ltrim(" ");
+ StringRef Msg = StringRef(Message).ltrim(" ");
if (isWarning)
Diag(Tok, diag::pp_hash_warning) << Msg;
@@ -1491,7 +1491,7 @@
FilenameBuffer.push_back('<');
if (ConcatenateIncludeName(FilenameBuffer, End))
return; // Found <eod> but no ">"? Diagnostic already emitted.
- Filename = FilenameBuffer.str();
+ Filename = FilenameBuffer;
CharEnd = End.getLocWithOffset(1);
break;
default:
@@ -1680,9 +1680,9 @@
CharSourceRange ReplaceRange(SourceRange(HashLoc, CharEnd),
/*IsTokenRange=*/false);
Diag(HashLoc, diag::warn_auto_module_import)
- << IncludeKind << PathString
- << FixItHint::CreateReplacement(ReplaceRange,
- "@import " + PathString.str().str() + ";");
+ << IncludeKind << PathString
+ << FixItHint::CreateReplacement(
+ ReplaceRange, ("@import " + PathString + ";").str());
}
// Load the module. Only make macros visible. We'll make the declarations
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index b986ada..7763181 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -598,7 +598,7 @@
// If this is a comment token in the argument list and we're just in
// -C mode (not -CC mode), discard the comment.
continue;
- } else if (Tok.getIdentifierInfo() != nullptr) {
+ } else if (!Tok.isAnnotation() && Tok.getIdentifierInfo() != nullptr) {
// Reading macro arguments can cause macros that we are currently
// expanding from to be popped off the expansion stack. Doing so causes
// them to be reenabled for expansion. Here we record whether any
@@ -868,6 +868,7 @@
.Case("attribute_analyzer_noreturn", true)
.Case("attribute_availability", true)
.Case("attribute_availability_with_message", true)
+ .Case("attribute_availability_app_extension", true)
.Case("attribute_cf_returns_not_retained", true)
.Case("attribute_cf_returns_retained", true)
.Case("attribute_deprecated_with_message", true)
@@ -1130,7 +1131,7 @@
Tok.setKind(tok::eod);
return false; // Found <eod> but no ">"? Diagnostic already emitted.
}
- Filename = FilenameBuffer.str();
+ Filename = FilenameBuffer;
break;
default:
PP.Diag(Tok.getLocation(), diag::err_pp_expects_filename);
@@ -1313,7 +1314,7 @@
if (PLoc.isValid()) {
FN += PLoc.getFilename();
Lexer::Stringify(FN);
- OS << '"' << FN.str() << '"';
+ OS << '"' << FN << '"';
}
Tok.setKind(tok::string_literal);
} else if (II == Ident__DATE__) {
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 8ed8328..bfac3fd 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -648,7 +648,7 @@
SourceLocation End;
if (ConcatenateIncludeName(FileNameBuffer, End))
return; // Diagnostic already emitted
- SourceFileName = FileNameBuffer.str();
+ SourceFileName = FileNameBuffer;
} else {
Diag(Tok, diag::warn_pragma_include_alias_expected_filename);
return;
@@ -679,7 +679,7 @@
SourceLocation End;
if (ConcatenateIncludeName(FileNameBuffer, End))
return; // Diagnostic already emitted
- ReplaceFileName = FileNameBuffer.str();
+ ReplaceFileName = FileNameBuffer;
} else {
Diag(Tok, diag::warn_pragma_include_alias_expected_filename);
return;
@@ -870,7 +870,9 @@
LLVM_BUILTIN_TRAP;
} else if (II->isStr("parser_crash")) {
Token Crasher;
+ Crasher.startToken();
Crasher.setKind(tok::annot_pragma_parser_crash);
+ Crasher.setAnnotationRange(SourceRange(Tok.getLocation()));
PP.EnterToken(Crasher);
} else if (II->isStr("llvm_fatal_error")) {
llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error");
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 7abd340..dafcbbe 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -73,11 +73,8 @@
SourceLocation Loc = PPE->getSourceRange().getBegin();
if (Loc.isInvalid())
return false;
-
- if (SM.isInFileID(SM.getFileLoc(Loc), FID))
- return true;
- else
- return false;
+
+ return SM.isInFileID(SM.getFileLoc(Loc), FID);
}
/// \brief Returns true if the preprocessed entity that \arg PPEI iterator
@@ -91,7 +88,7 @@
if (FID.isInvalid())
return false;
- int Pos = PPEI.Position;
+ int Pos = std::distance(iterator(this, 0), PPEI);
if (Pos < 0) {
if (unsigned(-Pos-1) >= LoadedPreprocessedEntities.size()) {
assert(0 && "Out-of bounds loaded preprocessed entity");
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index b2a6d93..51a038a 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -321,11 +321,11 @@
StringRef BestSpelling;
for (Preprocessor::macro_iterator I = macro_begin(), E = macro_end();
I != E; ++I) {
- if (!I->second->getMacroInfo()->isObjectLike())
- continue;
const MacroDirective::DefInfo
Def = I->second->findDirectiveAtLoc(Loc, SourceMgr);
- if (!Def)
+ if (!Def || !Def.getMacroInfo())
+ continue;
+ if (!Def.getMacroInfo()->isObjectLike())
continue;
if (!MacroDefinitionEquals(Def.getMacroInfo(), Tokens))
continue;
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index 5f4705e..23d7281 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -637,7 +637,7 @@
// disabling it.
PP.Diag(Loc, PP.getLangOpts().MicrosoftExt ? diag::ext_pp_bad_paste_ms
: diag::err_pp_bad_paste)
- << Buffer.str();
+ << Buffer;
}
// An error has occurred so exit loop.
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index a53079b..5da70d0 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -26,8 +26,7 @@
AttributeList *AccessAttrs,
ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
- const VirtSpecifiers& VS,
- FunctionDefinitionKind DefinitionKind,
+ const VirtSpecifiers& VS,
ExprResult& Init) {
assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) ||
@@ -40,7 +39,6 @@
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
NamedDecl *FnD;
- D.setFunctionDefinitionKind(DefinitionKind);
if (D.getDeclSpec().isFriendSpecified())
FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D,
TemplateParams);
@@ -71,17 +69,24 @@
bool Delete = false;
SourceLocation KWLoc;
+ SourceLocation KWEndLoc = Tok.getEndLoc().getLocWithOffset(-1);
if (TryConsumeToken(tok::kw_delete, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_deleted_function
: diag::ext_deleted_function);
Actions.SetDeclDeleted(FnD, KWLoc);
Delete = true;
+ if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) {
+ DeclAsFunction->setRangeEnd(KWEndLoc);
+ }
} else if (TryConsumeToken(tok::kw_default, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_defaulted_function
: diag::ext_defaulted_function);
Actions.SetDeclDefaulted(FnD, KWLoc);
+ if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) {
+ DeclAsFunction->setRangeEnd(KWEndLoc);
+ }
} else {
llvm_unreachable("function definition after = not 'delete' or 'default'");
}
@@ -97,12 +102,12 @@
return FnD;
}
-
+
// In delayed template parsing mode, if we are within a class template
// or if we are about to parse function member template then consume
// the tokens and store them for parsing at the end of the translation unit.
if (getLangOpts().DelayedTemplateParsing &&
- DefinitionKind == FDK_Definition &&
+ D.getFunctionDefinitionKind() == FDK_Definition &&
!D.getDeclSpec().isConstexprSpecified() &&
!(FnD && FnD->getAsFunction() &&
FnD->getAsFunction()->getReturnType()->getContainedAutoType()) &&
@@ -317,8 +322,7 @@
Token DefArgEnd;
DefArgEnd.startToken();
DefArgEnd.setKind(tok::eof);
- DefArgEnd.setLocation(LastDefaultArgToken.getLocation().getLocWithOffset(
- LastDefaultArgToken.getLength()));
+ DefArgEnd.setLocation(LastDefaultArgToken.getEndLoc());
DefArgEnd.setEofData(Param);
Toks->push_back(DefArgEnd);
@@ -392,9 +396,7 @@
Token ExceptionSpecEnd;
ExceptionSpecEnd.startToken();
ExceptionSpecEnd.setKind(tok::eof);
- ExceptionSpecEnd.setLocation(
- LastExceptionSpecToken.getLocation().getLocWithOffset(
- LastExceptionSpecToken.getLength()));
+ ExceptionSpecEnd.setLocation(LastExceptionSpecToken.getEndLoc());
ExceptionSpecEnd.setEofData(LM.Method);
Toks->push_back(ExceptionSpecEnd);
@@ -499,8 +501,7 @@
Token BodyEnd;
BodyEnd.startToken();
BodyEnd.setKind(tok::eof);
- BodyEnd.setLocation(
- LastBodyToken.getLocation().getLocWithOffset(LastBodyToken.getLength()));
+ BodyEnd.setLocation(LastBodyToken.getEndLoc());
BodyEnd.setEofData(LM.D);
LM.Toks.push_back(BodyEnd);
// Append the current token at the end of the new token stream so that it
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index b6264d4..5726fb6 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -547,7 +547,7 @@
// We expect either a well-known identifier or a generic string. Anything
// else is a malformed declspec.
- bool IsString = Tok.getKind() == tok::string_literal ? true : false;
+ bool IsString = Tok.getKind() == tok::string_literal;
if (!IsString && Tok.getKind() != tok::identifier &&
Tok.getKind() != tok::kw_restrict) {
Diag(Tok, diag::err_ms_declspec_type);
@@ -2569,7 +2569,8 @@
bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
bool AttrsLastTime = false;
ParsedAttributesWithRange attrs(AttrFactory);
- const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
+ // We use Sema's policy to get bool macros right.
+ const PrintingPolicy &Policy = Actions.getPrintingPolicy();
while (1) {
bool isInvalid = false;
bool isStorageClass = false;
@@ -5328,7 +5329,7 @@
if (getLangOpts().CPlusPlus) {
// FIXME: Accept these components in any order, and produce fixits to
// correct the order if the user gets it wrong. Ideally we should deal
- // with the virt-specifier-seq and pure-specifier in the same way.
+ // with the pure-specifier in the same way.
// Parse cv-qualifier-seq[opt].
ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed,
@@ -5341,15 +5342,8 @@
}
// Parse ref-qualifier[opt].
- if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) {
- Diag(Tok, getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_ref_qualifier :
- diag::ext_ref_qualifier);
-
- RefQualifierIsLValueRef = Tok.is(tok::amp);
- RefQualifierLoc = ConsumeToken();
+ if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc))
EndLoc = RefQualifierLoc;
- }
// C++11 [expr.prim.general]p3:
// If a declaration declares a member function or member function
@@ -5445,6 +5439,22 @@
FnAttrs, EndLoc);
}
+/// ParseRefQualifier - Parses a member function ref-qualifier. Returns
+/// true if a ref-qualifier is found.
+bool Parser::ParseRefQualifier(bool &RefQualifierIsLValueRef,
+ SourceLocation &RefQualifierLoc) {
+ if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) {
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
+ diag::warn_cxx98_compat_ref_qualifier :
+ diag::ext_ref_qualifier);
+
+ RefQualifierIsLValueRef = Tok.is(tok::amp);
+ RefQualifierLoc = ConsumeToken();
+ return true;
+ }
+ return false;
+}
+
/// isFunctionDeclaratorIdentifierList - This parameter list may have an
/// identifier list form for a K&R-style function: void foo(a,b,c)
///
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 5f7893c..ec19f35 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -558,6 +558,7 @@
// Maybe this is an alias-declaration.
TypeResult TypeAlias;
bool IsAliasDecl = Tok.is(tok::equal);
+ Decl *DeclFromDeclSpec = nullptr;
if (IsAliasDecl) {
// If we had any misplaced attributes from earlier, this is where they
// should have been written.
@@ -612,10 +613,12 @@
Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
<< FixItHint::CreateRemoval(SS.getRange());
- TypeAlias = ParseTypeName(nullptr, TemplateInfo.Kind ?
- Declarator::AliasTemplateContext :
- Declarator::AliasDeclContext, AS, OwnedType,
- &Attrs);
+ TypeAlias = ParseTypeName(nullptr, TemplateInfo.Kind
+ ? Declarator::AliasTemplateContext
+ : Declarator::AliasDeclContext,
+ AS, &DeclFromDeclSpec, &Attrs);
+ if (OwnedType)
+ *OwnedType = DeclFromDeclSpec;
} else {
// C++11 attributes are not allowed on a using-declaration, but GNU ones
// are.
@@ -664,7 +667,7 @@
TemplateParams ? TemplateParams->size() : 0);
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
UsingLoc, Name, Attrs.getList(),
- TypeAlias);
+ TypeAlias, DeclFromDeclSpec);
}
return Actions.ActOnUsingDeclaration(getCurScope(), AS,
@@ -1547,6 +1550,7 @@
TypeResult TypeResult = true; // invalid
bool Owned = false;
+ bool SkipBody = false;
if (TemplateId) {
// Explicit specialization, class template partial specialization,
// or explicit instantiation.
@@ -1692,7 +1696,8 @@
TParams, Owned, IsDependent,
SourceLocation(), false,
clang::TypeResult(),
- DSC == DSC_type_specifier);
+ DSC == DSC_type_specifier,
+ &SkipBody);
// If ActOnTag said the type was dependent, try again with the
// less common call.
@@ -1708,7 +1713,10 @@
assert(Tok.is(tok::l_brace) ||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
isCXX11FinalKeyword());
- if (getLangOpts().CPlusPlus)
+ if (SkipBody)
+ SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType,
+ TagOrTempResult.get());
+ else if (getLangOpts().CPlusPlus)
ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType,
TagOrTempResult.get());
else
@@ -2034,10 +2042,13 @@
BitfieldSize = ParseConstantExpression();
if (BitfieldSize.isInvalid())
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
- } else
+ } else {
ParseOptionalCXX11VirtSpecifierSeq(
VS, getCurrentClass().IsInterface,
DeclaratorInfo.getDeclSpec().getFriendSpecLoc());
+ if (!VS.isUnset())
+ MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo, VS);
+ }
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
@@ -2068,6 +2079,7 @@
Diag(Attr->getLoc(), diag::warn_gcc_attribute_location);
Attr = Attr->getNext();
}
+ MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo, VS);
}
}
@@ -2081,6 +2093,68 @@
return false;
}
+/// \brief Look for declaration specifiers possibly occurring after C++11
+/// virt-specifier-seq and diagnose them.
+void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(
+ Declarator &D,
+ VirtSpecifiers &VS) {
+ DeclSpec DS(AttrFactory);
+
+ // GNU-style and C++11 attributes are not allowed here, but they will be
+ // handled by the caller. Diagnose everything else.
+ ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, false);
+ D.ExtendWithDeclSpec(DS);
+
+ if (D.isFunctionDeclarator()) {
+ auto &Function = D.getFunctionTypeInfo();
+ if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
+ auto DeclSpecCheck = [&] (DeclSpec::TQ TypeQual,
+ const char *FixItName,
+ SourceLocation SpecLoc,
+ unsigned* QualifierLoc) {
+ FixItHint Insertion;
+ if (DS.getTypeQualifiers() & TypeQual) {
+ if (!(Function.TypeQuals & TypeQual)) {
+ std::string Name(FixItName);
+ Name += " ";
+ Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name.c_str());
+ Function.TypeQuals |= TypeQual;
+ *QualifierLoc = SpecLoc.getRawEncoding();
+ }
+ Diag(SpecLoc, diag::err_declspec_after_virtspec)
+ << FixItName
+ << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier())
+ << FixItHint::CreateRemoval(SpecLoc)
+ << Insertion;
+ }
+ };
+ DeclSpecCheck(DeclSpec::TQ_const, "const", DS.getConstSpecLoc(),
+ &Function.ConstQualifierLoc);
+ DeclSpecCheck(DeclSpec::TQ_volatile, "volatile", DS.getVolatileSpecLoc(),
+ &Function.VolatileQualifierLoc);
+ DeclSpecCheck(DeclSpec::TQ_restrict, "restrict", DS.getRestrictSpecLoc(),
+ &Function.RestrictQualifierLoc);
+ }
+
+ // Parse ref-qualifiers.
+ bool RefQualifierIsLValueRef = true;
+ SourceLocation RefQualifierLoc;
+ if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) {
+ const char *Name = (RefQualifierIsLValueRef ? "& " : "&& ");
+ FixItHint Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name);
+ Function.RefQualifierIsLValueRef = RefQualifierIsLValueRef;
+ Function.RefQualifierLoc = RefQualifierLoc.getRawEncoding();
+
+ Diag(RefQualifierLoc, diag::err_declspec_after_virtspec)
+ << (RefQualifierIsLValueRef ? "&" : "&&")
+ << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier())
+ << FixItHint::CreateRemoval(RefQualifierLoc)
+ << Insertion;
+ D.SetRangeEnd(RefQualifierLoc);
+ }
+ }
+}
+
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
///
/// member-declaration:
@@ -2344,6 +2418,7 @@
DefinitionKind = FDK_Deleted;
}
}
+ DeclaratorInfo.setFunctionDefinitionKind(DefinitionKind);
// C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains
// to a friend declaration, that declaration shall be a definition.
@@ -2376,7 +2451,7 @@
Decl *FunDecl =
ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo,
- VS, DefinitionKind, Init);
+ VS, Init);
if (FunDecl) {
for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) {
@@ -2618,6 +2693,55 @@
return ParseInitializer();
}
+void Parser::SkipCXXMemberSpecification(SourceLocation RecordLoc,
+ SourceLocation AttrFixitLoc,
+ unsigned TagType, Decl *TagDecl) {
+ // Skip the optional 'final' keyword.
+ if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) {
+ assert(isCXX11FinalKeyword() && "not a class definition");
+ ConsumeToken();
+
+ // Diagnose any C++11 attributes after 'final' keyword.
+ // We deliberately discard these attributes.
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc);
+
+ // This can only happen if we had malformed misplaced attributes;
+ // we only get called if there is a colon or left-brace after the
+ // attributes.
+ if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_brace))
+ return;
+ }
+
+ // Skip the base clauses. This requires actually parsing them, because
+ // otherwise we can't be sure where they end (a left brace may appear
+ // within a template argument).
+ if (Tok.is(tok::colon)) {
+ // Enter the scope of the class so that we can correctly parse its bases.
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
+ ParsingClassDefinition ParsingDef(*this, TagDecl, /*NonNestedClass*/ true,
+ TagType == DeclSpec::TST_interface);
+ Actions.ActOnTagStartSkippedDefinition(getCurScope(), TagDecl);
+
+ // Parse the bases but don't attach them to the class.
+ ParseBaseClause(nullptr);
+
+ Actions.ActOnTagFinishSkippedDefinition();
+
+ if (!Tok.is(tok::l_brace)) {
+ Diag(PP.getLocForEndOfToken(PrevTokLocation),
+ diag::err_expected_lbrace_after_base_specifiers);
+ return;
+ }
+ }
+
+ // Skip the body.
+ assert(Tok.is(tok::l_brace));
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ T.consumeOpen();
+ T.skipToEnd();
+}
+
/// ParseCXXMemberSpecification - Parse the class definition.
///
/// member-specification:
@@ -2912,6 +3036,10 @@
ParseLexedMemberInitializers(getCurrentClass());
ParseLexedMethodDefs(getCurrentClass());
PrevTokLocation = SavedPrevTokLocation;
+
+ // We've finished parsing everything, including default argument
+ // initializers.
+ Actions.ActOnFinishCXXMemberDefaultArgs(TagDecl);
}
if (TagDecl)
@@ -2966,9 +3094,11 @@
/// mem-initializer ...[opt]
/// mem-initializer ...[opt] , mem-initializer-list
void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
- assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'");
+ assert(Tok.is(tok::colon) &&
+ "Constructor initializer always starts with ':'");
- // Poison the SEH identifiers so they are flagged as illegal in constructor initializers
+ // Poison the SEH identifiers so they are flagged as illegal in constructor
+ // initializers.
PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
SourceLocation ColonLoc = ConsumeToken();
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 07af62f..72af14d 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -1459,6 +1459,9 @@
})) {
(void)Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
+ } else if (LHS.isInvalid()) {
+ for (auto &E : ArgExprs)
+ Actions.CorrectDelayedTyposInExpr(E);
}
}
}
@@ -2368,7 +2371,8 @@
// C11 6.5.1.1p3 "The controlling expression of a generic selection is
// not evaluated."
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
- ControllingExpr = ParseAssignmentExpression();
+ ControllingExpr =
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (ControllingExpr.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
@@ -2414,7 +2418,8 @@
// FIXME: These expressions should be parsed in a potentially potentially
// evaluated context.
- ExprResult ER(ParseAssignmentExpression());
+ ExprResult ER(
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
if (ER.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 6cff1c5..1030072 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -118,6 +118,7 @@
// Eat the '('.
ConsumeParen();
Token RParen;
+ RParen.setLocation(SourceLocation());
// Do we have a ')' ?
NextTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : GetLookAheadToken(1);
if (NextTok.is(tok::r_paren)) {
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 7fe9862..42287d6 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -148,7 +148,7 @@
Diag(NameLoc, diag::ext_gnu_old_style_field_designator)
<< FixItHint::CreateReplacement(SourceRange(NameLoc, ColonLoc),
- NewSyntax.str());
+ NewSyntax);
Designation D;
D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc));
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 5f89f01..96484b4 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -198,9 +198,12 @@
OpenMPHandler.reset(new PragmaNoOpenMPHandler());
PP.AddPragmaHandler(OpenMPHandler.get());
- if (getLangOpts().MicrosoftExt) {
+ if (getLangOpts().MicrosoftExt || getTargetInfo().getTriple().isPS4()) {
MSCommentHandler.reset(new PragmaCommentHandler(Actions));
PP.AddPragmaHandler(MSCommentHandler.get());
+ }
+
+ if (getLangOpts().MicrosoftExt) {
MSDetectMismatchHandler.reset(new PragmaDetectMismatchHandler(Actions));
PP.AddPragmaHandler(MSDetectMismatchHandler.get());
MSPointersToMembers.reset(new PragmaMSPointersToMembers());
@@ -219,9 +222,6 @@
PP.AddPragmaHandler(MSCodeSeg.get());
MSSection.reset(new PragmaMSPragma("section"));
PP.AddPragmaHandler(MSSection.get());
- } else if (getTargetInfo().getTriple().isPS4()) {
- MSCommentHandler.reset(new PragmaCommentHandler(Actions));
- PP.AddPragmaHandler(MSCommentHandler.get());
}
OptimizeHandler.reset(new PragmaOptimizeHandler(Actions));
@@ -264,9 +264,12 @@
PP.RemovePragmaHandler(OpenMPHandler.get());
OpenMPHandler.reset();
- if (getLangOpts().MicrosoftExt) {
+ if (getLangOpts().MicrosoftExt || getTargetInfo().getTriple().isPS4()) {
PP.RemovePragmaHandler(MSCommentHandler.get());
MSCommentHandler.reset();
+ }
+
+ if (getLangOpts().MicrosoftExt) {
PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
MSDetectMismatchHandler.reset();
PP.RemovePragmaHandler(MSPointersToMembers.get());
@@ -285,9 +288,6 @@
MSCodeSeg.reset();
PP.RemovePragmaHandler(MSSection.get());
MSSection.reset();
- } else if (getTargetInfo().getTriple().isPS4()) {
- PP.RemovePragmaHandler(MSCommentHandler.get());
- MSCommentHandler.reset();
}
PP.RemovePragmaHandler("STDC", FPContractHandler.get());
@@ -906,6 +906,7 @@
<< "visibility";
return;
}
+ SourceLocation EndLoc = Tok.getLocation();
PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
@@ -917,6 +918,7 @@
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_vis);
Toks[0].setLocation(VisLoc);
+ Toks[0].setAnnotationEndLoc(EndLoc);
Toks[0].setAnnotationValue(
const_cast<void*>(static_cast<const void*>(VisType)));
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
@@ -1036,6 +1038,7 @@
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_pack);
Toks[0].setLocation(PackLoc);
+ Toks[0].setAnnotationEndLoc(RParenLoc);
Toks[0].setAnnotationValue(static_cast<void*>(Info));
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
/*OwnsTokens=*/false);
@@ -1054,6 +1057,7 @@
PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct);
return;
}
+ SourceLocation EndLoc = Tok.getLocation();
const IdentifierInfo *II = Tok.getIdentifierInfo();
if (II->isStr("on")) {
Kind = Sema::PMSST_ON;
@@ -1079,6 +1083,7 @@
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_msstruct);
Toks[0].setLocation(MSStructTok.getLocation());
+ Toks[0].setAnnotationEndLoc(EndLoc);
Toks[0].setAnnotationValue(reinterpret_cast<void*>(
static_cast<uintptr_t>(Kind)));
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
@@ -1134,6 +1139,7 @@
return;
}
+ SourceLocation EndLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
@@ -1148,6 +1154,7 @@
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_align);
Toks[0].setLocation(FirstTok.getLocation());
+ Toks[0].setAnnotationEndLoc(EndLoc);
Toks[0].setAnnotationValue(reinterpret_cast<void*>(
static_cast<uintptr_t>(Kind)));
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
@@ -1291,6 +1298,7 @@
pragmaUnusedTok.startToken();
pragmaUnusedTok.setKind(tok::annot_pragma_weakalias);
pragmaUnusedTok.setLocation(WeakLoc);
+ pragmaUnusedTok.setAnnotationEndLoc(AliasName.getLocation());
Toks[1] = WeakName;
Toks[2] = AliasName;
PP.EnterTokenStream(Toks, 3,
@@ -1303,6 +1311,7 @@
pragmaUnusedTok.startToken();
pragmaUnusedTok.setKind(tok::annot_pragma_weak);
pragmaUnusedTok.setLocation(WeakLoc);
+ pragmaUnusedTok.setAnnotationEndLoc(WeakLoc);
Toks[1] = WeakName;
PP.EnterTokenStream(Toks, 2,
/*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
@@ -1348,6 +1357,7 @@
pragmaRedefTok.startToken();
pragmaRedefTok.setKind(tok::annot_pragma_redefine_extname);
pragmaRedefTok.setLocation(RedefLoc);
+ pragmaRedefTok.setAnnotationEndLoc(AliasName.getLocation());
Toks[1] = RedefName;
Toks[2] = AliasName;
PP.EnterTokenStream(Toks, 3,
@@ -1370,6 +1380,7 @@
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_fp_contract);
Toks[0].setLocation(Tok.getLocation());
+ Toks[0].setAnnotationEndLoc(Tok.getLocation());
Toks[0].setAnnotationValue(reinterpret_cast<void*>(
static_cast<uintptr_t>(OOS)));
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
@@ -1429,6 +1440,7 @@
Toks[0].setKind(tok::annot_pragma_opencl_extension);
Toks[0].setLocation(NameLoc);
Toks[0].setAnnotationValue(data.getOpaqueValue());
+ Toks[0].setAnnotationEndLoc(StateLoc);
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
/*OwnsTokens=*/false);
@@ -1560,6 +1572,7 @@
return;
}
+ SourceLocation EndLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
@@ -1571,6 +1584,7 @@
AnnotTok.startToken();
AnnotTok.setKind(tok::annot_pragma_ms_pointers_to_members);
AnnotTok.setLocation(PointersToMembersLoc);
+ AnnotTok.setAnnotationEndLoc(EndLoc);
AnnotTok.setAnnotationValue(
reinterpret_cast<void *>(static_cast<uintptr_t>(RepresentationMethod)));
PP.EnterToken(AnnotTok);
@@ -1650,6 +1664,7 @@
PP.Diag(VtorDispLoc, diag::warn_pragma_expected_rparen) << "vtordisp";
return;
}
+ SourceLocation EndLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
@@ -1662,6 +1677,7 @@
AnnotTok.startToken();
AnnotTok.setKind(tok::annot_pragma_ms_vtordisp);
AnnotTok.setLocation(VtorDispLoc);
+ AnnotTok.setAnnotationEndLoc(EndLoc);
AnnotTok.setAnnotationValue(reinterpret_cast<void *>(
static_cast<uintptr_t>((Kind << 16) | (Value & 0xFFFF))));
PP.EnterToken(AnnotTok);
@@ -1678,10 +1694,13 @@
AnnotTok.startToken();
AnnotTok.setKind(tok::annot_pragma_ms_pragma);
AnnotTok.setLocation(Tok.getLocation());
+ AnnotTok.setAnnotationEndLoc(Tok.getLocation());
SmallVector<Token, 8> TokenVector;
// Suck up all of the tokens before the eod.
- for (; Tok.isNot(tok::eod); PP.Lex(Tok))
+ for (; Tok.isNot(tok::eod); PP.Lex(Tok)) {
TokenVector.push_back(Tok);
+ AnnotTok.setAnnotationEndLoc(Tok.getLocation());
+ }
// Add a sentinal EoF token to the end of the list.
TokenVector.push_back(EoF);
// We must allocate this array with new because EnterTokenStream is going to
@@ -1792,6 +1811,14 @@
return;
}
+ // On PS4, issue a warning about any pragma comments other than
+ // #pragma comment lib.
+ if (PP.getTargetInfo().getTriple().isPS4() && Kind != Sema::PCK_Lib) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_ignored)
+ << II->getName();
+ return;
+ }
+
// Read the optional string if present.
PP.Lex(Tok);
std::string ArgumentString;
@@ -2000,6 +2027,7 @@
LoopHintTok.startToken();
LoopHintTok.setKind(tok::annot_pragma_loop_hint);
LoopHintTok.setLocation(PragmaName.getLocation());
+ LoopHintTok.setAnnotationEndLoc(PragmaName.getLocation());
LoopHintTok.setAnnotationValue(static_cast<void *>(Info));
TokenList.push_back(LoopHintTok);
}
@@ -2082,6 +2110,7 @@
TokenArray[0].startToken();
TokenArray[0].setKind(tok::annot_pragma_loop_hint);
TokenArray[0].setLocation(PragmaName.getLocation());
+ TokenArray[0].setAnnotationEndLoc(PragmaName.getLocation());
TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
PP.EnterTokenStream(TokenArray, 1, /*DisableMacroExpansion=*/false,
/*OwnsTokens=*/true);
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index e77f07a..d15f2af 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -507,7 +507,7 @@
/// seh-finally-block:
/// '__finally' compound-statement
///
-StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) {
+StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyLoc) {
PoisonIdentifierRAIIObject raii(Ident__abnormal_termination, false),
raii2(Ident___abnormal_termination, false),
raii3(Ident_AbnormalTermination, false);
@@ -515,11 +515,16 @@
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- StmtResult Block(ParseCompoundStatement());
- if(Block.isInvalid())
- return Block;
+ ParseScope FinallyScope(this, 0);
+ Actions.ActOnStartSEHFinallyBlock();
- return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.get());
+ StmtResult Block(ParseCompoundStatement());
+ if(Block.isInvalid()) {
+ Actions.ActOnAbortSEHFinallyBlock();
+ return Block;
+ }
+
+ return Actions.ActOnFinishSEHFinallyBlock(FinallyLoc, Block.get());
}
/// Handle __leave
@@ -1263,7 +1268,7 @@
// We have incremented the mangling number for the SwitchScope and the
// InnerScope, which is one too many.
if (C99orCXX)
- getCurScope()->decrementMSLocalManglingNumber();
+ getCurScope()->decrementMSManglingNumber();
// Read the body statement.
StmtResult Body(ParseStatement(TrailingElseLoc));
@@ -1705,7 +1710,7 @@
// It will only be incremented if the body contains other things that would
// normally increment the mangling number (like a compound statement).
if (C99orCXXorObjC)
- getCurScope()->decrementMSLocalManglingNumber();
+ getCurScope()->decrementMSManglingNumber();
// Read the body statement.
StmtResult Body(ParseStatement(TrailingElseLoc));
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 7ccd209..3b56102 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -1048,7 +1048,6 @@
if (TryConsumeToken(tok::equal)) {
assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='");
- Actions.ActOnFinishFunctionBody(Res, nullptr, false);
bool Delete = false;
SourceLocation KWLoc;
@@ -1076,6 +1075,8 @@
SkipUntil(tok::semi);
}
+ Stmt *GeneratedBody = Res ? Res->getBody() : nullptr;
+ Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false);
return Res;
}
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index 60cdcf7..be09a36 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -54,7 +54,7 @@
if (Size == 0) return;
unsigned RealOffset = getMappedOffset(OrigOffset, true);
- assert(RealOffset+Size < Buffer.size() && "Invalid location");
+ assert(RealOffset+Size <= Buffer.size() && "Invalid location");
// Remove the dead characters.
Buffer.erase(RealOffset, Size);
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index f52bc6e..8ee2410 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -1439,7 +1439,7 @@
//===----------------------------------------------------------------------===//
namespace clang {
namespace threadSafety {
-
+namespace {
class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
Sema &S;
DiagList Warnings;
@@ -1704,9 +1704,9 @@
CurrentFunction = 0;
}
};
-
-}
-}
+} // namespace
+} // namespace threadSafety
+} // namespace clang
//===----------------------------------------------------------------------===//
// -Wconsumed
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 92d2aeb..69ae4f0 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -251,19 +251,16 @@
return nullptr;
}
-const char *CodeCompletionAllocator::CopyString(StringRef String) {
- char *Mem = (char *)Allocate(String.size() + 1, 1);
- std::copy(String.begin(), String.end(), Mem);
- Mem[String.size()] = 0;
- return Mem;
-}
-
-const char *CodeCompletionAllocator::CopyString(Twine String) {
+const char *CodeCompletionAllocator::CopyString(const Twine &String) {
+ SmallString<128> Data;
+ StringRef Ref = String.toStringRef(Data);
// FIXME: It would be more efficient to teach Twine to tell us its size and
// then add a routine there to fill in an allocated char* with the contents
// of the string.
- SmallString<128> Data;
- return CopyString(String.toStringRef(Data));
+ char *Mem = (char *)Allocate(Ref.size() + 1, 1);
+ std::copy(Ref.begin(), Ref.end(), Mem);
+ Mem[Ref.size()] = 0;
+ return Mem;
}
StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) {
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 7bf3e51..f6689a9 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -982,11 +982,18 @@
getSpecifierName((TST)TypeSpecType, Policy));
}
- // Only 'short' is valid with vector bool. (PIM 2.1)
- if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short))
+ // Only 'short' and 'long long' are valid with vector bool. (PIM 2.1)
+ if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short) &&
+ (TypeSpecWidth != TSW_longlong))
Diag(D, TSWLoc, diag::err_invalid_vector_bool_decl_spec)
<< getSpecifierName((TSW)TypeSpecWidth);
+ // vector bool long long requires VSX support.
+ if ((TypeSpecWidth == TSW_longlong) &&
+ (!PP.getTargetInfo().hasFeature("vsx")) &&
+ (!PP.getTargetInfo().hasFeature("power8-vector")))
+ Diag(D, TSTLoc, diag::err_invalid_vector_long_long_decl_spec);
+
// Elements of vector bool are interpreted as unsigned. (PIM 2.1)
if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) ||
(TypeSpecWidth != TSW_unspecified))
@@ -1213,7 +1220,10 @@
bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc,
const char *&PrevSpec) {
+ if (!FirstLocation.isValid())
+ FirstLocation = Loc;
LastLocation = Loc;
+ LastSpecifier = VS;
if (Specifiers & VS) {
PrevSpec = getSpecifierName(VS);
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index 664a6b1..ceea04f 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -35,6 +35,8 @@
case Sema::AD_Unavailable:
DD.Kind = Unavailable;
break;
+ case Sema::AD_Partial:
+ llvm_unreachable("AD_Partial diags should not be delayed");
}
DD.Triggered = false;
DD.Loc = Loc;
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 6586fb3..53263ba 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -98,7 +98,7 @@
bool AllowInlineNamespace) const {
Ctx = Ctx->getRedeclContext();
- if (Ctx->isFunctionOrMethod() || S->isFunctionPrototypeScope()) {
+ if (Ctx->isFunctionOrMethod() || (S && S->isFunctionPrototypeScope())) {
// Ignore the scopes associated within transparent declaration contexts.
while (S->getEntity() && S->getEntity()->isTransparentContext())
S = S->getParent();
@@ -266,6 +266,11 @@
// If the declarations are redeclarations of each other, keep the newest one.
if (Existing->getCanonicalDecl() == New->getCanonicalDecl()) {
+ // If we're adding an imported declaration, don't replace another imported
+ // declaration.
+ if (Existing->isFromASTFile() && New->isFromASTFile())
+ return DMK_Different;
+
// If either of these is the most recent declaration, use it.
Decl *MostRecent = Existing->getMostRecentDecl();
if (Existing == MostRecent)
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 03fcc94..aac28be 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -789,6 +789,18 @@
// Common case: exactly the same scope, which is fine.
if (FromScope == ToScope) return;
+ // Warn on gotos out of __finally blocks.
+ if (isa<GotoStmt>(From) || isa<IndirectGotoStmt>(From)) {
+ // If FromScope > ToScope, FromScope is more nested and the jump goes to a
+ // less nested scope. Check if it crosses a __finally along the way.
+ for (unsigned I = FromScope; I > ToScope; I = Scopes[I].ParentScope) {
+ if (Scopes[I].InDiag == diag::note_protected_by_seh_finally) {
+ S.Diag(From->getLocStart(), diag::warn_jump_out_of_seh_finally);
+ break;
+ }
+ }
+ }
+
unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope);
// It's okay to jump out from a nested scope.
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
index 449ddf4..51a1274 100644
--- a/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -86,6 +86,14 @@
return nullptr;
}
+CXXCtorInitializer **
+MultiplexExternalSemaSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
+ for (auto *S : Sources)
+ if (auto *R = S->GetExternalCXXCtorInitializers(Offset))
+ return R;
+ return nullptr;
+}
+
bool MultiplexExternalSemaSource::
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
bool AnyDeclsFound = false;
@@ -236,24 +244,12 @@
Sources[i]->ReadExtVectorDecls(Decls);
}
-void MultiplexExternalSemaSource::ReadDynamicClasses(
- SmallVectorImpl<CXXRecordDecl*> &Decls) {
- for(size_t i = 0; i < Sources.size(); ++i)
- Sources[i]->ReadDynamicClasses(Decls);
-}
-
void MultiplexExternalSemaSource::ReadUnusedLocalTypedefNameCandidates(
llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {
for(size_t i = 0; i < Sources.size(); ++i)
Sources[i]->ReadUnusedLocalTypedefNameCandidates(Decls);
}
-void MultiplexExternalSemaSource::ReadLocallyScopedExternCDecls(
- SmallVectorImpl<NamedDecl*> &Decls) {
- for(size_t i = 0; i < Sources.size(); ++i)
- Sources[i]->ReadLocallyScopedExternCDecls(Decls);
-}
-
void MultiplexExternalSemaSource::ReadReferencedSelectors(
SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {
for(size_t i = 0; i < Sources.size(); ++i)
@@ -280,7 +276,7 @@
}
void MultiplexExternalSemaSource::ReadLateParsedTemplates(
- llvm::DenseMap<const FunctionDecl *, LateParsedTemplate *> &LPTMap) {
+ llvm::MapVector<const FunctionDecl *, LateParsedTemplate *> &LPTMap) {
for (size_t i = 0; i < Sources.size(); ++i)
Sources[i]->ReadLateParsedTemplates(LPTMap);
}
diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp
index eeb2e01..7c70048 100644
--- a/lib/Sema/Scope.cpp
+++ b/lib/Sema/Scope.cpp
@@ -38,7 +38,8 @@
FnParent = parent->FnParent;
BlockParent = parent->BlockParent;
TemplateParamParent = parent->TemplateParamParent;
- MSLocalManglingParent = parent->MSLocalManglingParent;
+ MSLastManglingParent = parent->MSLastManglingParent;
+ MSCurManglingNumber = getMSLastManglingNumber();
if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
0)
@@ -47,9 +48,10 @@
Depth = 0;
PrototypeDepth = 0;
PrototypeIndex = 0;
- MSLocalManglingParent = FnParent = BlockParent = nullptr;
+ MSLastManglingParent = FnParent = BlockParent = nullptr;
TemplateParamParent = nullptr;
- MSLocalManglingNumber = 1;
+ MSLastManglingNumber = 1;
+ MSCurManglingNumber = 1;
}
// If this scope is a function or contains breaks/continues, remember it.
@@ -57,8 +59,9 @@
// The MS mangler uses the number of scopes that can hold declarations as
// part of an external name.
if (Flags & (ClassScope | FnScope)) {
- MSLocalManglingNumber = getMSLocalManglingNumber();
- MSLocalManglingParent = this;
+ MSLastManglingNumber = getMSLastManglingNumber();
+ MSLastManglingParent = this;
+ MSCurManglingNumber = 1;
}
if (flags & BreakScope) BreakParent = this;
if (flags & ContinueScope) ContinueParent = this;
@@ -78,7 +81,7 @@
else if ((flags & EnumScope))
; // Don't increment for enum scopes.
else
- incrementMSLocalManglingNumber();
+ incrementMSManglingNumber();
}
DeclsInScope.clear();
@@ -209,12 +212,13 @@
OS << "Parent: (clang::Scope*)" << Parent << '\n';
OS << "Depth: " << Depth << '\n';
- OS << "MSLocalManglingNumber: " << getMSLocalManglingNumber() << '\n';
+ OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
+ OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
if (const DeclContext *DC = getEntity())
OS << "Entity : (clang::DeclContext*)" << DC << '\n';
if (NRVO.getInt())
- OS << "NRVO not allowed";
+ OS << "NRVO not allowed\n";
else if (NRVO.getPointer())
OS << "NRVO candidate : (clang::VarDecl*)" << NRVO.getPointer() << '\n';
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 5170c24..6825dfa 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -212,6 +212,29 @@
addImplicitTypedef("image3d_t", Context.OCLImage3dTy);
addImplicitTypedef("sampler_t", Context.OCLSamplerTy);
addImplicitTypedef("event_t", Context.OCLEventTy);
+ if (getLangOpts().OpenCLVersion >= 200) {
+ addImplicitTypedef("atomic_int", Context.getAtomicType(Context.IntTy));
+ addImplicitTypedef("atomic_uint",
+ Context.getAtomicType(Context.UnsignedIntTy));
+ addImplicitTypedef("atomic_long", Context.getAtomicType(Context.LongTy));
+ addImplicitTypedef("atomic_ulong",
+ Context.getAtomicType(Context.UnsignedLongTy));
+ addImplicitTypedef("atomic_float",
+ Context.getAtomicType(Context.FloatTy));
+ addImplicitTypedef("atomic_double",
+ Context.getAtomicType(Context.DoubleTy));
+ // OpenCLC v2.0, s6.13.11.6 requires that atomic_flag is implemented as
+ // 32-bit integer and OpenCLC v2.0, s6.1.1 int is always 32-bit wide.
+ addImplicitTypedef("atomic_flag", Context.getAtomicType(Context.IntTy));
+ addImplicitTypedef("atomic_intptr_t",
+ Context.getAtomicType(Context.getIntPtrType()));
+ addImplicitTypedef("atomic_uintptr_t",
+ Context.getAtomicType(Context.getUIntPtrType()));
+ addImplicitTypedef("atomic_size_t",
+ Context.getAtomicType(Context.getSizeType()));
+ addImplicitTypedef("atomic_ptrdiff_t",
+ Context.getAtomicType(Context.getPointerDiffType()));
+ }
}
DeclarationName BuiltinVaList = &Context.Idents.get("__builtin_va_list");
@@ -501,14 +524,8 @@
SmallVector<std::pair<IdentifierInfo *, WeakInfo>, 4> WeakIDs;
ExternalSource->ReadWeakUndeclaredIdentifiers(WeakIDs);
- for (unsigned I = 0, N = WeakIDs.size(); I != N; ++I) {
- llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator Pos
- = WeakUndeclaredIdentifiers.find(WeakIDs[I].first);
- if (Pos != WeakUndeclaredIdentifiers.end())
- continue;
-
- WeakUndeclaredIdentifiers.insert(WeakIDs[I]);
- }
+ for (auto &WeakID : WeakIDs)
+ WeakUndeclaredIdentifiers.insert(WeakID);
}
@@ -621,22 +638,6 @@
if (TUKind != TU_Prefix) {
DiagnoseUseOfUnimplementedSelectors();
- // If any dynamic classes have their key function defined within
- // this translation unit, then those vtables are considered "used" and must
- // be emitted.
- for (DynamicClassesType::iterator I = DynamicClasses.begin(ExternalSource),
- E = DynamicClasses.end();
- I != E; ++I) {
- assert(!(*I)->isDependentType() &&
- "Should not see dependent types here!");
- if (const CXXMethodDecl *KeyFunction =
- Context.getCurrentKeyFunction(*I)) {
- const FunctionDecl *Definition = nullptr;
- if (KeyFunction->hasBody(Definition))
- MarkVTableUsed(Definition->getLocation(), *I, true);
- }
- }
-
// If DefinedUsedVTables ends up marking any virtual member functions it
// might lead to more pending template instantiations, which we then need
// to instantiate.
@@ -668,6 +669,8 @@
// All delayed member exception specs should be checked or we end up accepting
// incompatible declarations.
+ // FIXME: This is wrong for TUKind == TU_Prefix. In that case, we need to
+ // write out the lists to the AST file (if any).
assert(DelayedDefaultedMemberExceptionSpecs.empty());
assert(DelayedExceptionSpecChecks.empty());
@@ -685,16 +688,13 @@
}
// Check for #pragma weak identifiers that were never declared
- // FIXME: This will cause diagnostics to be emitted in a non-determinstic
- // order! Iterating over a densemap like this is bad.
LoadExternalWeakUndeclaredIdentifiers();
- for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator
- I = WeakUndeclaredIdentifiers.begin(),
- E = WeakUndeclaredIdentifiers.end(); I != E; ++I) {
- if (I->second.getUsed()) continue;
+ for (auto WeakID : WeakUndeclaredIdentifiers) {
+ if (WeakID.second.getUsed())
+ continue;
- Diag(I->second.getLocation(), diag::warn_weak_identifier_undeclared)
- << I->first;
+ Diag(WeakID.second.getLocation(), diag::warn_weak_identifier_undeclared)
+ << WeakID.first;
}
if (LangOpts.CPlusPlus11 &&
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index e3b66bf..5a29bad 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -422,6 +422,9 @@
if (Action & PSK_Pop && Stack->Stack.empty())
Diag(PragmaLocation, diag::warn_pragma_pop_failed) << PragmaName
<< "stack empty";
+ if (SegmentName &&
+ !checkSectionName(SegmentName->getLocStart(), SegmentName->getString()))
+ return;
Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName);
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 438ad61..9e146ed 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -218,6 +218,7 @@
// Fixed enum types are complete, but they aren't valid as scopes
// until we see a definition, so awkwardly pull out this special
// case.
+ // FIXME: The definition might not be visible; complain if it is not.
const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType);
if (!enumType || enumType->getDecl()->isCompleteDefinition())
return false;
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 5a0d8d4..abcccba 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -319,6 +319,15 @@
if (SemaBuiltinLongjmp(TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_setjmp:
+ if (SemaBuiltinSetjmp(TheCall))
+ return ExprError();
+ break;
+ case Builtin::BI_setjmp:
+ case Builtin::BI_setjmpex:
+ if (checkArgCount(*this, TheCall, 1))
+ return true;
+ break;
case Builtin::BI__builtin_classify_type:
if (checkArgCount(*this, TheCall, 1)) return true;
@@ -499,6 +508,19 @@
break;
}
+ case Builtin::BI__GetExceptionInfo:
+ if (checkArgCount(*this, TheCall, 1))
+ return ExprError();
+
+ if (CheckCXXThrowOperand(
+ TheCall->getLocStart(),
+ Context.getExceptionObjectType(FDecl->getParamDecl(0)->getType()),
+ TheCall))
+ return ExprError();
+
+ TheCall->setType(Context.VoidPtrTy);
+ break;
+
}
// Since the target specific builtins for each arch overlap, only check those
@@ -878,14 +900,6 @@
switch (BuiltinID) {
default: return false;
case X86::BI_mm_prefetch: i = 1; l = 0; u = 3; break;
- case X86::BI__builtin_ia32_vextractf128_pd256:
- case X86::BI__builtin_ia32_vextractf128_ps256:
- case X86::BI__builtin_ia32_vextractf128_si256:
- case X86::BI__builtin_ia32_extract128i256: i = 1, l = 0, u = 1; break;
- case X86::BI__builtin_ia32_vinsertf128_pd256:
- case X86::BI__builtin_ia32_vinsertf128_ps256:
- case X86::BI__builtin_ia32_vinsertf128_si256:
- case X86::BI__builtin_ia32_insert128i256: i = 2, l = 0; u = 1; break;
case X86::BI__builtin_ia32_sha1rnds4: i = 2, l = 0; u = 3; break;
case X86::BI__builtin_ia32_vpermil2pd:
case X86::BI__builtin_ia32_vpermil2pd256:
@@ -1309,9 +1323,10 @@
// M is C if C is an integer, and ptrdiff_t if C is a pointer, and
// the int parameters are for orderings.
- assert(AtomicExpr::AO__c11_atomic_init == 0 &&
- AtomicExpr::AO__c11_atomic_fetch_xor + 1 == AtomicExpr::AO__atomic_load
- && "need to update code for modified C11 atomics");
+ static_assert(AtomicExpr::AO__c11_atomic_init == 0 &&
+ AtomicExpr::AO__c11_atomic_fetch_xor + 1 ==
+ AtomicExpr::AO__atomic_load,
+ "need to update code for modified C11 atomics");
bool IsC11 = Op >= AtomicExpr::AO__c11_atomic_init &&
Op <= AtomicExpr::AO__c11_atomic_fetch_xor;
bool IsN = Op == AtomicExpr::AO__atomic_load_n ||
@@ -2128,7 +2143,7 @@
if (checkBuiltinArgument(*this, Call, 0))
return true;
- static const struct {
+ const struct {
unsigned ArgNo;
QualType Type;
} ArgumentTypes[] = {
@@ -2460,8 +2475,13 @@
}
/// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val).
-/// This checks that val is a constant 1.
+/// This checks that the target supports __builtin_longjmp and
+/// that val is a constant 1.
bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
+ if (!Context.getTargetInfo().hasSjLjLowering())
+ return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_unsupported)
+ << SourceRange(TheCall->getLocStart(), TheCall->getLocEnd());
+
Expr *Arg = TheCall->getArg(1);
llvm::APSInt Result;
@@ -2476,6 +2496,16 @@
return false;
}
+
+/// SemaBuiltinSetjmp - Handle __builtin_setjmp(void *env[5]).
+/// This checks that the target supports __builtin_setjmp.
+bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) {
+ if (!Context.getTargetInfo().hasSjLjLowering())
+ return Diag(TheCall->getLocStart(), diag::err_builtin_setjmp_unsupported)
+ << SourceRange(TheCall->getLocStart(), TheCall->getLocEnd());
+ return false;
+}
+
namespace {
enum StringLiteralCheckType {
SLCT_NotALiteral,
@@ -3669,8 +3699,11 @@
ExprTy = TET->getUnderlyingExpr()->getType();
}
- if (AT.matchesType(S.Context, ExprTy))
+ analyze_printf::ArgType::MatchKind match = AT.matchesType(S.Context, ExprTy);
+
+ if (match == analyze_printf::ArgType::Match) {
return true;
+ }
// Look through argument promotions for our error message's reported type.
// This includes the integral and floating promotions, but excludes array
@@ -3765,16 +3798,18 @@
CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) {
+ unsigned diag = diag::warn_format_conversion_argument_type_mismatch;
+ if (match == analyze_format_string::ArgType::NoMatchPedantic) {
+ diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+ }
// In this case, the specifier is wrong and should be changed to match
// the argument.
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << IntendedTy << IsEnum
- << E->getSourceRange(),
- E->getLocStart(),
- /*IsStringLocation*/false,
- SpecRange,
- FixItHint::CreateReplacement(SpecRange, os.str()));
+ EmitFormatDiagnostic(S.PDiag(diag)
+ << AT.getRepresentativeTypeName(S.Context)
+ << IntendedTy << IsEnum << E->getSourceRange(),
+ E->getLocStart(),
+ /*IsStringLocation*/ false, SpecRange,
+ FixItHint::CreateReplacement(SpecRange, os.str()));
} else {
// The canonical type for formatting this value is different from the
@@ -3848,15 +3883,18 @@
// arguments here.
switch (S.isValidVarArgType(ExprTy)) {
case Sema::VAK_Valid:
- case Sema::VAK_ValidInCXX11:
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << ExprTy << IsEnum
- << CSR
- << E->getSourceRange(),
- E->getLocStart(), /*IsStringLocation*/false, CSR);
- break;
+ case Sema::VAK_ValidInCXX11: {
+ unsigned diag = diag::warn_format_conversion_argument_type_mismatch;
+ if (match == analyze_printf::ArgType::NoMatchPedantic) {
+ diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+ }
+ EmitFormatDiagnostic(
+ S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy
+ << IsEnum << CSR << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/ false, CSR);
+ break;
+ }
case Sema::VAK_Undefined:
case Sema::VAK_MSVCUndefined:
EmitFormatDiagnostic(
@@ -3988,13 +4026,13 @@
FixItHint::CreateRemoval(R));
}
}
-
+
if (!FS.consumesDataArgument()) {
// FIXME: Technically specifying a precision or field width here
// makes no sense. Worth issuing a warning at some point.
return true;
}
-
+
// Consume the argument.
unsigned argIndex = FS.getArgIndex();
if (argIndex < NumDataArgs) {
@@ -4003,7 +4041,7 @@
// function if we encounter some other error.
CoveredArgs.set(argIndex);
}
-
+
// Check the length modifier is valid with the given conversion specifier.
if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
@@ -4020,47 +4058,57 @@
// The remaining checks depend on the data arguments.
if (HasVAListArg)
return true;
-
+
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
return false;
-
+
// Check that the argument type matches the format specifier.
const Expr *Ex = getDataArg(argIndex);
if (!Ex)
return true;
const analyze_format_string::ArgType &AT = FS.getArgType(S.Context);
- if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) {
- ScanfSpecifier fixedFS = FS;
- bool success = fixedFS.fixType(Ex->getType(),
- Ex->IgnoreImpCasts()->getType(),
- S.getLangOpts(), S.Context);
- if (success) {
- // Get the fix string from the fixed format specifier.
- SmallString<128> buf;
- llvm::raw_svector_ostream os(buf);
- fixedFS.toString(os);
+ if (!AT.isValid()) {
+ return true;
+ }
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false
- << Ex->getSourceRange(),
+ analyze_format_string::ArgType::MatchKind match =
+ AT.matchesType(S.Context, Ex->getType());
+ if (match == analyze_format_string::ArgType::Match) {
+ return true;
+ }
+
+ ScanfSpecifier fixedFS = FS;
+ bool success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(),
+ S.getLangOpts(), S.Context);
+
+ unsigned diag = diag::warn_format_conversion_argument_type_mismatch;
+ if (match == analyze_format_string::ArgType::NoMatchPedantic) {
+ diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+ }
+
+ if (success) {
+ // Get the fix string from the fixed format specifier.
+ SmallString<128> buf;
+ llvm::raw_svector_ostream os(buf);
+ fixedFS.toString(os);
+
+ EmitFormatDiagnostic(
+ S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context)
+ << Ex->getType() << false << Ex->getSourceRange(),
Ex->getLocStart(),
- /*IsStringLocation*/false,
+ /*IsStringLocation*/ false,
getSpecifierRange(startSpecifier, specifierLen),
FixItHint::CreateReplacement(
- getSpecifierRange(startSpecifier, specifierLen),
- os.str()));
- } else {
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false
- << Ex->getSourceRange(),
- Ex->getLocStart(),
- /*IsStringLocation*/false,
- getSpecifierRange(startSpecifier, specifierLen));
- }
+ getSpecifierRange(startSpecifier, specifierLen), os.str()));
+ } else {
+ EmitFormatDiagnostic(S.PDiag(diag)
+ << AT.getRepresentativeTypeName(S.Context)
+ << Ex->getType() << false << Ex->getSourceRange(),
+ Ex->getLocStart(),
+ /*IsStringLocation*/ false,
+ getSpecifierRange(startSpecifier, specifierLen));
}
return true;
@@ -4602,7 +4650,7 @@
/// \brief If E is a sizeof expression, returns its argument expression,
/// otherwise returns NULL.
-static const Expr *getSizeOfExprArg(const Expr* E) {
+static const Expr *getSizeOfExprArg(const Expr *E) {
if (const UnaryExprOrTypeTraitExpr *SizeOf =
dyn_cast<UnaryExprOrTypeTraitExpr>(E))
if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType())
@@ -4612,7 +4660,7 @@
}
/// \brief If E is a sizeof expression, returns its argument type.
-static QualType getSizeOfArgType(const Expr* E) {
+static QualType getSizeOfArgType(const Expr *E) {
if (const UnaryExprOrTypeTraitExpr *SizeOf =
dyn_cast<UnaryExprOrTypeTraitExpr>(E))
if (SizeOf->getKind() == clang::UETT_SizeOf)
@@ -4658,8 +4706,9 @@
SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange();
QualType DestTy = Dest->getType();
+ QualType PointeeTy;
if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
- QualType PointeeTy = DestPtrTy->getPointeeType();
+ PointeeTy = DestPtrTy->getPointeeType();
// Never warn about void type pointers. This can be used to suppress
// false positives.
@@ -4739,47 +4788,53 @@
break;
}
}
+ } else if (DestTy->isArrayType()) {
+ PointeeTy = DestTy;
+ }
- // Always complain about dynamic classes.
- bool IsContained;
- if (const CXXRecordDecl *ContainedRD =
- getContainedDynamicClass(PointeeTy, IsContained)) {
+ if (PointeeTy == QualType())
+ continue;
- unsigned OperationType = 0;
- // "overwritten" if we're warning about the destination for any call
- // but memcmp; otherwise a verb appropriate to the call.
- if (ArgIdx != 0 || BId == Builtin::BImemcmp) {
- if (BId == Builtin::BImemcpy)
- OperationType = 1;
- else if(BId == Builtin::BImemmove)
- OperationType = 2;
- else if (BId == Builtin::BImemcmp)
- OperationType = 3;
- }
-
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::warn_dyn_class_memaccess)
- << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx)
- << FnName << IsContained << ContainedRD << OperationType
- << Call->getCallee()->getSourceRange());
- } else if (PointeeTy.hasNonTrivialObjCLifetime() &&
- BId != Builtin::BImemset)
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::warn_arc_object_memaccess)
- << ArgIdx << FnName << PointeeTy
- << Call->getCallee()->getSourceRange());
- else
- continue;
+ // Always complain about dynamic classes.
+ bool IsContained;
+ if (const CXXRecordDecl *ContainedRD =
+ getContainedDynamicClass(PointeeTy, IsContained)) {
+ unsigned OperationType = 0;
+ // "overwritten" if we're warning about the destination for any call
+ // but memcmp; otherwise a verb appropriate to the call.
+ if (ArgIdx != 0 || BId == Builtin::BImemcmp) {
+ if (BId == Builtin::BImemcpy)
+ OperationType = 1;
+ else if(BId == Builtin::BImemmove)
+ OperationType = 2;
+ else if (BId == Builtin::BImemcmp)
+ OperationType = 3;
+ }
+
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
- PDiag(diag::note_bad_memaccess_silence)
- << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
- break;
- }
+ PDiag(diag::warn_dyn_class_memaccess)
+ << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx)
+ << FnName << IsContained << ContainedRD << OperationType
+ << Call->getCallee()->getSourceRange());
+ } else if (PointeeTy.hasNonTrivialObjCLifetime() &&
+ BId != Builtin::BImemset)
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_arc_object_memaccess)
+ << ArgIdx << FnName << PointeeTy
+ << Call->getCallee()->getSourceRange());
+ else
+ continue;
+
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::note_bad_memaccess_silence)
+ << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
+ break;
}
+
}
// A little helper routine: ignore addition and subtraction of integer literals.
@@ -8169,6 +8224,236 @@
return !isLowercase(str.front());
}
+static Optional<int> GetNSMutableArrayArgumentIndex(Sema &S,
+ ObjCMessageExpr *Message) {
+ if (S.NSMutableArrayPointer.isNull()) {
+ IdentifierInfo *NSMutableArrayId =
+ S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableArray);
+ NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableArrayId,
+ Message->getLocStart(),
+ Sema::LookupOrdinaryName);
+ ObjCInterfaceDecl *InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (!InterfaceDecl) {
+ return None;
+ }
+ QualType NSMutableArrayObject =
+ S.Context.getObjCInterfaceType(InterfaceDecl);
+ S.NSMutableArrayPointer =
+ S.Context.getObjCObjectPointerType(NSMutableArrayObject);
+ }
+
+ if (S.NSMutableArrayPointer != Message->getReceiverType()) {
+ return None;
+ }
+
+ Selector Sel = Message->getSelector();
+
+ Optional<NSAPI::NSArrayMethodKind> MKOpt =
+ S.NSAPIObj->getNSArrayMethodKind(Sel);
+ if (!MKOpt) {
+ return None;
+ }
+
+ NSAPI::NSArrayMethodKind MK = *MKOpt;
+
+ switch (MK) {
+ case NSAPI::NSMutableArr_addObject:
+ case NSAPI::NSMutableArr_insertObjectAtIndex:
+ case NSAPI::NSMutableArr_setObjectAtIndexedSubscript:
+ return 0;
+ case NSAPI::NSMutableArr_replaceObjectAtIndex:
+ return 1;
+
+ default:
+ return None;
+ }
+
+ return None;
+}
+
+static
+Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S,
+ ObjCMessageExpr *Message) {
+
+ if (S.NSMutableDictionaryPointer.isNull()) {
+ IdentifierInfo *NSMutableDictionaryId =
+ S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableDictionary);
+ NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableDictionaryId,
+ Message->getLocStart(),
+ Sema::LookupOrdinaryName);
+ ObjCInterfaceDecl *InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (!InterfaceDecl) {
+ return None;
+ }
+ QualType NSMutableDictionaryObject =
+ S.Context.getObjCInterfaceType(InterfaceDecl);
+ S.NSMutableDictionaryPointer =
+ S.Context.getObjCObjectPointerType(NSMutableDictionaryObject);
+ }
+
+ if (S.NSMutableDictionaryPointer != Message->getReceiverType()) {
+ return None;
+ }
+
+ Selector Sel = Message->getSelector();
+
+ Optional<NSAPI::NSDictionaryMethodKind> MKOpt =
+ S.NSAPIObj->getNSDictionaryMethodKind(Sel);
+ if (!MKOpt) {
+ return None;
+ }
+
+ NSAPI::NSDictionaryMethodKind MK = *MKOpt;
+
+ switch (MK) {
+ case NSAPI::NSMutableDict_setObjectForKey:
+ case NSAPI::NSMutableDict_setValueForKey:
+ case NSAPI::NSMutableDict_setObjectForKeyedSubscript:
+ return 0;
+
+ default:
+ return None;
+ }
+
+ return None;
+}
+
+static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
+
+ ObjCInterfaceDecl *InterfaceDecl;
+ if (S.NSMutableSetPointer.isNull()) {
+ IdentifierInfo *NSMutableSetId =
+ S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableSet);
+ NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableSetId,
+ Message->getLocStart(),
+ Sema::LookupOrdinaryName);
+ InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (InterfaceDecl) {
+ QualType NSMutableSetObject =
+ S.Context.getObjCInterfaceType(InterfaceDecl);
+ S.NSMutableSetPointer =
+ S.Context.getObjCObjectPointerType(NSMutableSetObject);
+ }
+ }
+
+ if (S.NSCountedSetPointer.isNull()) {
+ IdentifierInfo *NSCountedSetId =
+ S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSCountedSet);
+ NamedDecl *IF = S.LookupSingleName(S.TUScope, NSCountedSetId,
+ Message->getLocStart(),
+ Sema::LookupOrdinaryName);
+ InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (InterfaceDecl) {
+ QualType NSCountedSetObject =
+ S.Context.getObjCInterfaceType(InterfaceDecl);
+ S.NSCountedSetPointer =
+ S.Context.getObjCObjectPointerType(NSCountedSetObject);
+ }
+ }
+
+ if (S.NSMutableOrderedSetPointer.isNull()) {
+ IdentifierInfo *NSOrderedSetId =
+ S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableOrderedSet);
+ NamedDecl *IF = S.LookupSingleName(S.TUScope, NSOrderedSetId,
+ Message->getLocStart(),
+ Sema::LookupOrdinaryName);
+ InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (InterfaceDecl) {
+ QualType NSOrderedSetObject =
+ S.Context.getObjCInterfaceType(InterfaceDecl);
+ S.NSMutableOrderedSetPointer =
+ S.Context.getObjCObjectPointerType(NSOrderedSetObject);
+ }
+ }
+
+ QualType ReceiverType = Message->getReceiverType();
+
+ bool IsMutableSet = !S.NSMutableSetPointer.isNull() &&
+ ReceiverType == S.NSMutableSetPointer;
+ bool IsMutableOrderedSet = !S.NSMutableOrderedSetPointer.isNull() &&
+ ReceiverType == S.NSMutableOrderedSetPointer;
+ bool IsCountedSet = !S.NSCountedSetPointer.isNull() &&
+ ReceiverType == S.NSCountedSetPointer;
+
+ if (!IsMutableSet && !IsMutableOrderedSet && !IsCountedSet) {
+ return None;
+ }
+
+ Selector Sel = Message->getSelector();
+
+ Optional<NSAPI::NSSetMethodKind> MKOpt = S.NSAPIObj->getNSSetMethodKind(Sel);
+ if (!MKOpt) {
+ return None;
+ }
+
+ NSAPI::NSSetMethodKind MK = *MKOpt;
+
+ switch (MK) {
+ case NSAPI::NSMutableSet_addObject:
+ case NSAPI::NSOrderedSet_setObjectAtIndex:
+ case NSAPI::NSOrderedSet_setObjectAtIndexedSubscript:
+ case NSAPI::NSOrderedSet_insertObjectAtIndex:
+ return 0;
+ case NSAPI::NSOrderedSet_replaceObjectAtIndexWithObject:
+ return 1;
+ }
+
+ return None;
+}
+
+void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) {
+ if (!Message->isInstanceMessage()) {
+ return;
+ }
+
+ Optional<int> ArgOpt;
+
+ if (!(ArgOpt = GetNSMutableArrayArgumentIndex(*this, Message)) &&
+ !(ArgOpt = GetNSMutableDictionaryArgumentIndex(*this, Message)) &&
+ !(ArgOpt = GetNSSetArgumentIndex(*this, Message))) {
+ return;
+ }
+
+ int ArgIndex = *ArgOpt;
+
+ Expr *Receiver = Message->getInstanceReceiver()->IgnoreImpCasts();
+ if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Receiver)) {
+ Receiver = OE->getSourceExpr()->IgnoreImpCasts();
+ }
+
+ Expr *Arg = Message->getArg(ArgIndex)->IgnoreImpCasts();
+ if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Arg)) {
+ Arg = OE->getSourceExpr()->IgnoreImpCasts();
+ }
+
+ if (DeclRefExpr *ReceiverRE = dyn_cast<DeclRefExpr>(Receiver)) {
+ if (DeclRefExpr *ArgRE = dyn_cast<DeclRefExpr>(Arg)) {
+ if (ReceiverRE->getDecl() == ArgRE->getDecl()) {
+ ValueDecl *Decl = ReceiverRE->getDecl();
+ Diag(Message->getSourceRange().getBegin(),
+ diag::warn_objc_circular_container)
+ << Decl->getName();
+ Diag(Decl->getLocation(),
+ diag::note_objc_circular_container_declared_here)
+ << Decl->getName();
+ }
+ }
+ } else if (ObjCIvarRefExpr *IvarRE = dyn_cast<ObjCIvarRefExpr>(Receiver)) {
+ if (ObjCIvarRefExpr *IvarArgRE = dyn_cast<ObjCIvarRefExpr>(Arg)) {
+ if (IvarRE->getDecl() == IvarArgRE->getDecl()) {
+ ObjCIvarDecl *Decl = IvarRE->getDecl();
+ Diag(Message->getSourceRange().getBegin(),
+ diag::warn_objc_circular_container)
+ << Decl->getName();
+ Diag(Decl->getLocation(),
+ diag::note_objc_circular_container_declared_here)
+ << Decl->getName();
+ }
+ }
+ }
+
+}
+
/// Check a message send to see if it's likely to cause a retain cycle.
void Sema::checkRetainCycles(ObjCMessageExpr *msg) {
// Only check instance methods whose selector looks like a setter.
@@ -8353,7 +8638,7 @@
// Get line numbers of statement and body.
bool StmtLineInvalid;
- unsigned StmtLine = SourceMgr.getSpellingLineNumber(StmtLoc,
+ unsigned StmtLine = SourceMgr.getPresumedLineNumber(StmtLoc,
&StmtLineInvalid);
if (StmtLineInvalid)
return false;
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 80238e5..eeeb851 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -4035,12 +4035,18 @@
if (RequireCompleteType(Loc, Type, 0))
return;
+ CXXRecordDecl *RD = Type->getAsCXXRecordDecl();
+ if (!RD) {
+ CodeCompleteExpression(S, Type);
+ return;
+ }
+
// FIXME: Provide support for member initializers.
// FIXME: Provide support for variadic template constructors.
OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
- for (auto C : LookupConstructors(Type->getAsCXXRecordDecl())) {
+ for (auto C : LookupConstructors(RD)) {
if (auto FD = dyn_cast<FunctionDecl>(C)) {
AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()),
Args, CandidateSet,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e254773..9bbfeaf 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CommentDiagnostic.h"
@@ -1835,11 +1836,18 @@
// Declarations of the same entity are not ignored, even if they have
// different linkages.
- if (auto *OldTD = dyn_cast<TypedefNameDecl>(Old))
+ if (auto *OldTD = dyn_cast<TypedefNameDecl>(Old)) {
if (Context.hasSameType(OldTD->getUnderlyingType(),
Decl->getUnderlyingType()))
continue;
+ // If both declarations give a tag declaration a typedef name for linkage
+ // purposes, then they declare the same entity.
+ if (OldTD->getAnonDeclWithTypedefName() &&
+ Decl->getAnonDeclWithTypedefName())
+ continue;
+ }
+
if (!Old->isExternallyVisible())
Filter.erase();
}
@@ -1949,6 +1957,29 @@
if (Old->isInvalidDecl())
return New->setInvalidDecl();
+ if (auto *OldTD = dyn_cast<TypedefNameDecl>(Old)) {
+ auto *OldTag = OldTD->getAnonDeclWithTypedefName();
+ auto *NewTag = New->getAnonDeclWithTypedefName();
+ NamedDecl *Hidden = nullptr;
+ if (getLangOpts().CPlusPlus && OldTag && NewTag &&
+ OldTag->getCanonicalDecl() != NewTag->getCanonicalDecl() &&
+ !hasVisibleDefinition(OldTag, &Hidden)) {
+ // There is a definition of this tag, but it is not visible. Use it
+ // instead of our tag.
+ New->setTypeForDecl(OldTD->getTypeForDecl());
+ if (OldTD->isModed())
+ New->setModedTypeSourceInfo(OldTD->getTypeSourceInfo(),
+ OldTD->getUnderlyingType());
+ else
+ New->setTypeSourceInfo(OldTD->getTypeSourceInfo());
+
+ // Make the old tag definition visible.
+ if (auto *Listener = getASTMutationListener())
+ Listener->RedefinedHiddenDefinition(Hidden, NewTag->getLocation());
+ Hidden->setHidden(false);
+ }
+ }
+
// If the typedef types are not identical, reject them in all languages and
// with any extensions enabled.
if (isIncompatibleTypedef(Old, New))
@@ -2018,7 +2049,6 @@
Diag(New->getLocation(), diag::ext_redefinition_of_typedef)
<< New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
- return;
}
/// DeclhasAttr - returns true if decl Declaration already has the target
@@ -3416,8 +3446,19 @@
return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg());
}
-static void HandleTagNumbering(Sema &S, const TagDecl *Tag, Scope *TagScope) {
- if (!S.Context.getLangOpts().CPlusPlus)
+// The MS ABI changed between VS2013 and VS2015 with regard to numbers used to
+// disambiguate entities defined in different scopes.
+// While the VS2015 ABI fixes potential miscompiles, it is also breaks
+// compatibility.
+// We will pick our mangling number depending on which version of MSVC is being
+// targeted.
+static unsigned getMSManglingNumber(const LangOptions &LO, Scope *S) {
+ return LO.isCompatibleWithMSVC(19) ? S->getMSCurManglingNumber()
+ : S->getMSLastManglingNumber();
+}
+
+void Sema::handleTagNumbering(const TagDecl *Tag, Scope *TagScope) {
+ if (!Context.getLangOpts().CPlusPlus)
return;
if (isa<CXXRecordDecl>(Tag->getParent())) {
@@ -3426,23 +3467,64 @@
if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl())
return;
MangleNumberingContext &MCtx =
- S.Context.getManglingNumberContext(Tag->getParent());
- S.Context.setManglingNumber(
- Tag, MCtx.getManglingNumber(Tag, TagScope->getMSLocalManglingNumber()));
+ Context.getManglingNumberContext(Tag->getParent());
+ Context.setManglingNumber(
+ Tag, MCtx.getManglingNumber(
+ Tag, getMSManglingNumber(getLangOpts(), TagScope)));
return;
}
// If this tag isn't a direct child of a class, number it if it is local.
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx =
- S.getCurrentMangleNumberContext(Tag->getDeclContext(),
- ManglingContextDecl)) {
- S.Context.setManglingNumber(
- Tag,
- MCtx->getManglingNumber(Tag, TagScope->getMSLocalManglingNumber()));
+ if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(
+ Tag->getDeclContext(), ManglingContextDecl)) {
+ Context.setManglingNumber(
+ Tag, MCtx->getManglingNumber(
+ Tag, getMSManglingNumber(getLangOpts(), TagScope)));
}
}
+void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec,
+ TypedefNameDecl *NewTD) {
+ // Do nothing if the tag is not anonymous or already has an
+ // associated typedef (from an earlier typedef in this decl group).
+ if (TagFromDeclSpec->getIdentifier())
+ return;
+ if (TagFromDeclSpec->getTypedefNameForAnonDecl())
+ return;
+
+ // A well-formed anonymous tag must always be a TUK_Definition.
+ assert(TagFromDeclSpec->isThisDeclarationADefinition());
+
+ // The type must match the tag exactly; no qualifiers allowed.
+ if (!Context.hasSameType(NewTD->getUnderlyingType(),
+ Context.getTagDeclType(TagFromDeclSpec)))
+ return;
+
+ // If we've already computed linkage for the anonymous tag, then
+ // adding a typedef name for the anonymous decl can change that
+ // linkage, which might be a serious problem. Diagnose this as
+ // unsupported and ignore the typedef name. TODO: we should
+ // pursue this as a language defect and establish a formal rule
+ // for how to handle it.
+ if (TagFromDeclSpec->hasLinkageBeenComputed()) {
+ Diag(NewTD->getLocation(), diag::err_typedef_changes_linkage);
+
+ SourceLocation tagLoc = TagFromDeclSpec->getInnerLocStart();
+ tagLoc = getLocForEndOfToken(tagLoc);
+
+ llvm::SmallString<40> textToInsert;
+ textToInsert += ' ';
+ textToInsert += NewTD->getIdentifier()->getName();
+ Diag(tagLoc, diag::note_typedef_changes_linkage)
+ << FixItHint::CreateInsertion(tagLoc, textToInsert);
+ return;
+ }
+
+ // Otherwise, set this is the anon-decl typedef for the tag.
+ TagFromDeclSpec->setTypedefNameForAnonDecl(NewTD);
+}
+
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed. It also accepts template
/// parameters to cope with template friend declarations.
@@ -3472,7 +3554,7 @@
}
if (Tag) {
- HandleTagNumbering(*this, Tag, S);
+ handleTagNumbering(Tag, S);
Tag->setFreeStanding();
if (Tag->isInvalidDecl())
return Tag;
@@ -4095,10 +4177,11 @@
if (VarDecl *NewVD = dyn_cast<VarDecl>(Anon)) {
if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) {
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx =
- getCurrentMangleNumberContext(NewVD->getDeclContext(),
- ManglingContextDecl)) {
- Context.setManglingNumber(NewVD, MCtx->getManglingNumber(NewVD, S->getMSLocalManglingNumber()));
+ if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(
+ NewVD->getDeclContext(), ManglingContextDecl)) {
+ Context.setManglingNumber(
+ NewVD, MCtx->getManglingNumber(
+ NewVD, getMSManglingNumber(getLangOpts(), S)));
Context.setStaticLocalNumber(NewVD, MCtx->getStaticLocalNumber(NewVD));
}
}
@@ -4864,27 +4947,13 @@
return;
// Note that we have a locally-scoped external with this name.
- // FIXME: There can be multiple such declarations if they are functions marked
- // __attribute__((overloadable)) declared in function scope in C.
- LocallyScopedExternCDecls[ND->getDeclName()] = ND;
+ Context.getExternCContextDecl()->makeDeclVisibleInContext(ND);
}
NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) {
- if (ExternalSource) {
- // Load locally-scoped external decls from the external source.
- // FIXME: This is inefficient. Maybe add a DeclContext for extern "C" decls?
- SmallVector<NamedDecl *, 4> Decls;
- ExternalSource->ReadLocallyScopedExternCDecls(Decls);
- for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
- llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = LocallyScopedExternCDecls.find(Decls[I]->getDeclName());
- if (Pos == LocallyScopedExternCDecls.end())
- LocallyScopedExternCDecls[Decls[I]->getDeclName()] = Decls[I];
- }
- }
-
- NamedDecl *D = LocallyScopedExternCDecls.lookup(Name);
- return D ? D->getMostRecentDecl() : nullptr;
+ // FIXME: We can have multiple results via __attribute__((overloadable)).
+ auto Result = Context.getExternCContextDecl()->lookup(Name);
+ return Result.empty() ? nullptr : *Result.begin();
}
/// \brief Diagnose function specifiers on a declaration of an identifier that
@@ -5899,11 +5968,11 @@
if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) {
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx =
- getCurrentMangleNumberContext(NewVD->getDeclContext(),
- ManglingContextDecl)) {
+ if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(
+ NewVD->getDeclContext(), ManglingContextDecl)) {
Context.setManglingNumber(
- NewVD, MCtx->getManglingNumber(NewVD, S->getMSLocalManglingNumber()));
+ NewVD, MCtx->getManglingNumber(
+ NewVD, getMSManglingNumber(getLangOpts(), S)));
Context.setStaticLocalNumber(NewVD, MCtx->getStaticLocalNumber(NewVD));
}
}
@@ -7403,7 +7472,8 @@
NewFD->setInvalidDecl();
}
- if (D.isFunctionDefinition() && CodeSegStack.CurrentValue &&
+ // Apply an implicit SectionAttr if #pragma code_seg is active.
+ if (CodeSegStack.CurrentValue && D.isFunctionDefinition() &&
!NewFD->hasAttr<SectionAttr>()) {
NewFD->addAttr(
SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
@@ -8011,28 +8081,8 @@
// This needs to happen first so that 'inline' propagates.
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
- if (isa<CXXMethodDecl>(NewFD)) {
- // A valid redeclaration of a C++ method must be out-of-line,
- // but (unfortunately) it's not necessarily a definition
- // because of templates, which means that the previous
- // declaration is not necessarily from the class definition.
-
- // For just setting the access, that doesn't matter.
- CXXMethodDecl *oldMethod = cast<CXXMethodDecl>(OldDecl);
- NewFD->setAccess(oldMethod->getAccess());
-
- // Update the key-function state if necessary for this ABI.
- if (NewFD->isInlined() &&
- !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) {
- // setNonKeyFunction needs to work with the original
- // declaration from the class definition, and isVirtual() is
- // just faster in that case, so map back to that now.
- oldMethod = cast<CXXMethodDecl>(oldMethod->getFirstDecl());
- if (oldMethod->isVirtual()) {
- Context.setNonKeyFunction(oldMethod);
- }
- }
- }
+ if (isa<CXXMethodDecl>(NewFD))
+ NewFD->setAccess(OldDecl->getAccess());
}
}
@@ -8602,8 +8652,13 @@
diag = diag::warn_uninit_self_reference_in_reference_init;
} else if (cast<VarDecl>(OrigDecl)->isStaticLocal()) {
diag = diag::warn_static_self_reference_in_init;
- } else {
+ } else if (isa<TranslationUnitDecl>(OrigDecl->getDeclContext()) ||
+ isa<NamespaceDecl>(OrigDecl->getDeclContext()) ||
+ DRE->getDecl()->getType()->isRecordType()) {
diag = diag::warn_uninit_self_reference_in_init;
+ } else {
+ // Local variables will be handled by the CFG analysis.
+ return;
}
S.DiagRuntimeBehavior(DRE->getLocStart(), DRE,
@@ -8676,6 +8731,20 @@
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) {
+ // Attempt typo correction early so that the type of the init expression can
+ // be deduced based on the chosen correction:if the original init contains a
+ // TypoExpr.
+ ExprResult Res = CorrectDelayedTyposInExpr(Init);
+ if (!Res.isUsable()) {
+ RealDecl->setInvalidDecl();
+ return;
+ }
+ if (Res.get() != Init) {
+ Init = Res.get();
+ if (CXXDirectInit)
+ CXXDirectInit = dyn_cast<ParenListExpr>(Init);
+ }
+
Expr *DeduceInit = Init;
// Initializer could be a C++ direct-initializer. Deduction only works if it
// contains exactly one expression.
@@ -9512,7 +9581,9 @@
}
- if (var->isThisDeclarationADefinition() &&
+ // Apply section attributes and pragmas to global variables.
+ bool GlobalStorage = var->hasGlobalStorage();
+ if (GlobalStorage && var->isThisDeclarationADefinition() &&
ActiveTemplateInstantiations.empty()) {
PragmaStack<StringLiteral *> *Stack = nullptr;
int SectionFlags = ASTContext::PSF_Implicit | ASTContext::PSF_Read;
@@ -9525,11 +9596,11 @@
Stack = &DataSegStack;
SectionFlags |= ASTContext::PSF_Write;
}
- if (!var->hasAttr<SectionAttr>() && Stack->CurrentValue)
- var->addAttr(
- SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
- Stack->CurrentValue->getString(),
- Stack->CurrentPragmaLocation));
+ if (Stack->CurrentValue && !var->hasAttr<SectionAttr>()) {
+ var->addAttr(SectionAttr::CreateImplicit(
+ Context, SectionAttr::Declspec_allocate,
+ Stack->CurrentValue->getString(), Stack->CurrentPragmaLocation));
+ }
if (const SectionAttr *SA = var->getAttr<SectionAttr>())
if (UnifySection(SA->getName(), SectionFlags, var))
var->dropAttr<SectionAttr>();
@@ -9572,7 +9643,7 @@
}
Expr *Init = var->getInit();
- bool IsGlobal = var->hasGlobalStorage() && !var->isStaticLocal();
+ bool IsGlobal = GlobalStorage && !var->isStaticLocal();
QualType baseType = Context.getBaseElementType(type);
if (!var->getDeclContext()->isDependentContext() &&
@@ -9746,7 +9817,7 @@
if (DeclSpec::isDeclRep(DS.getTypeSpecType())) {
if (TagDecl *Tag = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl())) {
- HandleTagNumbering(*this, Tag, S);
+ handleTagNumbering(Tag, S);
if (!Tag->hasNameForLinkage() && !Tag->hasDeclaratorForAnonDecl())
Tag->setDeclaratorForAnonDecl(FirstDeclaratorInGroup);
}
@@ -9813,9 +9884,12 @@
void Sema::ActOnDocumentableDecls(ArrayRef<Decl *> Group) {
// Don't parse the comment if Doxygen diagnostics are ignored.
if (Group.empty() || !Group[0])
- return;
+ return;
- if (Diags.isIgnored(diag::warn_doc_param_not_found, Group[0]->getLocation()))
+ if (Diags.isIgnored(diag::warn_doc_param_not_found,
+ Group[0]->getLocation()) &&
+ Diags.isIgnored(diag::warn_unknown_comment_command_name,
+ Group[0]->getLocation()))
return;
if (Group.size() >= 2) {
@@ -10105,7 +10179,7 @@
<< " int " << FTI.Params[i].Ident->getName() << ";\n";
Diag(FTI.Params[i].IdentLoc, diag::ext_param_not_declared)
<< FTI.Params[i].Ident
- << FixItHint::CreateInsertion(LocAfterDecls, Code.str());
+ << FixItHint::CreateInsertion(LocAfterDecls, Code);
// Implicitly declare the argument as type 'int' for lack of a better
// type.
@@ -10174,6 +10248,10 @@
if (FD->hasAttr<OpenCLKernelAttr>())
return false;
+ // Don't warn on explicitly deleted functions.
+ if (FD->isDeleted())
+ return false;
+
bool MissingPrototype = true;
for (const FunctionDecl *Prev = FD->getPreviousDecl();
Prev; Prev = Prev->getPreviousDecl()) {
@@ -10316,30 +10394,6 @@
diag::err_func_def_incomplete_result))
FD->setInvalidDecl();
- // GNU warning -Wmissing-prototypes:
- // Warn if a global function is defined without a previous
- // prototype declaration. This warning is issued even if the
- // definition itself provides a prototype. The aim is to detect
- // global functions that fail to be declared in header files.
- const FunctionDecl *PossibleZeroParamPrototype = nullptr;
- if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) {
- Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
-
- if (PossibleZeroParamPrototype) {
- // We found a declaration that is not a prototype,
- // but that could be a zero-parameter prototype
- if (TypeSourceInfo *TI =
- PossibleZeroParamPrototype->getTypeSourceInfo()) {
- TypeLoc TL = TI->getTypeLoc();
- if (FunctionNoProtoTypeLoc FTL = TL.getAs<FunctionNoProtoTypeLoc>())
- Diag(PossibleZeroParamPrototype->getLocation(),
- diag::note_declaration_not_a_prototype)
- << PossibleZeroParamPrototype
- << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
- }
- }
- }
-
if (FnBodyScope)
PushDeclContext(FnBodyScope, FD);
@@ -10368,9 +10422,9 @@
I != E; ++I) {
NamedDecl *D = *I;
- // Some of these decls (like enums) may have been pinned to the translation unit
- // for lack of a real context earlier. If so, remove from the translation unit
- // and reattach to the current context.
+ // Some of these decls (like enums) may have been pinned to the
+ // translation unit for lack of a real context earlier. If so, remove
+ // from the translation unit and reattach to the current context.
if (D->getLexicalDeclContext() == Context.getTranslationUnitDecl()) {
// Is the decl actually in the context?
for (const auto *DI : Context.getTranslationUnitDecl()->decls()) {
@@ -10541,7 +10595,7 @@
if (!FD->isInvalidDecl()) {
// Don't diagnose unused parameters of defaulted or deleted functions.
- if (Body)
+ if (!FD->isDeleted() && !FD->isDefaulted())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(),
FD->getReturnType(), FD);
@@ -10559,7 +10613,55 @@
!FD->isDependentContext())
computeNRVO(Body, getCurFunction());
}
-
+
+ // GNU warning -Wmissing-prototypes:
+ // Warn if a global function is defined without a previous
+ // prototype declaration. This warning is issued even if the
+ // definition itself provides a prototype. The aim is to detect
+ // global functions that fail to be declared in header files.
+ const FunctionDecl *PossibleZeroParamPrototype = nullptr;
+ if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) {
+ Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
+
+ if (PossibleZeroParamPrototype) {
+ // We found a declaration that is not a prototype,
+ // but that could be a zero-parameter prototype
+ if (TypeSourceInfo *TI =
+ PossibleZeroParamPrototype->getTypeSourceInfo()) {
+ TypeLoc TL = TI->getTypeLoc();
+ if (FunctionNoProtoTypeLoc FTL = TL.getAs<FunctionNoProtoTypeLoc>())
+ Diag(PossibleZeroParamPrototype->getLocation(),
+ diag::note_declaration_not_a_prototype)
+ << PossibleZeroParamPrototype
+ << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
+ }
+ }
+ }
+
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ const CXXMethodDecl *KeyFunction;
+ if (MD->isOutOfLine() && (MD = MD->getCanonicalDecl()) &&
+ MD->isVirtual() &&
+ (KeyFunction = Context.getCurrentKeyFunction(MD->getParent())) &&
+ MD == KeyFunction->getCanonicalDecl()) {
+ // Update the key-function state if necessary for this ABI.
+ if (FD->isInlined() &&
+ !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) {
+ Context.setNonKeyFunction(MD);
+
+ // If the newly-chosen key function is already defined, then we
+ // need to mark the vtable as used retroactively.
+ KeyFunction = Context.getCurrentKeyFunction(MD->getParent());
+ const FunctionDecl *Definition;
+ if (KeyFunction && KeyFunction->isDefined(Definition))
+ MarkVTableUsed(Definition->getLocation(), MD->getParent(), true);
+ } else {
+ // We just defined they key function; mark the vtable as used.
+ MarkVTableUsed(FD->getLocation(), MD->getParent(), true);
+ }
+ }
+ }
+
assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) &&
"Function parsing confused");
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
@@ -10608,7 +10710,8 @@
if (getCurFunction()->ObjCWarnForNoInitDelegation) {
// Don't issue this warning for unavaialable inits.
if (!MD->isUnavailable())
- Diag(MD->getLocation(), diag::warn_objc_secondary_init_missing_init_call);
+ Diag(MD->getLocation(),
+ diag::warn_objc_secondary_init_missing_init_call);
getCurFunction()->ObjCWarnForNoInitDelegation = false;
}
} else {
@@ -10620,7 +10723,7 @@
"handled in the block above.");
// Verify and clean out per-function state.
- if (Body) {
+ if (Body && (!FD || !FD->isDefaulted())) {
// C++ constructors that have function-try-blocks can't have return
// statements in the handlers of that block. (C++ [except.handle]p14)
// Verify this.
@@ -10670,8 +10773,9 @@
}
}
- assert(ExprCleanupObjects.size() == ExprEvalContexts.back().NumCleanupObjects
- && "Leftover temporaries in function");
+ assert(ExprCleanupObjects.size() ==
+ ExprEvalContexts.back().NumCleanupObjects &&
+ "Leftover temporaries in function");
assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
assert(MaybeODRUseExprs.empty() &&
"Leftover expressions for odr-use checking");
@@ -10935,44 +11039,10 @@
case TST_union:
case TST_class: {
TagDecl *tagFromDeclSpec = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
-
- // Do nothing if the tag is not anonymous or already has an
- // associated typedef (from an earlier typedef in this decl group).
- if (tagFromDeclSpec->getIdentifier()) break;
- if (tagFromDeclSpec->getTypedefNameForAnonDecl()) break;
-
- // A well-formed anonymous tag must always be a TUK_Definition.
- assert(tagFromDeclSpec->isThisDeclarationADefinition());
-
- // The type must match the tag exactly; no qualifiers allowed.
- if (!Context.hasSameType(T, Context.getTagDeclType(tagFromDeclSpec)))
- break;
-
- // If we've already computed linkage for the anonymous tag, then
- // adding a typedef name for the anonymous decl can change that
- // linkage, which might be a serious problem. Diagnose this as
- // unsupported and ignore the typedef name. TODO: we should
- // pursue this as a language defect and establish a formal rule
- // for how to handle it.
- if (tagFromDeclSpec->hasLinkageBeenComputed()) {
- Diag(D.getIdentifierLoc(), diag::err_typedef_changes_linkage);
-
- SourceLocation tagLoc = D.getDeclSpec().getTypeSpecTypeLoc();
- tagLoc = getLocForEndOfToken(tagLoc);
-
- llvm::SmallString<40> textToInsert;
- textToInsert += ' ';
- textToInsert += D.getIdentifier()->getName();
- Diag(tagLoc, diag::note_typedef_changes_linkage)
- << FixItHint::CreateInsertion(tagLoc, textToInsert);
- break;
- }
-
- // Otherwise, set this is the anon-decl typedef for the tag.
- tagFromDeclSpec->setTypedefNameForAnonDecl(NewTD);
+ setTagNameForLinkagePurposes(tagFromDeclSpec, NewTD);
break;
}
-
+
default:
break;
}
@@ -11193,13 +11263,16 @@
return FixItHint::CreateInsertion(NameLoc, Insertion);
}
-/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the
+/// \brief This is invoked when we see 'struct foo' or 'struct {'. In the
/// former case, Name will be non-null. In the later case, Name will be null.
/// TagSpec indicates what kind of tag this is. TUK indicates whether this is a
/// reference/declaration/definition of a tag.
///
-/// IsTypeSpecifier is true if this is a type-specifier (or
+/// \param IsTypeSpecifier \c true if this is a type-specifier (or
/// trailing-type-specifier) other than one in an alias-declaration.
+///
+/// \param SkipBody If non-null, will be set to true if the caller should skip
+/// the definition of this tag, and treat it as if it were a declaration.
Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
@@ -11210,7 +11283,7 @@
SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag,
TypeResult UnderlyingType,
- bool IsTypeSpecifier) {
+ bool IsTypeSpecifier, bool *SkipBody) {
// If this is not a definition, it must have a name.
IdentifierInfo *OrigName = Name;
assert((Name != nullptr || TUK == TUK_Definition) &&
@@ -11253,7 +11326,8 @@
ModulePrivateLoc,
/*FriendLoc*/SourceLocation(),
TemplateParameterLists.size()-1,
- TemplateParameterLists.data());
+ TemplateParameterLists.data(),
+ SkipBody);
return Result.get();
} else {
// The "template<>" header is extraneous.
@@ -11636,7 +11710,7 @@
// Diagnose attempts to redefine a tag.
if (TUK == TUK_Definition) {
- if (TagDecl *Def = PrevTagDecl->getDefinition()) {
+ if (NamedDecl *Def = PrevTagDecl->getDefinition()) {
// If we're defining a specialization and the previous definition
// is from an implicit instantiation, don't emit an error
// here; we'll catch this in the general case below.
@@ -11652,7 +11726,20 @@
TSK_ExplicitSpecialization;
}
- if (!IsExplicitSpecializationAfterInstantiation) {
+ NamedDecl *Hidden = nullptr;
+ if (SkipBody && getLangOpts().CPlusPlus &&
+ !hasVisibleDefinition(Def, &Hidden)) {
+ // There is a definition of this tag, but it is not visible. We
+ // explicitly make use of C++'s one definition rule here, and
+ // assume that this definition is identical to the hidden one
+ // we already have. Make the existing definition visible and
+ // use it in place of this one.
+ *SkipBody = true;
+ if (auto *Listener = getASTMutationListener())
+ Listener->RedefinedHiddenDefinition(Hidden, KWLoc);
+ Hidden->setHidden(false);
+ return Def;
+ } else if (!IsExplicitSpecializationAfterInstantiation) {
// A redeclaration in function prototype scope in C isn't
// visible elsewhere, so merely issue a warning.
if (!getLangOpts().CPlusPlus && S->containedInPrototypeScope())
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 5ca074b..1c50d77 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -2352,6 +2352,15 @@
AttrSpellingListIndex);
}
+bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) {
+ std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName);
+ if (!Error.empty()) {
+ Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error;
+ return false;
+ }
+ return true;
+}
+
static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Make sure that there is a string literal as the sections's single
// argument.
@@ -2360,6 +2369,9 @@
if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc))
return;
+ if (!S.checkSectionName(LiteralLoc, Str))
+ return;
+
// If the target wants to validate the section specifier, make it happen.
std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(Str);
if (!Error.empty()) {
@@ -5020,8 +5032,7 @@
ND = FD;
if (ND) {
if (IdentifierInfo *Id = ND->getIdentifier()) {
- llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I
- = WeakUndeclaredIdentifiers.find(Id);
+ auto I = WeakUndeclaredIdentifiers.find(Id);
if (I != WeakUndeclaredIdentifiers.end()) {
WeakInfo W = I->second;
DeclApplyPragmaWeak(S, ND, W);
@@ -5118,7 +5129,7 @@
return false;
}
-static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K,
+static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K,
Decl *Ctx, const NamedDecl *D,
StringRef Message, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass,
@@ -5135,7 +5146,7 @@
// Don't warn if our current context is deprecated or unavailable.
switch (K) {
- case DelayedDiagnostic::Deprecation:
+ case Sema::AD_Deprecation:
if (isDeclDeprecated(Ctx))
return;
diag = !ObjCPropertyAccess ? diag::warn_deprecated
@@ -5146,7 +5157,7 @@
available_here_select_kind = /* deprecated */ 2;
break;
- case DelayedDiagnostic::Unavailable:
+ case Sema::AD_Unavailable:
if (isDeclUnavailable(Ctx))
return;
diag = !ObjCPropertyAccess ? diag::err_unavailable
@@ -5157,8 +5168,13 @@
available_here_select_kind = /* unavailable */ 0;
break;
- default:
- llvm_unreachable("Neither a deprecation or unavailable kind");
+ case Sema::AD_Partial:
+ diag = diag::warn_partial_availability;
+ diag_message = diag::warn_partial_message;
+ diag_fwdclass_message = diag::warn_partial_fwdclass_message;
+ property_note_select = /* partial */ 2;
+ available_here_select_kind = /* partial */ 3;
+ break;
}
if (!Message.empty()) {
@@ -5178,15 +5194,21 @@
S.Diag(D->getLocation(), diag::note_availability_specified_here)
<< D << available_here_select_kind;
+ if (K == Sema::AD_Partial)
+ S.Diag(Loc, diag::note_partial_availability_silence) << D;
}
static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
Decl *Ctx) {
+ assert(DD.Kind == DelayedDiagnostic::Deprecation ||
+ DD.Kind == DelayedDiagnostic::Unavailable);
+ Sema::AvailabilityDiagnostic AD = DD.Kind == DelayedDiagnostic::Deprecation
+ ? Sema::AD_Deprecation
+ : Sema::AD_Unavailable;
DD.Triggered = true;
- DoEmitAvailabilityWarning(S, (DelayedDiagnostic::DDKind)DD.Kind, Ctx,
- DD.getDeprecationDecl(), DD.getDeprecationMessage(),
- DD.Loc, DD.getUnknownObjCClass(),
- DD.getObjCProperty(), false);
+ DoEmitAvailabilityWarning(
+ S, AD, Ctx, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc,
+ DD.getUnknownObjCClass(), DD.getObjCProperty(), false);
}
void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
@@ -5252,7 +5274,7 @@
const ObjCPropertyDecl *ObjCProperty,
bool ObjCPropertyAccess) {
// Delay if we're currently parsing a declaration.
- if (DelayedDiagnostics.shouldDelayDiagnostics()) {
+ if (DelayedDiagnostics.shouldDelayDiagnostics() && AD != AD_Partial) {
DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(
AD, Loc, D, UnknownObjCClass, ObjCProperty, Message,
ObjCPropertyAccess));
@@ -5260,16 +5282,6 @@
}
Decl *Ctx = cast<Decl>(getCurLexicalContext());
- DelayedDiagnostic::DDKind K;
- switch (AD) {
- case AD_Deprecation:
- K = DelayedDiagnostic::Deprecation;
- break;
- case AD_Unavailable:
- K = DelayedDiagnostic::Unavailable;
- break;
- }
-
- DoEmitAvailabilityWarning(*this, K, Ctx, D, Message, Loc,
- UnknownObjCClass, ObjCProperty, ObjCPropertyAccess);
+ DoEmitAvailabilityWarning(*this, AD, Ctx, D, Message, Loc, UnknownObjCClass,
+ ObjCProperty, ObjCPropertyAccess);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index c41dc33..f7183bc 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3581,8 +3581,9 @@
InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation());
Expr *CtorArgE = CtorArg.getAs<Expr>();
- InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, CtorArgE);
-
+ InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind,
+ CtorArgE);
+
ExprResult MemberInit
= InitSeq.Perform(SemaRef, Entities.back(), InitKind,
MultiExprArg(&CtorArgE, 1));
@@ -4875,9 +4876,6 @@
}
}
- if (Record->isDynamicClass() && !Record->isDependentType())
- DynamicClasses.push_back(Record);
-
if (Record->getIdentifier()) {
// C++ [class.mem]p13:
// If T is the name of a class, then each of the following shall have a
@@ -8476,7 +8474,8 @@
SourceLocation UsingLoc,
UnqualifiedId &Name,
AttributeList *AttrList,
- TypeResult Type) {
+ TypeResult Type,
+ Decl *DeclFromDeclSpec) {
// Skip up to the relevant declaration scope.
while (S->getFlags() & Scope::TemplateParamScope)
S = S->getParent();
@@ -8604,6 +8603,10 @@
NewND = NewDecl;
} else {
+ if (auto *TD = dyn_cast_or_null<TagDecl>(DeclFromDeclSpec)) {
+ setTagNameForLinkagePurposes(TD, NewTD);
+ handleTagNumbering(TD, S);
+ }
ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration);
NewND = NewTD;
}
@@ -9418,6 +9421,44 @@
}
}
+static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) {
+ // Don't do anything for template patterns.
+ if (Class->getDescribedClassTemplate())
+ return;
+
+ for (Decl *Member : Class->decls()) {
+ auto *CD = dyn_cast<CXXConstructorDecl>(Member);
+ if (!CD) {
+ // Recurse on nested classes.
+ if (auto *NestedRD = dyn_cast<CXXRecordDecl>(Member))
+ getDefaultArgExprsForConstructors(S, NestedRD);
+ continue;
+ } else if (!CD->isDefaultConstructor() || !CD->hasAttr<DLLExportAttr>()) {
+ continue;
+ }
+
+ for (unsigned I = 0, E = CD->getNumParams(); I != E; ++I) {
+ // Skip any default arguments that we've already instantiated.
+ if (S.Context.getDefaultArgExprForConstructor(CD, I))
+ continue;
+
+ Expr *DefaultArg = S.BuildCXXDefaultArgExpr(Class->getLocation(), CD,
+ CD->getParamDecl(I)).get();
+ S.Context.addDefaultArgExprForConstructor(CD, I, DefaultArg);
+ }
+ }
+}
+
+void Sema::ActOnFinishCXXMemberDefaultArgs(Decl *D) {
+ auto *RD = dyn_cast<CXXRecordDecl>(D);
+
+ // Default constructors that are annotated with __declspec(dllexport) which
+ // have default arguments or don't use the standard calling convention are
+ // wrapped with a thunk called the default constructor closure.
+ if (RD && Context.getTargetInfo().getCXXABI().isMicrosoft())
+ getDefaultArgExprsForConstructors(*this, RD);
+}
+
void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
CXXDestructorDecl *Destructor) {
assert(getLangOpts().CPlusPlus11 &&
@@ -11936,7 +11977,7 @@
//
// We just pretend to initialize the object with itself, then make sure
// it can be destroyed later.
- QualType initType = ExDeclType;
+ QualType initType = Context.getExceptionObjectType(ExDeclType);
InitializedEntity entity =
InitializedEntity::InitializeVariable(ExDecl);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 33d9e95..4865b08 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -3490,12 +3490,11 @@
if (ReferencedSelectors.empty() ||
!Context.AnyObjCImplementation())
return;
- for (llvm::DenseMap<Selector, SourceLocation>::iterator S =
- ReferencedSelectors.begin(),
- E = ReferencedSelectors.end(); S != E; ++S) {
- Selector Sel = (*S).first;
+ for (auto &SelectorAndLocation : ReferencedSelectors) {
+ Selector Sel = SelectorAndLocation.first;
+ SourceLocation Loc = SelectorAndLocation.second;
if (!LookupImplementedMethodInGlobalPool(Sel))
- Diag((*S).second, diag::warn_unimplemented_selector) << Sel;
+ Diag(Loc, diag::warn_unimplemented_selector) << Sel;
}
return;
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 41abd49..51d6ace 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -167,13 +167,13 @@
void
Sema::UpdateExceptionSpec(FunctionDecl *FD,
const FunctionProtoType::ExceptionSpecInfo &ESI) {
- for (auto *Redecl : FD->redecls())
- Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
-
// If we've fully resolved the exception specification, notify listeners.
if (!isUnresolvedExceptionSpec(ESI.Type))
if (auto *Listener = getASTMutationListener())
Listener->ResolvedExceptionSpec(FD);
+
+ for (auto *Redecl : FD->redecls())
+ Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
}
/// Determine whether a function has an implicitly-generated exception
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3725b2d..6eac5b6 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -82,10 +82,26 @@
}
}
-static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
- NamedDecl *D, SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass,
- bool ObjCPropertyAccess) {
+static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) {
+ const auto *OMD = dyn_cast<ObjCMethodDecl>(D);
+ if (!OMD)
+ return false;
+ const ObjCInterfaceDecl *OID = OMD->getClassInterface();
+ if (!OID)
+ return false;
+
+ for (const ObjCCategoryDecl *Cat : OID->visible_categories())
+ if (ObjCMethodDecl *CatMeth =
+ Cat->getMethod(OMD->getSelector(), OMD->isInstanceMethod()))
+ if (!CatMeth->hasAttr<AvailabilityAttr>())
+ return true;
+ return false;
+}
+
+static AvailabilityResult
+DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ bool ObjCPropertyAccess) {
// See if this declaration is unavailable or deprecated.
std::string Message;
@@ -103,7 +119,8 @@
}
const ObjCPropertyDecl *ObjCPDecl = nullptr;
- if (Result == AR_Deprecated || Result == AR_Unavailable) {
+ if (Result == AR_Deprecated || Result == AR_Unavailable ||
+ AR_NotYetIntroduced) {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
@@ -115,9 +132,8 @@
switch (Result) {
case AR_Available:
- case AR_NotYetIntroduced:
break;
-
+
case AR_Deprecated:
if (S.getCurContextAvailability() != AR_Deprecated)
S.EmitAvailabilityWarning(Sema::AD_Deprecation,
@@ -125,6 +141,34 @@
ObjCPropertyAccess);
break;
+ case AR_NotYetIntroduced: {
+ // Don't do this for enums, they can't be redeclared.
+ if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D))
+ break;
+
+ bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited();
+ // Objective-C method declarations in categories are not modelled as
+ // redeclarations, so manually look for a redeclaration in a category
+ // if necessary.
+ if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D))
+ Warn = false;
+ // In general, D will point to the most recent redeclaration. However,
+ // for `@class A;` decls, this isn't true -- manually go through the
+ // redecl chain in that case.
+ if (Warn && isa<ObjCInterfaceDecl>(D))
+ for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn;
+ Redecl = Redecl->getPreviousDecl())
+ if (!Redecl->hasAttr<AvailabilityAttr>() ||
+ Redecl->getAttr<AvailabilityAttr>()->isInherited())
+ Warn = false;
+
+ if (Warn)
+ S.EmitAvailabilityWarning(Sema::AD_Partial, D, Message, Loc,
+ UnknownObjCClass, ObjCPDecl,
+ ObjCPropertyAccess);
+ break;
+ }
+
case AR_Unavailable:
if (S.getCurContextAvailability() != AR_Unavailable)
S.EmitAvailabilityWarning(Sema::AD_Unavailable,
@@ -307,7 +351,8 @@
DeduceReturnType(FD, Loc))
return true;
}
- DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, ObjCPropertyAccess);
+ DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass,
+ ObjCPropertyAccess);
DiagnoseUnusedOfDecl(*this, D, Loc);
@@ -3324,6 +3369,9 @@
Diag(Tok.getLocation(), diag::err_int128_unsupported);
Width = MaxWidth;
Ty = Context.getIntMaxType();
+ } else if (Literal.MicrosoftInteger == 8 && !Literal.isUnsigned) {
+ Width = 8;
+ Ty = Context.CharTy;
} else {
Width = Literal.MicrosoftInteger;
Ty = Context.getIntTypeForBitwidth(Width,
@@ -7721,7 +7769,7 @@
llvm::APSInt Right;
// Check right/shifter operand
if (RHS.get()->isValueDependent() ||
- !RHS.get()->isIntegerConstantExpr(Right, S.Context))
+ !RHS.get()->EvaluateAsInt(Right, S.Context))
return;
if (Right.isNegative()) {
@@ -7768,7 +7816,7 @@
// turned off separately if needed.
if (LeftBits == ResultBits - 1) {
S.Diag(Loc, diag::warn_shift_result_sets_sign_bit)
- << HexResult.str() << LHSType
+ << HexResult << LHSType
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return;
}
@@ -11859,8 +11907,11 @@
} else if (CXXDestructorDecl *Destructor =
dyn_cast<CXXDestructorDecl>(Func)) {
Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
- if (Destructor->isDefaulted() && !Destructor->isDeleted())
+ if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
+ if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
+ return;
DefineImplicitDestructor(Loc, Destructor);
+ }
if (Destructor->isVirtual() && getLangOpts().AppleKext)
MarkVTableUsed(Loc, Destructor->getParent());
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 695c3db..5c43e0c 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -647,37 +647,98 @@
Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";
if (Ex && !Ex->isTypeDependent()) {
- ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope);
- if (ExRes.isInvalid())
+ QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType());
+ if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex))
return ExprError();
- Ex = ExRes.get();
+
+ // Initialize the exception result. This implicitly weeds out
+ // abstract types or types with inaccessible copy constructors.
+
+ // C++0x [class.copymove]p31:
+ // When certain criteria are met, an implementation is allowed to omit the
+ // copy/move construction of a class object [...]
+ //
+ // - in a throw-expression, when the operand is the name of a
+ // non-volatile automatic object (other than a function or
+ // catch-clause
+ // parameter) whose scope does not extend beyond the end of the
+ // innermost enclosing try-block (if there is one), the copy/move
+ // operation from the operand to the exception object (15.1) can be
+ // omitted by constructing the automatic object directly into the
+ // exception object
+ const VarDecl *NRVOVariable = nullptr;
+ if (IsThrownVarInScope)
+ NRVOVariable = getCopyElisionCandidate(QualType(), Ex, false);
+
+ InitializedEntity Entity = InitializedEntity::InitializeException(
+ OpLoc, ExceptionObjectTy,
+ /*NRVO=*/NRVOVariable != nullptr);
+ ExprResult Res = PerformMoveOrCopyInitialization(
+ Entity, NRVOVariable, QualType(), Ex, IsThrownVarInScope);
+ if (Res.isInvalid())
+ return ExprError();
+ Ex = Res.get();
}
-
+
return new (Context)
CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope);
}
+static void
+collectPublicBases(CXXRecordDecl *RD,
+ llvm::DenseMap<CXXRecordDecl *, unsigned> &SubobjectsSeen,
+ llvm::SmallPtrSetImpl<CXXRecordDecl *> &VBases,
+ llvm::SetVector<CXXRecordDecl *> &PublicSubobjectsSeen,
+ bool ParentIsPublic) {
+ for (const CXXBaseSpecifier &BS : RD->bases()) {
+ CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl();
+ bool NewSubobject;
+ // Virtual bases constitute the same subobject. Non-virtual bases are
+ // always distinct subobjects.
+ if (BS.isVirtual())
+ NewSubobject = VBases.insert(BaseDecl).second;
+ else
+ NewSubobject = true;
+
+ if (NewSubobject)
+ ++SubobjectsSeen[BaseDecl];
+
+ // Only add subobjects which have public access throughout the entire chain.
+ bool PublicPath = ParentIsPublic && BS.getAccessSpecifier() == AS_public;
+ if (PublicPath)
+ PublicSubobjectsSeen.insert(BaseDecl);
+
+ // Recurse on to each base subobject.
+ collectPublicBases(BaseDecl, SubobjectsSeen, VBases, PublicSubobjectsSeen,
+ PublicPath);
+ }
+}
+
+static void getUnambiguousPublicSubobjects(
+ CXXRecordDecl *RD, llvm::SmallVectorImpl<CXXRecordDecl *> &Objects) {
+ llvm::DenseMap<CXXRecordDecl *, unsigned> SubobjectsSeen;
+ llvm::SmallSet<CXXRecordDecl *, 2> VBases;
+ llvm::SetVector<CXXRecordDecl *> PublicSubobjectsSeen;
+ SubobjectsSeen[RD] = 1;
+ PublicSubobjectsSeen.insert(RD);
+ collectPublicBases(RD, SubobjectsSeen, VBases, PublicSubobjectsSeen,
+ /*ParentIsPublic=*/true);
+
+ for (CXXRecordDecl *PublicSubobject : PublicSubobjectsSeen) {
+ // Skip ambiguous objects.
+ if (SubobjectsSeen[PublicSubobject] > 1)
+ continue;
+
+ Objects.push_back(PublicSubobject);
+ }
+}
+
/// CheckCXXThrowOperand - Validate the operand of a throw.
-ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
- bool IsThrownVarInScope) {
- // C++ [except.throw]p3:
- // A throw-expression initializes a temporary object, called the exception
- // object, the type of which is determined by removing any top-level
- // cv-qualifiers from the static type of the operand of throw and adjusting
- // the type from "array of T" or "function returning T" to "pointer to T"
- // or "pointer to function returning T", [...]
- if (E->getType().hasQualifiers())
- E = ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp,
- E->getValueKind()).get();
-
- ExprResult Res = DefaultFunctionArrayConversion(E);
- if (Res.isInvalid())
- return ExprError();
- E = Res.get();
-
+bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc,
+ QualType ExceptionObjectTy, Expr *E) {
// If the type of the exception would be an incomplete type or a pointer
// to an incomplete type other than (cv) void the program is ill-formed.
- QualType Ty = E->getType();
+ QualType Ty = ExceptionObjectTy;
bool isPointer = false;
if (const PointerType* Ptr = Ty->getAs<PointerType>()) {
Ty = Ptr->getPointeeType();
@@ -685,49 +746,20 @@
}
if (!isPointer || !Ty->isVoidType()) {
if (RequireCompleteType(ThrowLoc, Ty,
- isPointer? diag::err_throw_incomplete_ptr
- : diag::err_throw_incomplete,
+ isPointer ? diag::err_throw_incomplete_ptr
+ : diag::err_throw_incomplete,
E->getSourceRange()))
- return ExprError();
+ return true;
- if (RequireNonAbstractType(ThrowLoc, E->getType(),
+ if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy,
diag::err_throw_abstract_type, E))
- return ExprError();
+ return true;
}
- // Initialize the exception result. This implicitly weeds out
- // abstract types or types with inaccessible copy constructors.
-
- // C++0x [class.copymove]p31:
- // When certain criteria are met, an implementation is allowed to omit the
- // copy/move construction of a class object [...]
- //
- // - in a throw-expression, when the operand is the name of a
- // non-volatile automatic object (other than a function or catch-clause
- // parameter) whose scope does not extend beyond the end of the
- // innermost enclosing try-block (if there is one), the copy/move
- // operation from the operand to the exception object (15.1) can be
- // omitted by constructing the automatic object directly into the
- // exception object
- const VarDecl *NRVOVariable = nullptr;
- if (IsThrownVarInScope)
- NRVOVariable = getCopyElisionCandidate(QualType(), E, false);
-
- InitializedEntity Entity =
- InitializedEntity::InitializeException(ThrowLoc, E->getType(),
- /*NRVO=*/NRVOVariable != nullptr);
- Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable,
- QualType(), E,
- IsThrownVarInScope);
- if (Res.isInvalid())
- return ExprError();
- E = Res.get();
-
// If the exception has class type, we need additional handling.
- const RecordType *RecordTy = Ty->getAs<RecordType>();
- if (!RecordTy)
- return E;
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
+ CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
// If we are throwing a polymorphic class type or pointer thereof,
// exception handling will make use of the vtable.
@@ -735,22 +767,69 @@
// If a pointer is thrown, the referenced object will not be destroyed.
if (isPointer)
- return E;
+ return false;
// If the class has a destructor, we must be able to call it.
- if (RD->hasIrrelevantDestructor())
- return E;
+ if (!RD->hasIrrelevantDestructor()) {
+ if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) {
+ MarkFunctionReferenced(E->getExprLoc(), Destructor);
+ CheckDestructorAccess(E->getExprLoc(), Destructor,
+ PDiag(diag::err_access_dtor_exception) << Ty);
+ if (DiagnoseUseOfDecl(Destructor, E->getExprLoc()))
+ return true;
+ }
+ }
- CXXDestructorDecl *Destructor = LookupDestructor(RD);
- if (!Destructor)
- return E;
+ // The MSVC ABI creates a list of all types which can catch the exception
+ // object. This list also references the appropriate copy constructor to call
+ // if the object is caught by value and has a non-trivial copy constructor.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ // We are only interested in the public, unambiguous bases contained within
+ // the exception object. Bases which are ambiguous or otherwise
+ // inaccessible are not catchable types.
+ llvm::SmallVector<CXXRecordDecl *, 2> UnambiguousPublicSubobjects;
+ getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects);
- MarkFunctionReferenced(E->getExprLoc(), Destructor);
- CheckDestructorAccess(E->getExprLoc(), Destructor,
- PDiag(diag::err_access_dtor_exception) << Ty);
- if (DiagnoseUseOfDecl(Destructor, E->getExprLoc()))
- return ExprError();
- return E;
+ for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) {
+ // Attempt to lookup the copy constructor. Various pieces of machinery
+ // will spring into action, like template instantiation, which means this
+ // cannot be a simple walk of the class's decls. Instead, we must perform
+ // lookup and overload resolution.
+ CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0);
+ if (!CD)
+ continue;
+
+ // Mark the constructor referenced as it is used by this throw expression.
+ MarkFunctionReferenced(E->getExprLoc(), CD);
+
+ // Skip this copy constructor if it is trivial, we don't need to record it
+ // in the catchable type data.
+ if (CD->isTrivial())
+ continue;
+
+ // The copy constructor is non-trivial, create a mapping from this class
+ // type to this constructor.
+ // N.B. The selection of copy constructor is not sensitive to this
+ // particular throw-site. Lookup will be performed at the catch-site to
+ // ensure that the copy constructor is, in fact, accessible (via
+ // friendship or any other means).
+ Context.addCopyConstructorForExceptionObject(Subobject, CD);
+
+ // We don't keep the instantiated default argument expressions around so
+ // we must rebuild them here.
+ for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) {
+ // Skip any default arguments that we've already instantiated.
+ if (Context.getDefaultArgExprForConstructor(CD, I))
+ continue;
+
+ Expr *DefaultArg =
+ BuildCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I)).get();
+ Context.addDefaultArgExprForConstructor(CD, I, DefaultArg);
+ }
+ }
+ }
+
+ return false;
}
QualType Sema::getCurrentThisType() {
@@ -2089,7 +2168,7 @@
}
}
}
-
+
FunctionProtoType::ExtProtoInfo EPI;
QualType BadAllocType;
@@ -2122,16 +2201,6 @@
Alloc->addAttr(VisibilityAttr::CreateImplicit(Context,
VisibilityAttr::Default));
- if (NumParams == 2 && !getLangOpts().DefineSizedDeallocation) {
- assert(getLangOpts().SizedDeallocation &&
- "Only sized deallocation can have two parameters");
-
- // This declaration should be emited as extern_weak.
- assert(Alloc->getLinkageAndVisibility().getLinkage() ==
- clang::ExternalLinkage);
- Alloc->addAttr(WeakAttr::CreateImplicit(Context));
- }
-
if (AddRestrictAttr)
Alloc->addAttr(
RestrictAttr::CreateImplicit(Context, RestrictAttr::GNU_malloc));
@@ -3015,8 +3084,18 @@
break;
case ICK_Vector_Splat:
- From = ImpCastExprToType(From, ToType, CK_VectorSplat,
- VK_RValue, /*BasePath=*/nullptr, CCK).get();
+ // Vector splat from any arithmetic type to a vector.
+ // Cast to the element type.
+ {
+ QualType elType = ToType->getAs<ExtVectorType>()->getElementType();
+ if (elType != From->getType()) {
+ ExprResult E = From;
+ From = ImpCastExprToType(From, elType,
+ PrepareScalarCast(E, elType)).get();
+ }
+ From = ImpCastExprToType(From, ToType, CK_VectorSplat,
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
+ }
break;
case ICK_Complex_Real:
@@ -5692,10 +5771,9 @@
if (Exp.isInvalid())
return true;
- MemberExpr *ME =
- new (Context) MemberExpr(Exp.get(), /*IsArrow=*/false, Method,
- SourceLocation(), Context.BoundMemberTy,
- VK_RValue, OK_Ordinary);
+ MemberExpr *ME = new (Context) MemberExpr(
+ Exp.get(), /*IsArrow=*/false, SourceLocation(), Method, SourceLocation(),
+ Context.BoundMemberTy, VK_RValue, OK_Ordinary);
if (HadMultipleCandidates)
ME->setHadMultipleCandidates(true);
MarkMemberReferenced(ME);
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index b27bd39..fab2fe1 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -749,8 +749,8 @@
static ExprResult
BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- const CXXScopeSpec &SS, FieldDecl *Field,
- DeclAccessPair FoundDecl,
+ SourceLocation OpLoc, const CXXScopeSpec &SS,
+ FieldDecl *Field, DeclAccessPair FoundDecl,
const DeclarationNameInfo &MemberNameInfo);
ExprResult
@@ -837,10 +837,10 @@
// Make a nameInfo that properly uses the anonymous name.
DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
-
+
result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
- EmptySS, field, foundDecl,
- memberNameInfo).get();
+ SourceLocation(), EmptySS, field,
+ foundDecl, memberNameInfo).get();
if (!result)
return ExprError();
@@ -858,9 +858,10 @@
DeclAccessPair fakeFoundDecl =
DeclAccessPair::make(field, field->getAccess());
- result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
- (FI == FEnd? SS : EmptySS), field,
- fakeFoundDecl, memberNameInfo).get();
+ result =
+ BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
+ SourceLocation(), (FI == FEnd ? SS : EmptySS),
+ field, fakeFoundDecl, memberNameInfo).get();
}
return result;
@@ -880,18 +881,16 @@
}
/// \brief Build a MemberExpr AST node.
-static MemberExpr *
-BuildMemberExpr(Sema &SemaRef, ASTContext &C, Expr *Base, bool isArrow,
- const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- ValueDecl *Member, DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo, QualType Ty,
- ExprValueKind VK, ExprObjectKind OK,
- const TemplateArgumentListInfo *TemplateArgs = nullptr) {
+static MemberExpr *BuildMemberExpr(
+ Sema &SemaRef, ASTContext &C, Expr *Base, bool isArrow,
+ SourceLocation OpLoc, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+ ValueDecl *Member, DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK,
+ ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = nullptr) {
assert((!isArrow || Base->isRValue()) && "-> base must be a pointer rvalue");
- MemberExpr *E =
- MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
- TemplateKWLoc, Member, FoundDecl, MemberNameInfo,
- TemplateArgs, Ty, VK, OK);
+ MemberExpr *E = MemberExpr::Create(
+ C, Base, isArrow, OpLoc, SS.getWithLocInContext(C), TemplateKWLoc, Member,
+ FoundDecl, MemberNameInfo, TemplateArgs, Ty, VK, OK);
SemaRef.MarkMemberReferenced(E);
return E;
}
@@ -1074,8 +1073,8 @@
return ExprError();
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
- return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
- SS, FD, FoundDecl, MemberNameInfo);
+ return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, OpLoc, SS, FD,
+ FoundDecl, MemberNameInfo);
if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl))
return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD,
@@ -1089,8 +1088,8 @@
OpLoc);
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
- return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
- Var, FoundDecl, MemberNameInfo,
+ return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, OpLoc, SS,
+ TemplateKWLoc, Var, FoundDecl, MemberNameInfo,
Var->getType().getNonReferenceType(), VK_LValue,
OK_Ordinary);
}
@@ -1106,16 +1105,16 @@
type = MemberFn->getType();
}
- return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
- MemberFn, FoundDecl, MemberNameInfo, type, valueKind,
- OK_Ordinary);
+ return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, OpLoc, SS,
+ TemplateKWLoc, MemberFn, FoundDecl, MemberNameInfo,
+ type, valueKind, OK_Ordinary);
}
assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
- return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
- Enum, FoundDecl, MemberNameInfo, Enum->getType(),
- VK_RValue, OK_Ordinary);
+ return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, OpLoc, SS,
+ TemplateKWLoc, Enum, FoundDecl, MemberNameInfo,
+ Enum->getType(), VK_RValue, OK_Ordinary);
}
// We found something that we didn't expect. Complain.
@@ -1660,8 +1659,8 @@
static ExprResult
BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- const CXXScopeSpec &SS, FieldDecl *Field,
- DeclAccessPair FoundDecl,
+ SourceLocation OpLoc, const CXXScopeSpec &SS,
+ FieldDecl *Field, DeclAccessPair FoundDecl,
const DeclarationNameInfo &MemberNameInfo) {
// x.a is an l-value if 'a' has a reference type. Otherwise:
// x.a is an l-value/x-value/pr-value if the base is (and note
@@ -1714,7 +1713,7 @@
FoundDecl, Field);
if (Base.isInvalid())
return ExprError();
- return BuildMemberExpr(S, S.Context, Base.get(), IsArrow, SS,
+ return BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS,
/*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
MemberNameInfo, MemberType, VK, OK);
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index ebe6cbb..52a384f 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -1061,15 +1061,11 @@
} else
DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc,
WarnMultipleSelectors);
-
+
if (Method &&
Method->getImplementationControl() != ObjCMethodDecl::Optional &&
- !getSourceManager().isInSystemHeader(Method->getLocation())) {
- llvm::DenseMap<Selector, SourceLocation>::iterator Pos
- = ReferencedSelectors.find(Sel);
- if (Pos == ReferencedSelectors.end())
- ReferencedSelectors.insert(std::make_pair(Sel, AtLoc));
- }
+ !getSourceManager().isInSystemHeader(Method->getLocation()))
+ ReferencedSelectors.insert(std::make_pair(Sel, AtLoc));
// In ARC, forbid the user from using @selector for
// retain/release/autorelease/dealloc/retainCount.
@@ -1509,64 +1505,6 @@
return nullptr;
}
-static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) {
- if (!Receiver)
- return;
-
- if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Receiver))
- Receiver = OVE->getSourceExpr();
-
- Expr *RExpr = Receiver->IgnoreParenImpCasts();
- SourceLocation Loc = RExpr->getLocStart();
- QualType T = RExpr->getType();
- const ObjCPropertyDecl *PDecl = nullptr;
- const ObjCMethodDecl *GDecl = nullptr;
- if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(RExpr)) {
- RExpr = POE->getSyntacticForm();
- if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(RExpr)) {
- if (PRE->isImplicitProperty()) {
- GDecl = PRE->getImplicitPropertyGetter();
- if (GDecl) {
- T = GDecl->getReturnType();
- }
- }
- else {
- PDecl = PRE->getExplicitProperty();
- if (PDecl) {
- T = PDecl->getType();
- }
- }
- }
- }
- else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RExpr)) {
- // See if receiver is a method which envokes a synthesized getter
- // backing a 'weak' property.
- ObjCMethodDecl *Method = ME->getMethodDecl();
- if (Method && Method->getSelector().getNumArgs() == 0) {
- PDecl = Method->findPropertyDecl();
- if (PDecl)
- T = PDecl->getType();
- }
- }
-
- if (T.getObjCLifetime() != Qualifiers::OCL_Weak) {
- if (!PDecl)
- return;
- if (!(PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak))
- return;
- }
-
- S.Diag(Loc, diag::warn_receiver_is_weak)
- << ((!PDecl && !GDecl) ? 0 : (PDecl ? 1 : 2));
-
- if (PDecl)
- S.Diag(PDecl->getLocation(), diag::note_property_declare);
- else if (GDecl)
- S.Diag(GDecl->getLocation(), diag::note_method_declared_at) << GDecl;
-
- S.Diag(Loc, diag::note_arc_assign_to_strong);
-}
-
/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an
/// objective C interface. This is a property reference expression.
ExprResult Sema::
@@ -2760,15 +2698,6 @@
}
if (getLangOpts().ObjCAutoRefCount) {
- // Do not warn about IBOutlet weak property receivers being set to null
- // as this cannot asynchronously happen.
- bool WarnWeakReceiver = true;
- if (isImplicit && Method)
- if (const ObjCPropertyDecl *PropertyDecl = Method->findPropertyDecl())
- WarnWeakReceiver = !PropertyDecl->hasAttr<IBOutletAttr>();
- if (WarnWeakReceiver)
- DiagnoseARCUseOfWeakReceiver(*this, Receiver);
-
// In ARC, annotate delegate init calls.
if (Result->getMethodFamily() == OMF_init &&
(SuperLoc.isValid() || isSelfExpr(Receiver))) {
@@ -2799,7 +2728,9 @@
}
}
}
-
+
+ CheckObjCCircularContainer(Result);
+
return MaybeBindToTemporary(Result);
}
@@ -2808,8 +2739,7 @@
dyn_cast<ObjCSelectorExpr>(Arg->IgnoreParenCasts())) {
Selector Sel = OSE->getSelector();
SourceLocation Loc = OSE->getAtLoc();
- llvm::DenseMap<Selector, SourceLocation>::iterator Pos
- = S.ReferencedSelectors.find(Sel);
+ auto Pos = S.ReferencedSelectors.find(Sel);
if (Pos != S.ReferencedSelectors.end() && Pos->second == Loc)
S.ReferencedSelectors.erase(Pos);
}
@@ -3475,6 +3405,9 @@
if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
HadTheAttribute = true;
+ if (Parm->isStr("id"))
+ return true;
+
NamedDecl *Target = nullptr;
// Check for an existing type with this name.
LookupResult R(S, DeclarationName(Parm), SourceLocation(),
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 06d2223..ac7376e 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -415,7 +415,9 @@
// If it's not unique, pull something off the back (and
// continue at this index).
// FIXME: This is wrong. We need to take the more recent declaration in
- // order to get the right type, default arguments, etc.
+ // order to get the right type, default arguments, etc. We also need to
+ // prefer visible declarations to hidden ones (for redeclaration lookup
+ // in modules builds).
Decls[I] = Decls[--N];
continue;
}
@@ -1215,11 +1217,27 @@
/// path (by instantiating a template, you allow it to see the declarations that
/// your module can see, including those later on in your module).
bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
- assert(D->isHidden() && !SemaRef.ActiveTemplateInstantiations.empty() &&
- "should not call this: not in slow case");
+ assert(D->isHidden() && "should not call this: not in slow case");
Module *DeclModule = D->getOwningModule();
assert(DeclModule && "hidden decl not from a module");
+ // If this declaration is not at namespace scope nor module-private,
+ // then it is visible if its lexical parent has a visible definition.
+ DeclContext *DC = D->getLexicalDeclContext();
+ if (!D->isModulePrivate() &&
+ DC && !DC->isFileContext() && !isa<LinkageSpecDecl>(DC)) {
+ NamedDecl *Hidden;
+ if (SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC), &Hidden)) {
+ if (SemaRef.ActiveTemplateInstantiations.empty()) {
+ // Cache the fact that this declaration is implicitly visible because
+ // its parent has a visible definition.
+ D->setHidden(false);
+ }
+ return true;
+ }
+ return false;
+ }
+
// Find the extra places where we need to look.
llvm::DenseSet<Module*> &LookupModules = SemaRef.getLookupModules();
if (LookupModules.empty())
@@ -3019,17 +3037,45 @@
if (Visited.visitedContext(Ctx->getPrimaryContext()))
return;
+ // Outside C++, lookup results for the TU live on identifiers.
+ if (isa<TranslationUnitDecl>(Ctx) &&
+ !Result.getSema().getLangOpts().CPlusPlus) {
+ auto &S = Result.getSema();
+ auto &Idents = S.Context.Idents;
+
+ // Ensure all external identifiers are in the identifier table.
+ if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) {
+ std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers());
+ for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next())
+ Idents.get(Name);
+ }
+
+ // Walk all lookup results in the TU for each identifier.
+ for (const auto &Ident : Idents) {
+ for (auto I = S.IdResolver.begin(Ident.getValue()),
+ E = S.IdResolver.end();
+ I != E; ++I) {
+ if (S.IdResolver.isDeclInScope(*I, Ctx)) {
+ if (NamedDecl *ND = Result.getAcceptableDecl(*I)) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
+ Visited.add(ND);
+ }
+ }
+ }
+ }
+
+ return;
+ }
+
if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
Result.getSema().ForceDeclarationOfImplicitMembers(Class);
// Enumerate all of the results in this context.
for (const auto &R : Ctx->lookups()) {
- for (auto *I : R) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(I)) {
- if ((ND = Result.getAcceptableDecl(ND))) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
- Visited.add(ND);
- }
+ for (auto *D : R) {
+ if (auto *ND = Result.getAcceptableDecl(D)) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
+ Visited.add(ND);
}
}
}
@@ -3683,8 +3729,7 @@
TypoCorrectionConsumer::NamespaceSpecifierSet::NamespaceSpecifierSet(
ASTContext &Context, DeclContext *CurContext, CXXScopeSpec *CurScopeSpec)
- : Context(Context), CurContextChain(buildContextChain(CurContext)),
- isSorted(false) {
+ : Context(Context), CurContextChain(buildContextChain(CurContext)) {
if (NestedNameSpecifier *NNS =
CurScopeSpec ? CurScopeSpec->getScopeRep() : nullptr) {
llvm::raw_string_ostream SpecifierOStream(CurNameSpecifier);
@@ -3703,7 +3748,6 @@
}
// Add the global context as a NestedNameSpecifier
- Distances.insert(1);
SpecifierInfo SI = {cast<DeclContext>(Context.getTranslationUnitDecl()),
NestedNameSpecifier::GlobalSpecifier(Context), 1};
DistanceMap[1].push_back(SI);
@@ -3723,22 +3767,6 @@
return Chain;
}
-void TypoCorrectionConsumer::NamespaceSpecifierSet::sortNamespaces() {
- SmallVector<unsigned, 4> sortedDistances;
- sortedDistances.append(Distances.begin(), Distances.end());
-
- if (sortedDistances.size() > 1)
- std::sort(sortedDistances.begin(), sortedDistances.end());
-
- Specifiers.clear();
- for (auto D : sortedDistances) {
- SpecifierInfoList &SpecList = DistanceMap[D];
- Specifiers.append(SpecList.begin(), SpecList.end());
- }
-
- isSorted = true;
-}
-
unsigned
TypoCorrectionConsumer::NamespaceSpecifierSet::buildNestedNameSpecifier(
DeclContextList &DeclChain, NestedNameSpecifier *&NNS) {
@@ -3819,8 +3847,6 @@
llvm::makeArrayRef(NewNameSpecifierIdentifiers));
}
- isSorted = false;
- Distances.insert(NumSpecifiers);
SpecifierInfo SI = {Ctx, NNS, NumSpecifiers};
DistanceMap[NumSpecifiers].push_back(SI);
}
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index d8bedd7..e027e55 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -308,8 +308,7 @@
// bound to the current team is shared.
if (DVar.DKind == OMPD_task) {
DSAVarData DVarTemp;
- for (StackTy::reverse_iterator I = std::next(Iter),
- EE = std::prev(Stack.rend());
+ for (StackTy::reverse_iterator I = std::next(Iter), EE = Stack.rend();
I != EE; ++I) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables
// Referenced
@@ -623,6 +622,10 @@
PopExpressionEvaluationContext();
}
+static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
+ Expr *NumIterations, Sema &SemaRef,
+ Scope *S);
+
namespace {
class VarDeclFilterCCC : public CorrectionCandidateCallback {
@@ -1122,11 +1125,19 @@
break;
}
case OMPD_task: {
+ QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
Sema::CapturedParamNameType Params[] = {
+ std::make_pair(".global_tid.", KmpInt32Ty),
+ std::make_pair(".part_id.", KmpInt32Ty),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
+ // Mark this captured region as inlined, because we don't use outlined
+ // function directly.
+ getCurCapturedRegion()->TheCapturedDecl->addAttr(
+ AlwaysInlineAttr::CreateImplicit(
+ Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange()));
break;
}
case OMPD_ordered: {
@@ -2908,6 +2919,7 @@
// Save results
Built.IterationVarRef = IV.get();
Built.LastIteration = LastIteration.get();
+ Built.NumIterations = NumIterations.get();
Built.CalcLastIteration = CalcLastIteration.get();
Built.PreCond = PreCond.get();
Built.Cond = Cond.get();
@@ -2951,6 +2963,16 @@
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp simd loop exprs were not built");
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (auto C : Clauses) {
+ if (auto LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope))
+ return StmtError();
+ }
+ }
+
getCurFunction()->setHasBranchProtectedScope();
return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
Clauses, AStmt, B);
@@ -3229,6 +3251,211 @@
return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, AStmt);
}
+namespace {
+/// \brief Helper class for checking expression in 'omp atomic [update]'
+/// construct.
+class OpenMPAtomicUpdateChecker {
+ /// \brief Error results for atomic update expressions.
+ enum ExprAnalysisErrorCode {
+ /// \brief A statement is not an expression statement.
+ NotAnExpression,
+ /// \brief Expression is not builtin binary or unary operation.
+ NotABinaryOrUnaryExpression,
+ /// \brief Unary operation is not post-/pre- increment/decrement operation.
+ NotAnUnaryIncDecExpression,
+ /// \brief An expression is not of scalar type.
+ NotAScalarType,
+ /// \brief A binary operation is not an assignment operation.
+ NotAnAssignmentOp,
+ /// \brief RHS part of the binary operation is not a binary expression.
+ NotABinaryExpression,
+ /// \brief RHS part is not additive/multiplicative/shift/biwise binary
+ /// expression.
+ NotABinaryOperator,
+ /// \brief RHS binary operation does not have reference to the updated LHS
+ /// part.
+ NotAnUpdateExpression,
+ /// \brief No errors is found.
+ NoError
+ };
+ /// \brief Reference to Sema.
+ Sema &SemaRef;
+ /// \brief A location for note diagnostics (when error is found).
+ SourceLocation NoteLoc;
+ /// \brief Atomic operation supposed to be performed on source expression.
+ BinaryOperatorKind OpKind;
+ /// \brief 'x' lvalue part of the source atomic expression.
+ Expr *X;
+ /// \brief 'x' rvalue part of the source atomic expression, used in the right
+ /// hand side of the expression. We need this to properly generate RHS part of
+ /// the source expression (x = x'rval' binop expr or x = expr binop x'rval').
+ Expr *XRVal;
+ /// \brief 'expr' rvalue part of the source atomic expression.
+ Expr *E;
+
+public:
+ OpenMPAtomicUpdateChecker(Sema &SemaRef)
+ : SemaRef(SemaRef), OpKind(BO_PtrMemD), X(nullptr), XRVal(nullptr),
+ E(nullptr) {}
+ /// \brief Check specified statement that it is suitable for 'atomic update'
+ /// constructs and extract 'x', 'expr' and Operation from the original
+ /// expression.
+ /// \param DiagId Diagnostic which should be emitted if error is found.
+ /// \param NoteId Diagnostic note for the main error message.
+ /// \return true if statement is not an update expression, false otherwise.
+ bool checkStatement(Stmt *S, unsigned DiagId, unsigned NoteId);
+ /// \brief Return the 'x' lvalue part of the source atomic expression.
+ Expr *getX() const { return X; }
+ /// \brief Return the 'x' rvalue part of the source atomic expression, used in
+ /// the RHS part of the source expression.
+ Expr *getXRVal() const { return XRVal; }
+ /// \brief Return the 'expr' rvalue part of the source atomic expression.
+ Expr *getExpr() const { return E; }
+ /// \brief Return required atomic operation.
+ BinaryOperatorKind getOpKind() const {return OpKind;}
+private:
+ bool checkBinaryOperation(BinaryOperator *AtomicBinOp, unsigned DiagId,
+ unsigned NoteId);
+};
+} // namespace
+
+bool OpenMPAtomicUpdateChecker::checkBinaryOperation(
+ BinaryOperator *AtomicBinOp, unsigned DiagId, unsigned NoteId) {
+ ExprAnalysisErrorCode ErrorFound = NoError;
+ SourceLocation ErrorLoc, NoteLoc;
+ SourceRange ErrorRange, NoteRange;
+ // Allowed constructs are:
+ // x = x binop expr;
+ // x = expr binop x;
+ if (AtomicBinOp->getOpcode() == BO_Assign) {
+ X = AtomicBinOp->getLHS();
+ if (auto *AtomicInnerBinOp = dyn_cast<BinaryOperator>(
+ AtomicBinOp->getRHS()->IgnoreParenImpCasts())) {
+ if (AtomicInnerBinOp->isMultiplicativeOp() ||
+ AtomicInnerBinOp->isAdditiveOp() || AtomicInnerBinOp->isShiftOp() ||
+ AtomicInnerBinOp->isBitwiseOp()) {
+ OpKind = AtomicInnerBinOp->getOpcode();
+ auto *LHS = AtomicInnerBinOp->getLHS();
+ auto *RHS = AtomicInnerBinOp->getRHS();
+ llvm::FoldingSetNodeID XId, LHSId, RHSId;
+ X->IgnoreParenImpCasts()->Profile(XId, SemaRef.getASTContext(),
+ /*Canonical=*/true);
+ LHS->IgnoreParenImpCasts()->Profile(LHSId, SemaRef.getASTContext(),
+ /*Canonical=*/true);
+ RHS->IgnoreParenImpCasts()->Profile(RHSId, SemaRef.getASTContext(),
+ /*Canonical=*/true);
+ if (XId == LHSId) {
+ E = RHS;
+ XRVal = LHS;
+ } else if (XId == RHSId) {
+ E = LHS;
+ XRVal = RHS;
+ } else {
+ ErrorLoc = AtomicInnerBinOp->getExprLoc();
+ ErrorRange = AtomicInnerBinOp->getSourceRange();
+ NoteLoc = X->getExprLoc();
+ NoteRange = X->getSourceRange();
+ ErrorFound = NotAnUpdateExpression;
+ }
+ } else {
+ ErrorLoc = AtomicInnerBinOp->getExprLoc();
+ ErrorRange = AtomicInnerBinOp->getSourceRange();
+ NoteLoc = AtomicInnerBinOp->getOperatorLoc();
+ NoteRange = SourceRange(NoteLoc, NoteLoc);
+ ErrorFound = NotABinaryOperator;
+ }
+ } else {
+ NoteLoc = ErrorLoc = AtomicBinOp->getRHS()->getExprLoc();
+ NoteRange = ErrorRange = AtomicBinOp->getRHS()->getSourceRange();
+ ErrorFound = NotABinaryExpression;
+ }
+ } else {
+ ErrorLoc = AtomicBinOp->getExprLoc();
+ ErrorRange = AtomicBinOp->getSourceRange();
+ NoteLoc = AtomicBinOp->getOperatorLoc();
+ NoteRange = SourceRange(NoteLoc, NoteLoc);
+ ErrorFound = NotAnAssignmentOp;
+ }
+ if (ErrorFound != NoError) {
+ SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange;
+ SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange;
+ return true;
+ } else if (SemaRef.CurContext->isDependentContext())
+ E = X = XRVal = nullptr;
+ return false;
+}
+
+bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId,
+ unsigned NoteId) {
+ ExprAnalysisErrorCode ErrorFound = NoError;
+ SourceLocation ErrorLoc, NoteLoc;
+ SourceRange ErrorRange, NoteRange;
+ // Allowed constructs are:
+ // x++;
+ // x--;
+ // ++x;
+ // --x;
+ // x binop= expr;
+ // x = x binop expr;
+ // x = expr binop x;
+ if (auto *AtomicBody = dyn_cast<Expr>(S)) {
+ AtomicBody = AtomicBody->IgnoreParenImpCasts();
+ if (AtomicBody->getType()->isScalarType() ||
+ AtomicBody->isInstantiationDependent()) {
+ if (auto *AtomicCompAssignOp = dyn_cast<CompoundAssignOperator>(
+ AtomicBody->IgnoreParenImpCasts())) {
+ // Check for Compound Assignment Operation
+ OpKind = BinaryOperator::getOpForCompoundAssignment(
+ AtomicCompAssignOp->getOpcode());
+ X = AtomicCompAssignOp->getLHS();
+ XRVal = SemaRef.PerformImplicitConversion(
+ X, AtomicCompAssignOp->getComputationLHSType(),
+ Sema::AA_Casting, /*AllowExplicit=*/true).get();
+ E = AtomicCompAssignOp->getRHS();
+ } else if (auto *AtomicBinOp = dyn_cast<BinaryOperator>(
+ AtomicBody->IgnoreParenImpCasts())) {
+ // Check for Binary Operation
+ return checkBinaryOperation(AtomicBinOp, DiagId, NoteId);
+ } else if (auto *AtomicUnaryOp =
+ // Check for Binary Operation
+ dyn_cast<UnaryOperator>(AtomicBody->IgnoreParenImpCasts())) {
+ // Check for Unary Operation
+ if (AtomicUnaryOp->isIncrementDecrementOp()) {
+ OpKind = AtomicUnaryOp->isIncrementOp() ? BO_Add : BO_Sub;
+ XRVal = X = AtomicUnaryOp->getSubExpr();
+ E = SemaRef.ActOnIntegerConstant(AtomicUnaryOp->getOperatorLoc(), 1)
+ .get();
+ } else {
+ ErrorFound = NotAnUnaryIncDecExpression;
+ ErrorLoc = AtomicUnaryOp->getExprLoc();
+ ErrorRange = AtomicUnaryOp->getSourceRange();
+ NoteLoc = AtomicUnaryOp->getOperatorLoc();
+ NoteRange = SourceRange(NoteLoc, NoteLoc);
+ }
+ } else {
+ ErrorFound = NotABinaryOrUnaryExpression;
+ NoteLoc = ErrorLoc = AtomicBody->getExprLoc();
+ NoteRange = ErrorRange = AtomicBody->getSourceRange();
+ }
+ } else {
+ ErrorFound = NotAScalarType;
+ NoteLoc = ErrorLoc = AtomicBody->getLocStart();
+ NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
+ }
+ } else {
+ ErrorFound = NotAnExpression;
+ NoteLoc = ErrorLoc = S->getLocStart();
+ NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
+ }
+ if (ErrorFound != NoError) {
+ SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange;
+ SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange;
+ return true;
+ } else if (SemaRef.CurContext->isDependentContext())
+ E = X = XRVal = nullptr;
+ return false;
+}
+
StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
@@ -3260,7 +3487,12 @@
}
auto Body = CS->getCapturedStmt();
+ if (auto *EWC = dyn_cast<ExprWithCleanups>(Body))
+ Body = EWC->getSubExpr();
+
+ BinaryOperatorKind OpKind = BO_PtrMemD;
Expr *X = nullptr;
+ Expr *XRVal = nullptr;
Expr *V = nullptr;
Expr *E = nullptr;
// OpenMP [2.12.6, atomic Construct]
@@ -3356,8 +3588,8 @@
auto AtomicBinOp =
dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts());
if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) {
- X = AtomicBinOp->getLHS()->IgnoreParenImpCasts();
- E = AtomicBinOp->getRHS()->IgnoreParenImpCasts();
+ X = AtomicBinOp->getLHS();
+ E = AtomicBinOp->getRHS();
if ((X->isInstantiationDependent() || X->getType()->isScalarType()) &&
(E->isInstantiationDependent() || E->getType()->isScalarType())) {
if (!X->isLValue()) {
@@ -3402,11 +3634,26 @@
} else if (CurContext->isDependentContext())
E = X = nullptr;
} else if (AtomicKind == OMPC_update || AtomicKind == OMPC_unknown) {
- if (!isa<Expr>(Body)) {
- Diag(Body->getLocStart(),
- diag::err_omp_atomic_update_not_expression_statement)
- << (AtomicKind == OMPC_update);
+ // If clause is update:
+ // x++;
+ // x--;
+ // ++x;
+ // --x;
+ // x binop= expr;
+ // x = x binop expr;
+ // x = expr binop x;
+ OpenMPAtomicUpdateChecker Checker(*this);
+ if (Checker.checkStatement(
+ Body, (AtomicKind == OMPC_update)
+ ? diag::err_omp_atomic_update_not_expression_statement
+ : diag::err_omp_atomic_not_expression_statement,
+ diag::note_omp_atomic_update))
return StmtError();
+ if (!CurContext->isDependentContext()) {
+ E = Checker.getExpr();
+ X = Checker.getX();
+ XRVal = Checker.getXRVal();
+ OpKind = Checker.getOpKind();
}
} else if (AtomicKind == OMPC_capture) {
if (isa<Expr>(Body) && !isa<BinaryOperator>(Body)) {
@@ -3423,7 +3670,7 @@
getCurFunction()->setHasBranchProtectedScope();
return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
- X, V, E);
+ OpKind, X, XRVal, V, E);
}
StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,
@@ -4999,11 +5246,13 @@
SourceLocation ColonLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
+ SmallVector<Expr *, 8> Inits;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP linear clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
+ Inits.push_back(nullptr);
continue;
}
@@ -5045,6 +5294,7 @@
if (QType->isDependentType() || QType->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
+ Inits.push_back(nullptr);
continue;
}
@@ -5090,14 +5340,27 @@
continue;
}
+ // Build var to save initial value.
+ VarDecl *Init = BuildVarDecl(*this, ELoc, DE->getType(), ".linear.start");
+ AddInitializerToDecl(Init, DefaultLvalueConversion(DE).get(),
+ /*DirectInit*/ false, /*TypeMayContainAuto*/ false);
+ CurContext->addDecl(Init);
+ Init->setIsUsed();
+ auto InitRef = DeclRefExpr::Create(
+ Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
+ /*TemplateKWLoc*/ SourceLocation(), Init,
+ /*isEnclosingLocal*/ false, DE->getLocStart(), DE->getType(),
+ /*VK*/ VK_LValue);
DSAStack->addDSA(VD, DE, OMPC_linear);
Vars.push_back(DE);
+ Inits.push_back(InitRef);
}
if (Vars.empty())
return nullptr;
Expr *StepExpr = Step;
+ Expr *CalcStepExpr = nullptr;
if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
!Step->isInstantiationDependent() &&
!Step->containsUnexpandedParameterPack()) {
@@ -5107,17 +5370,85 @@
return nullptr;
StepExpr = Val.get();
+ // Build var to save the step value.
+ VarDecl *SaveVar =
+ BuildVarDecl(*this, StepLoc, StepExpr->getType(), ".linear.step");
+ CurContext->addDecl(SaveVar);
+ SaveVar->setIsUsed();
+ ExprResult SaveRef =
+ BuildDeclRefExpr(SaveVar, StepExpr->getType(), VK_LValue, StepLoc);
+ ExprResult CalcStep =
+ BuildBinOp(CurScope, StepLoc, BO_Assign, SaveRef.get(), StepExpr);
+
// Warn about zero linear step (it would be probably better specified as
// making corresponding variables 'const').
llvm::APSInt Result;
- if (StepExpr->isIntegerConstantExpr(Result, Context) &&
- !Result.isNegative() && !Result.isStrictlyPositive())
+ bool IsConstant = StepExpr->isIntegerConstantExpr(Result, Context);
+ if (IsConstant && !Result.isNegative() && !Result.isStrictlyPositive())
Diag(StepLoc, diag::warn_omp_linear_step_zero) << Vars[0]
<< (Vars.size() > 1);
+ if (!IsConstant && CalcStep.isUsable()) {
+ // Calculate the step beforehand instead of doing this on each iteration.
+ // (This is not used if the number of iterations may be kfold-ed).
+ CalcStepExpr = CalcStep.get();
+ }
}
return OMPLinearClause::Create(Context, StartLoc, LParenLoc, ColonLoc, EndLoc,
- Vars, StepExpr);
+ Vars, Inits, StepExpr, CalcStepExpr);
+}
+
+static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
+ Expr *NumIterations, Sema &SemaRef,
+ Scope *S) {
+ // Walk the vars and build update/final expressions for the CodeGen.
+ SmallVector<Expr *, 8> Updates;
+ SmallVector<Expr *, 8> Finals;
+ Expr *Step = Clause.getStep();
+ Expr *CalcStep = Clause.getCalcStep();
+ // OpenMP [2.14.3.7, linear clause]
+ // If linear-step is not specified it is assumed to be 1.
+ if (Step == nullptr)
+ Step = SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get();
+ else if (CalcStep)
+ Step = cast<BinaryOperator>(CalcStep)->getLHS();
+ bool HasErrors = false;
+ auto CurInit = Clause.inits().begin();
+ for (auto &RefExpr : Clause.varlists()) {
+ Expr *InitExpr = *CurInit;
+
+ // Build privatized reference to the current linear var.
+ auto DE = cast<DeclRefExpr>(RefExpr);
+ auto PrivateRef = DeclRefExpr::Create(
+ SemaRef.Context, /*QualifierLoc*/ DE->getQualifierLoc(),
+ /*TemplateKWLoc*/ SourceLocation(), DE->getDecl(),
+ /* RefersToEnclosingVariableOrCapture */ true, DE->getLocStart(),
+ DE->getType(), /*VK*/ VK_LValue);
+
+ // Build update: Var = InitExpr + IV * Step
+ ExprResult Update =
+ BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), PrivateRef,
+ InitExpr, IV, Step, /* Subtract */ false);
+ Update = SemaRef.ActOnFinishFullExpr(Update.get());
+
+ // Build final: Var = InitExpr + NumIterations * Step
+ ExprResult Final =
+ BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), RefExpr, InitExpr,
+ NumIterations, Step, /* Subtract */ false);
+ Final = SemaRef.ActOnFinishFullExpr(Final.get());
+ if (!Update.isUsable() || !Final.isUsable()) {
+ Updates.push_back(nullptr);
+ Finals.push_back(nullptr);
+ HasErrors = true;
+ } else {
+ Updates.push_back(Update.get());
+ Finals.push_back(Final.get());
+ }
+ ++CurInit;
+ }
+ Clause.setUpdates(Updates);
+ Clause.setFinals(Finals);
+ return HasErrors;
}
OMPClause *Sema::ActOnOpenMPAlignedClause(
@@ -5283,11 +5614,17 @@
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
+ SmallVector<Expr *, 8> SrcExprs;
+ SmallVector<Expr *, 8> DstExprs;
+ SmallVector<Expr *, 8> AssignmentOps;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP copyprivate clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
+ SrcExprs.push_back(nullptr);
+ DstExprs.push_back(nullptr);
+ AssignmentOps.push_back(nullptr);
continue;
}
@@ -5309,6 +5646,9 @@
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
+ SrcExprs.push_back(nullptr);
+ DstExprs.push_back(nullptr);
+ AssignmentOps.push_back(nullptr);
continue;
}
@@ -5317,8 +5657,8 @@
// private or firstprivate clause on the single construct.
if (!DSAStack->isThreadPrivate(VD)) {
auto DVar = DSAStack->getTopDSA(VD, false);
- if (DVar.CKind != OMPC_copyprivate && DVar.CKind != OMPC_unknown &&
- !(DVar.CKind == OMPC_private && !DVar.RefExpr)) {
+ if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_copyprivate &&
+ DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_copyprivate);
@@ -5345,41 +5685,36 @@
// A variable of class type (or array thereof) that appears in a
// copyin clause requires an accessible, unambiguous copy assignment
// operator for the class type.
- Type = Context.getBaseElementType(Type);
- CXXRecordDecl *RD =
- getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
- // FIXME This code must be replaced by actual assignment of the
- // threadprivate variable.
- if (RD) {
- CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0);
- DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess());
- if (MD) {
- if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible ||
- MD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_copyprivate) << 2;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
- }
- MarkFunctionReferenced(ELoc, MD);
- DiagnoseUseOfDecl(MD, ELoc);
- }
- }
+ auto *SrcVD = BuildVarDecl(*this, DE->getLocStart(), VD->getType(),
+ ".copyprivate.src");
+ auto *PseudoSrcExpr = BuildDeclRefExpr(SrcVD, DE->getType(), VK_LValue,
+ DE->getExprLoc()).get();
+ auto *DstVD = BuildVarDecl(*this, DE->getLocStart(), VD->getType(),
+ ".copyprivate.dst");
+ auto *PseudoDstExpr = BuildDeclRefExpr(DstVD, DE->getType(), VK_LValue,
+ DE->getExprLoc()).get();
+ auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign,
+ PseudoDstExpr, PseudoSrcExpr);
+ if (AssignmentOp.isInvalid())
+ continue;
+ AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(),
+ /*DiscardedValue=*/true);
+ if (AssignmentOp.isInvalid())
+ continue;
// No need to mark vars as copyprivate, they are already threadprivate or
// implicitly private.
Vars.push_back(DE);
+ SrcExprs.push_back(PseudoSrcExpr);
+ DstExprs.push_back(PseudoDstExpr);
+ AssignmentOps.push_back(AssignmentOp.get());
}
if (Vars.empty())
return nullptr;
- return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+ return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ Vars, SrcExprs, DstExprs, AssignmentOps);
}
OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList,
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 664b6a4..fbf110b 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1762,8 +1762,8 @@
// We have already pre-calculated the promotion type, so this is trivial.
if (ToType->isIntegerType() &&
!RequireCompleteType(From->getLocStart(), FromType, 0))
- return Context.hasSameUnqualifiedType(ToType,
- FromEnumType->getDecl()->getPromotionType());
+ return Context.hasSameUnqualifiedType(
+ ToType, FromEnumType->getDecl()->getPromotionType());
}
// C++0x [conv.prom]p2:
@@ -1811,13 +1811,12 @@
// other value of that type for promotion purposes (C++ 4.5p3).
// FIXME: We should delay checking of bit-fields until we actually perform the
// conversion.
- using llvm::APSInt;
- if (From)
+ if (From) {
if (FieldDecl *MemberDecl = From->getSourceBitField()) {
- APSInt BitWidth;
+ llvm::APSInt BitWidth;
if (FromType->isIntegralType(Context) &&
MemberDecl->getBitWidth()->isIntegerConstantExpr(BitWidth, Context)) {
- APSInt ToSize(BitWidth.getBitWidth(), BitWidth.isUnsigned());
+ llvm::APSInt ToSize(BitWidth.getBitWidth(), BitWidth.isUnsigned());
ToSize = Context.getTypeSize(ToType);
// Are we promoting to an int from a bitfield that fits in an int?
@@ -1835,6 +1834,7 @@
return false;
}
}
+ }
// An rvalue of type bool can be converted to an rvalue of type int,
// with false becoming zero and true becoming one (C++ 4.5p4).
@@ -9497,10 +9497,7 @@
numLFixes = (numLFixes == 0) ? UINT_MAX : numLFixes;
numRFixes = (numRFixes == 0) ? UINT_MAX : numRFixes;
if (numLFixes != numRFixes) {
- if (numLFixes < numRFixes)
- return true;
- else
- return false;
+ return numLFixes < numRFixes;
}
// If there's any ordering between the defined conversions...
@@ -12488,21 +12485,17 @@
type = Fn->getType();
} else {
valueKind = VK_RValue;
- type = Context.BoundMemberTy;
- }
-
- MemberExpr *ME = MemberExpr::Create(Context, Base,
- MemExpr->isArrow(),
- MemExpr->getQualifierLoc(),
- MemExpr->getTemplateKeywordLoc(),
- Fn,
- Found,
- MemExpr->getMemberNameInfo(),
- TemplateArgs,
- type, valueKind, OK_Ordinary);
- ME->setHadMultipleCandidates(true);
- MarkMemberReferenced(ME);
- return ME;
+ type = Context.BoundMemberTy;
+ }
+
+ MemberExpr *ME = MemberExpr::Create(
+ Context, Base, MemExpr->isArrow(), MemExpr->getOperatorLoc(),
+ MemExpr->getQualifierLoc(), MemExpr->getTemplateKeywordLoc(), Fn, Found,
+ MemExpr->getMemberNameInfo(), TemplateArgs, type, valueKind,
+ OK_Ordinary);
+ ME->setHadMultipleCandidates(true);
+ MarkMemberReferenced(ME);
+ return ME;
}
llvm_unreachable("Invalid reference to overloaded function");
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index bc5c155..f923f61 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -906,12 +906,12 @@
if (PrevString == CurrString)
Diag(CaseVals[i].second->getLHS()->getLocStart(),
diag::err_duplicate_case) <<
- (PrevString.empty() ? CaseValStr.str() : PrevString);
+ (PrevString.empty() ? StringRef(CaseValStr) : PrevString);
else
Diag(CaseVals[i].second->getLHS()->getLocStart(),
diag::err_duplicate_case_differing_expr) <<
- (PrevString.empty() ? CaseValStr.str() : PrevString) <<
- (CurrString.empty() ? CaseValStr.str() : CurrString) <<
+ (PrevString.empty() ? StringRef(CaseValStr) : PrevString) <<
+ (CurrString.empty() ? StringRef(CaseValStr) : CurrString) <<
CaseValStr;
Diag(CaseVals[i-1].second->getLHS()->getLocStart(),
@@ -2428,6 +2428,14 @@
return new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E);
}
+static void CheckJumpOutOfSEHFinally(Sema &S, SourceLocation Loc,
+ const Scope &DestScope) {
+ if (!S.CurrentSEHFinally.empty() &&
+ DestScope.Contains(*S.CurrentSEHFinally.back())) {
+ S.Diag(Loc, diag::warn_jump_out_of_seh_finally);
+ }
+}
+
StmtResult
Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
Scope *S = CurScope->getContinueParent();
@@ -2435,6 +2443,7 @@
// C99 6.8.6.2p1: A break shall appear only in or as a loop body.
return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop));
}
+ CheckJumpOutOfSEHFinally(*this, ContinueLoc, *S);
return new (Context) ContinueStmt(ContinueLoc);
}
@@ -2449,6 +2458,7 @@
if (S->isOpenMPLoopScope())
return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt)
<< "break");
+ CheckJumpOutOfSEHFinally(*this, BreakLoc, *S);
return new (Context) BreakStmt(BreakLoc);
}
@@ -2908,6 +2918,8 @@
CurScope->setNoNRVO();
}
+ CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent());
+
return R;
}
@@ -3184,7 +3196,7 @@
Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@throw";
if (!Throw) {
- // @throw without an expression designates a rethrow (which much occur
+ // @throw without an expression designates a rethrow (which must occur
// in the context of an @catch clause).
Scope *AtCatchParent = CurScope;
while (AtCatchParent && !AtCatchParent->isAtCatchScope())
@@ -3406,11 +3418,18 @@
return SEHExceptStmt::Create(Context,Loc,FilterExpr,Block);
}
-StmtResult
-Sema::ActOnSEHFinallyBlock(SourceLocation Loc,
- Stmt *Block) {
+void Sema::ActOnStartSEHFinallyBlock() {
+ CurrentSEHFinally.push_back(CurScope);
+}
+
+void Sema::ActOnAbortSEHFinallyBlock() {
+ CurrentSEHFinally.pop_back();
+}
+
+StmtResult Sema::ActOnFinishSEHFinallyBlock(SourceLocation Loc, Stmt *Block) {
assert(Block);
- return SEHFinallyStmt::Create(Context,Loc,Block);
+ CurrentSEHFinally.pop_back();
+ return SEHFinallyStmt::Create(Context, Loc, Block);
}
StmtResult
@@ -3420,6 +3439,7 @@
SEHTryParent = SEHTryParent->getParent();
if (!SEHTryParent)
return StmtError(Diag(Loc, diag::err_ms___leave_not_in___try));
+ CheckJumpOutOfSEHFinally(*this, Loc, *SEHTryParent);
return new (Context) SEHLeaveStmt(Loc);
}
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index c091cf8..179e207 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -124,6 +124,17 @@
// The parser verifies that there is a string literal here.
assert(AsmString->isAscii());
+ bool ValidateConstraints = true;
+ if (getLangOpts().CUDA) {
+ // In CUDA mode don't verify asm constraints in device functions during host
+ // compilation and vice versa.
+ bool InDeviceMode = getLangOpts().CUDAIsDevice;
+ FunctionDecl *FD = getCurFunctionDecl();
+ bool IsDeviceFunction =
+ FD && (FD->hasAttr<CUDADeviceAttr>() || FD->hasAttr<CUDAGlobalAttr>());
+ ValidateConstraints = IsDeviceFunction == InDeviceMode;
+ }
+
for (unsigned i = 0; i != NumOutputs; i++) {
StringLiteral *Literal = Constraints[i];
assert(Literal->isAscii());
@@ -133,7 +144,8 @@
OutputName = Names[i]->getName();
TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
- if (!Context.getTargetInfo().validateOutputConstraint(Info))
+ if (ValidateConstraints &&
+ !Context.getTargetInfo().validateOutputConstraint(Info))
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_invalid_output_constraint)
<< Info.getConstraintStr());
@@ -207,8 +219,9 @@
InputName = Names[i]->getName();
TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
- if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(),
- NumOutputs, Info)) {
+ if (ValidateConstraints &&
+ !Context.getTargetInfo().validateInputConstraint(
+ OutputConstraintInfos.data(), NumOutputs, Info)) {
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_invalid_input_constraint)
<< Info.getConstraintStr());
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 6cba79a..c642c05 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -12,6 +12,7 @@
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
@@ -836,7 +837,8 @@
AccessSpecifier AS, SourceLocation ModulePrivateLoc,
SourceLocation FriendLoc,
unsigned NumOuterTemplateParamLists,
- TemplateParameterList** OuterTemplateParamLists) {
+ TemplateParameterList** OuterTemplateParamLists,
+ bool *SkipBody) {
assert(TemplateParams && TemplateParams->size() > 0 &&
"No template parameters");
assert(TUK != TUK_Reference && "Can only declare or define class templates");
@@ -993,6 +995,23 @@
// Check for redefinition of this class template.
if (TUK == TUK_Definition) {
if (TagDecl *Def = PrevRecordDecl->getDefinition()) {
+ // If we have a prior definition that is not visible, treat this as
+ // simply making that previous definition visible.
+ NamedDecl *Hidden = nullptr;
+ if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
+ *SkipBody = true;
+ auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
+ assert(Tmpl && "original definition of a class template is not a "
+ "class template?");
+ if (auto *Listener = getASTMutationListener()) {
+ Listener->RedefinedHiddenDefinition(Hidden, KWLoc);
+ Listener->RedefinedHiddenDefinition(Tmpl, KWLoc);
+ }
+ Hidden->setHidden(false);
+ Tmpl->setHidden(false);
+ return Def;
+ }
+
Diag(NameLoc, diag::err_redefinition) << Name;
Diag(Def->getLocation(), diag::note_previous_definition);
// FIXME: Would it make sense to try to "forget" the previous
@@ -5835,11 +5854,13 @@
if (isa<TranslationUnitDecl>(SpecializedContext))
S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
<< EntityKind << Specialized;
- else if (isa<NamespaceDecl>(SpecializedContext))
- S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope)
- << EntityKind << Specialized
- << cast<NamedDecl>(SpecializedContext);
- else
+ else if (isa<NamespaceDecl>(SpecializedContext)) {
+ int Diag = diag::err_template_spec_redecl_out_of_scope;
+ if (S.getLangOpts().MicrosoftExt)
+ Diag = diag::ext_ms_template_spec_redecl_out_of_scope;
+ S.Diag(Loc, Diag) << EntityKind << Specialized
+ << cast<NamedDecl>(SpecializedContext);
+ } else
llvm_unreachable("unexpected namespace context for specialization");
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
@@ -8303,7 +8324,7 @@
// Take tokens to avoid allocations
LPT->Toks.swap(Toks);
LPT->D = FnD;
- LateParsedTemplateMap[FD] = LPT;
+ LateParsedTemplateMap.insert(std::make_pair(FD, LPT));
FD->setLateTemplateParsed(true);
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 3515918..af8d309 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -576,6 +576,7 @@
DeducedPack *Outer;
};
+namespace {
/// A scope in which we're performing pack deduction.
class PackDeductionScope {
public:
@@ -730,6 +731,7 @@
SmallVector<DeducedPack, 2> Packs;
};
+} // namespace
/// \brief Deduce the template arguments by comparing the list of parameter
/// types to the list of argument types, as in the parameter-type-lists of
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index ed0d5a5..8e4fe85 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -200,13 +200,13 @@
llvm_unreachable("Invalid InstantiationKind!");
}
-void Sema::InstantiatingTemplate::Initialize(
- ActiveTemplateInstantiation::InstantiationKind Kind,
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, ActiveTemplateInstantiation::InstantiationKind Kind,
SourceLocation PointOfInstantiation, SourceRange InstantiationRange,
Decl *Entity, NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
- sema::TemplateDeductionInfo *DeductionInfo) {
- SavedInNonInstantiationSFINAEContext =
- SemaRef.InNonInstantiationSFINAEContext;
+ sema::TemplateDeductionInfo *DeductionInfo)
+ : SemaRef(SemaRef), SavedInNonInstantiationSFINAEContext(
+ SemaRef.InNonInstantiationSFINAEContext) {
// Don't allow further instantiation if a fatal error has occcured. Any
// diagnostics we might have raised will not be visible.
if (SemaRef.Diags.hasFatalErrorOccurred()) {
@@ -231,124 +231,98 @@
}
}
-Sema::InstantiatingTemplate::
-InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- Decl *Entity,
- SourceRange InstantiationRange)
- : SemaRef(SemaRef)
-{
- Initialize(ActiveTemplateInstantiation::TemplateInstantiation,
- PointOfInstantiation, InstantiationRange, Entity);
-}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(SemaRef,
+ ActiveTemplateInstantiation::TemplateInstantiation,
+ PointOfInstantiation, InstantiationRange, Entity) {}
-Sema::InstantiatingTemplate::
-InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- FunctionDecl *Entity, ExceptionSpecification,
- SourceRange InstantiationRange)
- : SemaRef(SemaRef)
-{
- Initialize(ActiveTemplateInstantiation::ExceptionSpecInstantiation,
- PointOfInstantiation, InstantiationRange, Entity);
-}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionDecl *Entity,
+ ExceptionSpecification, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, ActiveTemplateInstantiation::ExceptionSpecInstantiation,
+ PointOfInstantiation, InstantiationRange, Entity) {}
-Sema::InstantiatingTemplate::
-InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- TemplateDecl *Template,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange InstantiationRange)
- : SemaRef(SemaRef)
-{
- Initialize(ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation,
- PointOfInstantiation, InstantiationRange,
- Template, nullptr, TemplateArgs);
-}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template,
+ ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef,
+ ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation,
+ PointOfInstantiation, InstantiationRange, Template, nullptr,
+ TemplateArgs) {}
-Sema::InstantiatingTemplate::
-InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- FunctionTemplateDecl *FunctionTemplate,
- ArrayRef<TemplateArgument> TemplateArgs,
- ActiveTemplateInstantiation::InstantiationKind Kind,
- sema::TemplateDeductionInfo &DeductionInfo,
- SourceRange InstantiationRange)
- : SemaRef(SemaRef)
-{
- Initialize(Kind, PointOfInstantiation, InstantiationRange,
- FunctionTemplate, nullptr, TemplateArgs, &DeductionInfo);
-}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ FunctionTemplateDecl *FunctionTemplate,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ ActiveTemplateInstantiation::InstantiationKind Kind,
+ sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
+ : InstantiatingTemplate(SemaRef, Kind, PointOfInstantiation,
+ InstantiationRange, FunctionTemplate, nullptr,
+ TemplateArgs, &DeductionInfo) {}
-Sema::InstantiatingTemplate::
-InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- ClassTemplatePartialSpecializationDecl *PartialSpec,
- ArrayRef<TemplateArgument> TemplateArgs,
- sema::TemplateDeductionInfo &DeductionInfo,
- SourceRange InstantiationRange)
- : SemaRef(SemaRef)
-{
- Initialize(ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
- PointOfInstantiation, InstantiationRange,
- PartialSpec, nullptr, TemplateArgs, &DeductionInfo);
-}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ClassTemplatePartialSpecializationDecl *PartialSpec,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef,
+ ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
+ PointOfInstantiation, InstantiationRange, PartialSpec, nullptr,
+ TemplateArgs, &DeductionInfo) {}
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
VarTemplatePartialSpecializationDecl *PartialSpec,
ArrayRef<TemplateArgument> TemplateArgs,
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
- : SemaRef(SemaRef)
-{
- Initialize(ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
- PointOfInstantiation, InstantiationRange,
- PartialSpec, nullptr, TemplateArgs, &DeductionInfo);
-}
+ : InstantiatingTemplate(
+ SemaRef,
+ ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
+ PointOfInstantiation, InstantiationRange, PartialSpec, nullptr,
+ TemplateArgs, &DeductionInfo) {}
-Sema::InstantiatingTemplate::
-InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- ParmVarDecl *Param,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange InstantiationRange)
- : SemaRef(SemaRef)
-{
- Initialize(ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation,
- PointOfInstantiation, InstantiationRange,
- Param, nullptr, TemplateArgs);
-}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param,
+ ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef,
+ ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation,
+ PointOfInstantiation, InstantiationRange, Param, nullptr,
+ TemplateArgs) {}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template,
+ NonTypeTemplateParmDecl *Param, ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef,
+ ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution,
+ PointOfInstantiation, InstantiationRange, Param, Template,
+ TemplateArgs) {}
-Sema::InstantiatingTemplate::
-InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- NamedDecl *Template, NonTypeTemplateParmDecl *Param,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange InstantiationRange)
- : SemaRef(SemaRef)
-{
- Initialize(ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution,
- PointOfInstantiation, InstantiationRange,
- Param, Template, TemplateArgs);
-}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template,
+ TemplateTemplateParmDecl *Param, ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef,
+ ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution,
+ PointOfInstantiation, InstantiationRange, Param, Template,
+ TemplateArgs) {}
-Sema::InstantiatingTemplate::
-InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- NamedDecl *Template, TemplateTemplateParmDecl *Param,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange InstantiationRange)
- : SemaRef(SemaRef)
-{
- Initialize(ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution,
- PointOfInstantiation, InstantiationRange,
- Param, Template, TemplateArgs);
-}
-
-Sema::InstantiatingTemplate::
-InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- TemplateDecl *Template, NamedDecl *Param,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange InstantiationRange)
- : SemaRef(SemaRef)
-{
- Initialize(ActiveTemplateInstantiation::DefaultTemplateArgumentChecking,
- PointOfInstantiation, InstantiationRange,
- Param, Template, TemplateArgs);
-}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template,
+ NamedDecl *Param, ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, ActiveTemplateInstantiation::DefaultTemplateArgumentChecking,
+ PointOfInstantiation, InstantiationRange, Param, Template,
+ TemplateArgs) {}
void Sema::InstantiatingTemplate::Clear() {
if (!Invalid) {
@@ -2069,6 +2043,10 @@
SourceLocation(), SourceLocation(), nullptr);
CheckCompletedCXXClass(Instantiation);
+ // Default arguments are parsed, if not instantiated. We can go instantiate
+ // default arg exprs for default constructors if necessary now.
+ ActOnFinishCXXMemberDefaultArgs(Instantiation);
+
// Instantiate late parsed attributes, and attach them to their decls.
// See Sema::InstantiateAttrs
for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(),
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 1df0701..6936539 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -289,6 +289,11 @@
}
Decl *
+TemplateDeclInstantiator::VisitExternCContextDecl(ExternCContextDecl *D) {
+ llvm_unreachable("extern \"C\" context cannot be instantiated");
+}
+
+Decl *
TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) {
LabelDecl *Inst = LabelDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getIdentifier());
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 5614225..485b70a 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -871,7 +871,8 @@
if (S.getLangOpts().OpenCL &&
!((S.getLangOpts().OpenCLVersion >= 120) ||
S.getOpenCLOptions().cl_khr_fp64)) {
- S.Diag(DS.getTypeSpecTypeLoc(), diag::err_double_requires_fp64);
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension)
+ << Result << "cl_khr_fp64";
declarator.setInvalidType(true);
}
break;
@@ -947,6 +948,30 @@
<< DS.getSourceRange();
declarator.setInvalidType(true);
}
+ } else if (S.getLangOpts().OpenCL) {
+ if (const AtomicType *AT = Result->getAs<AtomicType>()) {
+ const BuiltinType *BT = AT->getValueType()->getAs<BuiltinType>();
+ bool NoExtTypes = BT && (BT->getKind() == BuiltinType::Int ||
+ BT->getKind() == BuiltinType::UInt ||
+ BT->getKind() == BuiltinType::Float);
+ if (!S.getOpenCLOptions().cl_khr_int64_base_atomics && !NoExtTypes) {
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension)
+ << Result << "cl_khr_int64_base_atomics";
+ declarator.setInvalidType(true);
+ }
+ if (!S.getOpenCLOptions().cl_khr_int64_extended_atomics &&
+ !NoExtTypes) {
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension)
+ << Result << "cl_khr_int64_extended_atomics";
+ declarator.setInvalidType(true);
+ }
+ if (!S.getOpenCLOptions().cl_khr_fp64 && BT &&
+ BT->getKind() == BuiltinType::Double) {
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension)
+ << Result << "cl_khr_fp64";
+ declarator.setInvalidType(true);
+ }
+ }
}
// TypeQuals handled by caller.
@@ -5101,9 +5126,9 @@
/// \param D The definition of the entity.
/// \param Suggested Filled in with the declaration that should be made visible
/// in order to provide a definition of this entity.
-static bool hasVisibleDefinition(Sema &S, NamedDecl *D, NamedDecl **Suggested) {
+bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) {
// Easy case: if we don't have modules, all declarations are visible.
- if (!S.getLangOpts().Modules)
+ if (!getLangOpts().Modules)
return true;
// If this definition was instantiated from a template, map back to the
@@ -5119,7 +5144,7 @@
// If the enum has a fixed underlying type, any declaration of it will do.
*Suggested = nullptr;
for (auto *Redecl : ED->redecls()) {
- if (LookupResult::isVisible(S, Redecl))
+ if (LookupResult::isVisible(*this, Redecl))
return true;
if (Redecl->isThisDeclarationADefinition() ||
(Redecl->isCanonicalDecl() && !*Suggested))
@@ -5134,7 +5159,7 @@
// FIXME: If we merged any other decl into D, and that declaration is visible,
// then we should consider a definition to be visible.
*Suggested = D;
- return LookupResult::isVisible(S, D);
+ return LookupResult::isVisible(*this, D);
}
/// Locks in the inheritance model for the given class and all of its bases.
@@ -5185,7 +5210,7 @@
// If we know about the definition but it is not visible, complain.
NamedDecl *SuggestedDef = nullptr;
if (!Diagnoser.Suppressed && Def &&
- !hasVisibleDefinition(*this, Def, &SuggestedDef)) {
+ !hasVisibleDefinition(Def, &SuggestedDef)) {
// Suppress this error outside of a SFINAE context if we've already
// emitted the error once for this type. There's no usefulness in
// repeating the diagnostic.
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index e1d0d18..1b0080a 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1702,7 +1702,7 @@
}
StmtResult RebuildSEHFinallyStmt(SourceLocation Loc, Stmt *Block) {
- return getSema().ActOnSEHFinallyBlock(Loc, Block);
+ return SEHFinallyStmt::Create(getSema().getASTContext(), Loc, Block);
}
/// \brief Build a new predefined expression.
@@ -1870,11 +1870,9 @@
return ExprError();
Base = BaseResult.get();
ExprValueKind VK = isArrow ? VK_LValue : Base->getValueKind();
- MemberExpr *ME =
- new (getSema().Context) MemberExpr(Base, isArrow,
- Member, MemberNameInfo,
- cast<FieldDecl>(Member)->getType(),
- VK, OK_Ordinary);
+ MemberExpr *ME = new (getSema().Context)
+ MemberExpr(Base, isArrow, OpLoc, Member, MemberNameInfo,
+ cast<FieldDecl>(Member)->getType(), VK, OK_Ordinary);
return ME;
}
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 04425ac..85c574c 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -94,6 +94,7 @@
switch (DC->getDeclKind()) {
// These entities may have multiple definitions.
case Decl::TranslationUnit:
+ case Decl::ExternCContext:
case Decl::Namespace:
case Decl::LinkageSpec:
return nullptr;
@@ -149,7 +150,11 @@
bool serialization::isRedeclarableDeclKind(unsigned Kind) {
switch (static_cast<Decl::Kind>(Kind)) {
- case Decl::TranslationUnit: // Special case of a "merged" declaration.
+ case Decl::TranslationUnit:
+ case Decl::ExternCContext:
+ // Special case of a "merged" declaration.
+ return true;
+
case Decl::Namespace:
case Decl::NamespaceAlias:
case Decl::Typedef:
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index 88cdbcf..79d1817 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -29,12 +29,14 @@
UPD_CXX_ADDED_FUNCTION_DEFINITION,
UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
UPD_CXX_INSTANTIATED_CLASS_DEFINITION,
+ UPD_CXX_RESOLVED_DTOR_DELETE,
UPD_CXX_RESOLVED_EXCEPTION_SPEC,
UPD_CXX_DEDUCED_RETURN_TYPE,
UPD_DECL_MARKED_USED,
UPD_MANGLING_NUMBER,
UPD_STATIC_LOCAL_NUMBER,
- UPD_DECL_MARKED_OPENMP_THREADPRIVATE
+ UPD_DECL_MARKED_OPENMP_THREADPRIVATE,
+ UPD_DECL_EXPORTED
};
TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT);
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 0ee2b2b..4d5141b 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1,4 +1,4 @@
-//===--- ASTReader.cpp - AST File Reader ----------------------------------===//
+//===-- ASTReader.cpp - AST File Reader ----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -89,11 +89,13 @@
Second->ReadLanguageOptions(LangOpts, Complain,
AllowCompatibleDifferences);
}
-bool
-ChainedASTReaderListener::ReadTargetOptions(const TargetOptions &TargetOpts,
- bool Complain) {
- return First->ReadTargetOptions(TargetOpts, Complain) ||
- Second->ReadTargetOptions(TargetOpts, Complain);
+bool ChainedASTReaderListener::ReadTargetOptions(
+ const TargetOptions &TargetOpts, bool Complain,
+ bool AllowCompatibleDifferences) {
+ return First->ReadTargetOptions(TargetOpts, Complain,
+ AllowCompatibleDifferences) ||
+ Second->ReadTargetOptions(TargetOpts, Complain,
+ AllowCompatibleDifferences);
}
bool ChainedASTReaderListener::ReadDiagnosticOptions(
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) {
@@ -232,7 +234,8 @@
/// \returns true if the target options mis-match, false otherwise.
static bool checkTargetOptions(const TargetOptions &TargetOpts,
const TargetOptions &ExistingTargetOpts,
- DiagnosticsEngine *Diags) {
+ DiagnosticsEngine *Diags,
+ bool AllowCompatibleDifferences = true) {
#define CHECK_TARGET_OPT(Field, Name) \
if (TargetOpts.Field != ExistingTargetOpts.Field) { \
if (Diags) \
@@ -241,9 +244,16 @@
return true; \
}
+ // The triple and ABI must match exactly.
CHECK_TARGET_OPT(Triple, "target");
- CHECK_TARGET_OPT(CPU, "target CPU");
CHECK_TARGET_OPT(ABI, "target ABI");
+
+ // We can tolerate different CPUs in many cases, notably when one CPU
+ // supports a strict superset of another. When allowing compatible
+ // differences skip this check.
+ if (!AllowCompatibleDifferences)
+ CHECK_TARGET_OPT(CPU, "target CPU");
+
#undef CHECK_TARGET_OPT
// Compare feature sets.
@@ -255,43 +265,31 @@
std::sort(ExistingFeatures.begin(), ExistingFeatures.end());
std::sort(ReadFeatures.begin(), ReadFeatures.end());
- unsigned ExistingIdx = 0, ExistingN = ExistingFeatures.size();
- unsigned ReadIdx = 0, ReadN = ReadFeatures.size();
- while (ExistingIdx < ExistingN && ReadIdx < ReadN) {
- if (ExistingFeatures[ExistingIdx] == ReadFeatures[ReadIdx]) {
- ++ExistingIdx;
- ++ReadIdx;
- continue;
- }
+ // We compute the set difference in both directions explicitly so that we can
+ // diagnose the differences differently.
+ SmallVector<StringRef, 4> UnmatchedExistingFeatures, UnmatchedReadFeatures;
+ std::set_difference(
+ ExistingFeatures.begin(), ExistingFeatures.end(), ReadFeatures.begin(),
+ ReadFeatures.end(), std::back_inserter(UnmatchedExistingFeatures));
+ std::set_difference(ReadFeatures.begin(), ReadFeatures.end(),
+ ExistingFeatures.begin(), ExistingFeatures.end(),
+ std::back_inserter(UnmatchedReadFeatures));
- if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) {
- if (Diags)
- Diags->Report(diag::err_pch_targetopt_feature_mismatch)
- << false << ReadFeatures[ReadIdx];
- return true;
- }
+ // If we are allowing compatible differences and the read feature set is
+ // a strict subset of the existing feature set, there is nothing to diagnose.
+ if (AllowCompatibleDifferences && UnmatchedReadFeatures.empty())
+ return false;
- if (Diags)
+ if (Diags) {
+ for (StringRef Feature : UnmatchedReadFeatures)
Diags->Report(diag::err_pch_targetopt_feature_mismatch)
- << true << ExistingFeatures[ExistingIdx];
- return true;
+ << /* is-existing-feature */ false << Feature;
+ for (StringRef Feature : UnmatchedExistingFeatures)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << /* is-existing-feature */ true << Feature;
}
- if (ExistingIdx < ExistingN) {
- if (Diags)
- Diags->Report(diag::err_pch_targetopt_feature_mismatch)
- << true << ExistingFeatures[ExistingIdx];
- return true;
- }
-
- if (ReadIdx < ReadN) {
- if (Diags)
- Diags->Report(diag::err_pch_targetopt_feature_mismatch)
- << false << ReadFeatures[ReadIdx];
- return true;
- }
-
- return false;
+ return !UnmatchedReadFeatures.empty() || !UnmatchedExistingFeatures.empty();
}
bool
@@ -305,10 +303,12 @@
}
bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts,
- bool Complain) {
+ bool Complain,
+ bool AllowCompatibleDifferences) {
const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
return checkTargetOptions(TargetOpts, ExistingTargetOpts,
- Complain? &Reader.Diags : nullptr);
+ Complain ? &Reader.Diags : nullptr,
+ AllowCompatibleDifferences);
}
namespace {
@@ -826,7 +826,7 @@
uint32_t LocalMacroID =
endian::readNext<uint32_t, little, unaligned>(d);
DataLen -= 4;
- if (LocalMacroID == 0xdeadbeef) break;
+ if (LocalMacroID == (uint32_t)-1) break;
LocalMacroIDs.push_back(LocalMacroID);
}
}
@@ -1807,7 +1807,7 @@
};
ASTReader::ModuleMacroInfo *
-ASTReader::getModuleMacro(const PendingMacroInfo &PMInfo) {
+ASTReader::getModuleMacro(IdentifierInfo *II, const PendingMacroInfo &PMInfo) {
ModuleMacroInfo Info;
uint32_t ID = PMInfo.ModuleMacroData.MacID;
@@ -1815,6 +1815,11 @@
// Macro undefinition.
Info.SubModID = getGlobalSubmoduleID(*PMInfo.M, ID >> 1);
Info.MI = nullptr;
+
+ // If we've already loaded the #undef of this macro from this module,
+ // don't do so again.
+ if (!LoadedUndefs.insert(std::make_pair(II, Info.SubModID)).second)
+ return nullptr;
} else {
// Macro definition.
GlobalMacroID GMacID = getGlobalMacroID(*PMInfo.M, ID >> 1);
@@ -1848,7 +1853,7 @@
// Module Macro.
- ModuleMacroInfo *MMI = getModuleMacro(PMInfo);
+ ModuleMacroInfo *MMI = getModuleMacro(II, PMInfo);
if (!MMI)
return;
@@ -1945,15 +1950,13 @@
Module *PrevOwner = nullptr;
if (SubmoduleID PrevModID = PrevMI->getOwningModuleID())
PrevOwner = Reader.getSubmodule(PrevModID);
- SourceManager &SrcMgr = Reader.getSourceManager();
- bool PrevInSystem
- = PrevOwner? PrevOwner->IsSystem
- : SrcMgr.isInSystemHeader(PrevMI->getDefinitionLoc());
- bool NewInSystem
- = NewOwner? NewOwner->IsSystem
- : SrcMgr.isInSystemHeader(NewMI->getDefinitionLoc());
if (PrevOwner && PrevOwner == NewOwner)
return false;
+ SourceManager &SrcMgr = Reader.getSourceManager();
+ bool PrevInSystem = (PrevOwner && PrevOwner->IsSystem) ||
+ SrcMgr.isInSystemHeader(PrevMI->getDefinitionLoc());
+ bool NewInSystem = (NewOwner && NewOwner->IsSystem) ||
+ SrcMgr.isInSystemHeader(NewMI->getDefinitionLoc());
return PrevInSystem && NewInSystem;
}
@@ -2459,6 +2462,9 @@
break;
}
+ case KNOWN_MODULE_FILES:
+ break;
+
case LANGUAGE_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
// FIXME: The &F == *ModuleMgr.begin() check is wrong for modules.
@@ -2473,7 +2479,8 @@
case TARGET_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
- ParseTargetOptions(Record, Complain, *Listener) &&
+ ParseTargetOptions(Record, Complain, *Listener,
+ AllowCompatibleConfigurationMismatch) &&
!DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
@@ -2828,6 +2835,8 @@
}
case EAGERLY_DESERIALIZED_DECLS:
+ // FIXME: Skip reading this record if our ASTConsumer doesn't care
+ // about "interesting" decls (for instance, if we're building a module).
for (unsigned I = 0, N = Record.size(); I != N; ++I)
EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
@@ -2892,11 +2901,6 @@
}
break;
- case LOCALLY_SCOPED_EXTERN_C_DECLS:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- LocallyScopedExternCDecls.push_back(getGlobalDeclID(F, Record[I]));
- break;
-
case SELECTOR_OFFSETS: {
F.SelectorOffsets = (const uint32_t *)Blob.data();
F.LocalNumSelectors = Record[0];
@@ -3099,11 +3103,6 @@
}
break;
- case DYNAMIC_CLASSES:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- DynamicClasses.push_back(getGlobalDeclID(F, Record[I]));
- break;
-
case PENDING_IMPLICIT_INSTANTIATIONS:
if (PendingInstantiations.size() % 2 != 0) {
Error("Invalid existing PendingInstantiations");
@@ -3205,16 +3204,26 @@
case OBJC_CATEGORIES:
F.ObjCCategories.swap(Record);
break;
-
+
case CXX_BASE_SPECIFIER_OFFSETS: {
if (F.LocalNumCXXBaseSpecifiers != 0) {
Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
return Failure;
}
-
+
F.LocalNumCXXBaseSpecifiers = Record[0];
F.CXXBaseSpecifiersOffsets = (const uint32_t *)Blob.data();
- NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers;
+ break;
+ }
+
+ case CXX_CTOR_INITIALIZERS_OFFSETS: {
+ if (F.LocalNumCXXCtorInitializers != 0) {
+ Error("duplicate CXX_CTOR_INITIALIZERS_OFFSETS record in AST file");
+ return Failure;
+ }
+
+ F.LocalNumCXXCtorInitializers = Record[0];
+ F.CXXCtorInitializersOffsets = (const uint32_t *)Blob.data();
break;
}
@@ -3321,16 +3330,6 @@
break;
}
- case MERGED_DECLARATIONS: {
- for (unsigned Idx = 0; Idx < Record.size(); /* increment in loop */) {
- GlobalDeclID CanonID = getGlobalDeclID(F, Record[Idx++]);
- SmallVectorImpl<GlobalDeclID> &Decls = StoredMergedDecls[CanonID];
- for (unsigned N = Record[Idx++]; N > 0; --N)
- Decls.push_back(getGlobalDeclID(F, Record[Idx++]));
- }
- break;
- }
-
case MACRO_OFFSET: {
if (F.LocalNumMacros != 0) {
Error("duplicate MACRO_OFFSET record in AST file");
@@ -3818,6 +3817,14 @@
static ASTFileSignature readASTFileSignature(llvm::BitstreamReader &StreamFile);
+/// \brief Whether \p Stream starts with the AST/PCH file magic number 'CPCH'.
+static bool startsWithASTFileMagic(BitstreamCursor &Stream) {
+ return Stream.Read(8) == 'C' &&
+ Stream.Read(8) == 'P' &&
+ Stream.Read(8) == 'C' &&
+ Stream.Read(8) == 'H';
+}
+
ASTReader::ASTReadResult
ASTReader::ReadASTCore(StringRef FileName,
ModuleKind Type,
@@ -3887,10 +3894,7 @@
F.SizeInBits = F.Buffer->getBufferSize() * 8;
// Sniff for the signature.
- if (Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'P' ||
- Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'H') {
+ if (!startsWithASTFileMagic(Stream)) {
Diag(diag::err_not_a_pch_file) << FileName;
return Failure;
}
@@ -4130,14 +4134,12 @@
}
}
+/// \brief Reads and return the signature record from \p StreamFile's control
+/// block, or else returns 0.
static ASTFileSignature readASTFileSignature(llvm::BitstreamReader &StreamFile){
BitstreamCursor Stream(StreamFile);
- if (Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'P' ||
- Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'H') {
+ if (!startsWithASTFileMagic(Stream))
return 0;
- }
// Scan for the CONTROL_BLOCK_ID block.
if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID))
@@ -4179,10 +4181,7 @@
BitstreamCursor Stream(StreamFile);
// Sniff for the signature.
- if (Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'P' ||
- Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'H') {
+ if (!startsWithASTFileMagic(Stream)) {
Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName;
return std::string();
}
@@ -4239,9 +4238,10 @@
return checkLanguageOptions(ExistingLangOpts, LangOpts, nullptr,
AllowCompatibleDifferences);
}
- bool ReadTargetOptions(const TargetOptions &TargetOpts,
- bool Complain) override {
- return checkTargetOptions(ExistingTargetOpts, TargetOpts, nullptr);
+ bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain,
+ bool AllowCompatibleDifferences) override {
+ return checkTargetOptions(ExistingTargetOpts, TargetOpts, nullptr,
+ AllowCompatibleDifferences);
}
bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
StringRef SpecificModuleCachePath,
@@ -4263,6 +4263,8 @@
FileManager &FileMgr,
ASTReaderListener &Listener) {
// Open the AST file.
+ // FIXME: This allows use of the VFS; we do not allow use of the
+ // VFS when actually loading a module.
auto Buffer = FileMgr.getBufferForFile(Filename);
if (!Buffer) {
return true;
@@ -4275,12 +4277,8 @@
BitstreamCursor Stream(StreamFile);
// Sniff for the signature.
- if (Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'P' ||
- Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'H') {
+ if (!startsWithASTFileMagic(Stream))
return true;
- }
// Scan for the CONTROL_BLOCK_ID block.
if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID))
@@ -4353,7 +4351,8 @@
break;
case TARGET_OPTIONS:
- if (ParseTargetOptions(Record, false, Listener))
+ if (ParseTargetOptions(Record, false, Listener,
+ /*AllowCompatibleConfigurationMismatch*/ false))
return true;
break;
@@ -4432,6 +4431,20 @@
break;
}
+ case KNOWN_MODULE_FILES: {
+ // Known-but-not-technically-used module files are treated as imports.
+ if (!NeedsImports)
+ break;
+
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ std::string Filename = ReadString(Record, Idx);
+ ResolveImportedPath(Filename, ModuleDir);
+ Listener.visitImport(Filename);
+ }
+ break;
+ }
+
default:
// No other validation to perform.
break;
@@ -4745,9 +4758,9 @@
AllowCompatibleDifferences);
}
-bool ASTReader::ParseTargetOptions(const RecordData &Record,
- bool Complain,
- ASTReaderListener &Listener) {
+bool ASTReader::ParseTargetOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener,
+ bool AllowCompatibleDifferences) {
unsigned Idx = 0;
TargetOptions TargetOpts;
TargetOpts.Triple = ReadString(Record, Idx);
@@ -4760,7 +4773,8 @@
TargetOpts.Features.push_back(ReadString(Record, Idx));
}
- return Listener.ReadTargetOptions(TargetOpts, Complain);
+ return Listener.ReadTargetOptions(TargetOpts, Complain,
+ AllowCompatibleDifferences);
}
bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain,
@@ -6183,6 +6197,38 @@
}
}
+uint64_t ASTReader::ReadCXXCtorInitializersRef(ModuleFile &M,
+ const RecordData &Record,
+ unsigned &Idx) {
+ if (Idx >= Record.size() || Record[Idx] > M.LocalNumCXXCtorInitializers) {
+ Error("malformed AST file: missing C++ ctor initializers");
+ return 0;
+ }
+
+ unsigned LocalID = Record[Idx++];
+ return getGlobalBitOffset(M, M.CXXCtorInitializersOffsets[LocalID - 1]);
+}
+
+CXXCtorInitializer **
+ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) {
+ RecordLocation Loc = getLocalBitOffset(Offset);
+ BitstreamCursor &Cursor = Loc.F->DeclsCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(Loc.Offset);
+ ReadingKindTracker ReadingKind(Read_Decl, *this);
+
+ RecordData Record;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.readRecord(Code, Record);
+ if (RecCode != DECL_CXX_CTOR_INITIALIZERS) {
+ Error("malformed AST file: missing C++ ctor initializers");
+ return nullptr;
+ }
+
+ unsigned Idx = 0;
+ return ReadCXXCtorInitializers(*Loc.F, Record, Idx);
+}
+
uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M,
const RecordData &Record,
unsigned &Idx) {
@@ -6232,6 +6278,10 @@
bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID,
ModuleFile &M) const {
+ // Predefined decls aren't from any module.
+ if (ID < NUM_PREDEF_DECL_IDS)
+ return false;
+
GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID);
assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
return &M == I->second;
@@ -6264,39 +6314,55 @@
return ReadSourceLocation(*Rec.F, RawLocation);
}
+static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
+ switch (ID) {
+ case PREDEF_DECL_NULL_ID:
+ return nullptr;
+
+ case PREDEF_DECL_TRANSLATION_UNIT_ID:
+ return Context.getTranslationUnitDecl();
+
+ case PREDEF_DECL_OBJC_ID_ID:
+ return Context.getObjCIdDecl();
+
+ case PREDEF_DECL_OBJC_SEL_ID:
+ return Context.getObjCSelDecl();
+
+ case PREDEF_DECL_OBJC_CLASS_ID:
+ return Context.getObjCClassDecl();
+
+ case PREDEF_DECL_OBJC_PROTOCOL_ID:
+ return Context.getObjCProtocolDecl();
+
+ case PREDEF_DECL_INT_128_ID:
+ return Context.getInt128Decl();
+
+ case PREDEF_DECL_UNSIGNED_INT_128_ID:
+ return Context.getUInt128Decl();
+
+ case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
+ return Context.getObjCInstanceTypeDecl();
+
+ case PREDEF_DECL_BUILTIN_VA_LIST_ID:
+ return Context.getBuiltinVaListDecl();
+
+ case PREDEF_DECL_EXTERN_C_CONTEXT_ID:
+ return Context.getExternCContextDecl();
+ }
+ llvm_unreachable("PredefinedDeclIDs unknown enum value");
+}
+
Decl *ASTReader::GetExistingDecl(DeclID ID) {
if (ID < NUM_PREDEF_DECL_IDS) {
- switch ((PredefinedDeclIDs)ID) {
- case PREDEF_DECL_NULL_ID:
- return nullptr;
-
- case PREDEF_DECL_TRANSLATION_UNIT_ID:
- return Context.getTranslationUnitDecl();
-
- case PREDEF_DECL_OBJC_ID_ID:
- return Context.getObjCIdDecl();
-
- case PREDEF_DECL_OBJC_SEL_ID:
- return Context.getObjCSelDecl();
-
- case PREDEF_DECL_OBJC_CLASS_ID:
- return Context.getObjCClassDecl();
-
- case PREDEF_DECL_OBJC_PROTOCOL_ID:
- return Context.getObjCProtocolDecl();
-
- case PREDEF_DECL_INT_128_ID:
- return Context.getInt128Decl();
-
- case PREDEF_DECL_UNSIGNED_INT_128_ID:
- return Context.getUInt128Decl();
-
- case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
- return Context.getObjCInstanceTypeDecl();
-
- case PREDEF_DECL_BUILTIN_VA_LIST_ID:
- return Context.getBuiltinVaListDecl();
+ Decl *D = getPredefinedDecl(Context, (PredefinedDeclIDs)ID);
+ if (D) {
+ // Track that we have merged the declaration with ID \p ID into the
+ // pre-existing predefined declaration \p D.
+ auto &Merged = MergedDecls[D->getCanonicalDecl()];
+ if (Merged.empty())
+ Merged.push_back(ID);
}
+ return D;
}
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
@@ -6806,6 +6872,12 @@
SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
true);
+ // Ensure that we've loaded all potentially-interesting declarations
+ // that need to be eagerly loaded.
+ for (auto ID : EagerlyDeserializedDecls)
+ GetDecl(ID);
+ EagerlyDeserializedDecls.clear();
+
while (!InterestingDecls.empty()) {
Decl *D = InterestingDecls.front();
InterestingDecls.pop_front();
@@ -6824,17 +6896,11 @@
void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
this->Consumer = Consumer;
- if (!Consumer)
- return;
+ if (Consumer)
+ PassInterestingDeclsToConsumer();
- for (unsigned I = 0, N = EagerlyDeserializedDecls.size(); I != N; ++I) {
- // Force deserialization of this decl, which will cause it to be queued for
- // passing to the consumer.
- GetDecl(EagerlyDeserializedDecls[I]);
- }
- EagerlyDeserializedDecls.clear();
-
- PassInterestingDeclsToConsumer();
+ if (DeserializationListener)
+ DeserializationListener->ReaderInitialized(this);
}
void ASTReader::PrintStats() {
@@ -7312,16 +7378,6 @@
ExtVectorDecls.clear();
}
-void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) {
- for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) {
- CXXRecordDecl *D
- = dyn_cast_or_null<CXXRecordDecl>(GetDecl(DynamicClasses[I]));
- if (D)
- Decls.push_back(D);
- }
- DynamicClasses.clear();
-}
-
void ASTReader::ReadUnusedLocalTypedefNameCandidates(
llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {
for (unsigned I = 0, N = UnusedLocalTypedefNameCandidates.size(); I != N;
@@ -7334,17 +7390,6 @@
UnusedLocalTypedefNameCandidates.clear();
}
-void
-ASTReader::ReadLocallyScopedExternCDecls(SmallVectorImpl<NamedDecl *> &Decls) {
- for (unsigned I = 0, N = LocallyScopedExternCDecls.size(); I != N; ++I) {
- NamedDecl *D
- = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternCDecls[I]));
- if (D)
- Decls.push_back(D);
- }
- LocallyScopedExternCDecls.clear();
-}
-
void ASTReader::ReadReferencedSelectors(
SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {
if (ReferencedSelectorsData.empty())
@@ -7408,7 +7453,7 @@
}
void ASTReader::ReadLateParsedTemplates(
- llvm::DenseMap<const FunctionDecl *, LateParsedTemplate *> &LPTMap) {
+ llvm::MapVector<const FunctionDecl *, LateParsedTemplate *> &LPTMap) {
for (unsigned Idx = 0, N = LateParsedTemplates.size(); Idx < N;
/* In loop */) {
FunctionDecl *FD = cast<FunctionDecl>(GetDecl(LateParsedTemplates[Idx++]));
@@ -7424,7 +7469,7 @@
for (unsigned T = 0; T < TokN; ++T)
LT->Toks.push_back(ReadToken(*F, LateParsedTemplates, Idx));
- LPTMap[FD] = LT;
+ LPTMap.insert(std::make_pair(FD, LT));
}
LateParsedTemplates.clear();
@@ -7915,92 +7960,89 @@
return Result;
}
-std::pair<CXXCtorInitializer **, unsigned>
+CXXCtorInitializer **
ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
- CXXCtorInitializer **CtorInitializers = nullptr;
unsigned NumInitializers = Record[Idx++];
- if (NumInitializers) {
- CtorInitializers
- = new (Context) CXXCtorInitializer*[NumInitializers];
- for (unsigned i=0; i != NumInitializers; ++i) {
- TypeSourceInfo *TInfo = nullptr;
- bool IsBaseVirtual = false;
- FieldDecl *Member = nullptr;
- IndirectFieldDecl *IndirectMember = nullptr;
+ assert(NumInitializers && "wrote ctor initializers but have no inits");
+ auto **CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers];
+ for (unsigned i = 0; i != NumInitializers; ++i) {
+ TypeSourceInfo *TInfo = nullptr;
+ bool IsBaseVirtual = false;
+ FieldDecl *Member = nullptr;
+ IndirectFieldDecl *IndirectMember = nullptr;
- CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
- switch (Type) {
- case CTOR_INITIALIZER_BASE:
- TInfo = GetTypeSourceInfo(F, Record, Idx);
- IsBaseVirtual = Record[Idx++];
- break;
-
- case CTOR_INITIALIZER_DELEGATING:
- TInfo = GetTypeSourceInfo(F, Record, Idx);
- break;
+ CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
+ switch (Type) {
+ case CTOR_INITIALIZER_BASE:
+ TInfo = GetTypeSourceInfo(F, Record, Idx);
+ IsBaseVirtual = Record[Idx++];
+ break;
- case CTOR_INITIALIZER_MEMBER:
- Member = ReadDeclAs<FieldDecl>(F, Record, Idx);
- break;
+ case CTOR_INITIALIZER_DELEGATING:
+ TInfo = GetTypeSourceInfo(F, Record, Idx);
+ break;
- case CTOR_INITIALIZER_INDIRECT_MEMBER:
- IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx);
- break;
- }
+ case CTOR_INITIALIZER_MEMBER:
+ Member = ReadDeclAs<FieldDecl>(F, Record, Idx);
+ break;
- SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
- Expr *Init = ReadExpr(F);
- SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
- SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
- bool IsWritten = Record[Idx++];
- unsigned SourceOrderOrNumArrayIndices;
- SmallVector<VarDecl *, 8> Indices;
- if (IsWritten) {
- SourceOrderOrNumArrayIndices = Record[Idx++];
- } else {
- SourceOrderOrNumArrayIndices = Record[Idx++];
- Indices.reserve(SourceOrderOrNumArrayIndices);
- for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i)
- Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx));
- }
-
- CXXCtorInitializer *BOMInit;
- if (Type == CTOR_INITIALIZER_BASE) {
- BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, IsBaseVirtual,
- LParenLoc, Init, RParenLoc,
- MemberOrEllipsisLoc);
- } else if (Type == CTOR_INITIALIZER_DELEGATING) {
- BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, LParenLoc,
- Init, RParenLoc);
- } else if (IsWritten) {
- if (Member)
- BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc,
- LParenLoc, Init, RParenLoc);
- else
- BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember,
- MemberOrEllipsisLoc, LParenLoc,
- Init, RParenLoc);
- } else {
- if (IndirectMember) {
- assert(Indices.empty() && "Indirect field improperly initialized");
- BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember,
- MemberOrEllipsisLoc, LParenLoc,
- Init, RParenLoc);
- } else {
- BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc,
- LParenLoc, Init, RParenLoc,
- Indices.data(), Indices.size());
- }
- }
-
- if (IsWritten)
- BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices);
- CtorInitializers[i] = BOMInit;
+ case CTOR_INITIALIZER_INDIRECT_MEMBER:
+ IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx);
+ break;
}
+
+ SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
+ Expr *Init = ReadExpr(F);
+ SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
+ SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
+ bool IsWritten = Record[Idx++];
+ unsigned SourceOrderOrNumArrayIndices;
+ SmallVector<VarDecl *, 8> Indices;
+ if (IsWritten) {
+ SourceOrderOrNumArrayIndices = Record[Idx++];
+ } else {
+ SourceOrderOrNumArrayIndices = Record[Idx++];
+ Indices.reserve(SourceOrderOrNumArrayIndices);
+ for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i)
+ Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx));
+ }
+
+ CXXCtorInitializer *BOMInit;
+ if (Type == CTOR_INITIALIZER_BASE) {
+ BOMInit = new (Context)
+ CXXCtorInitializer(Context, TInfo, IsBaseVirtual, LParenLoc, Init,
+ RParenLoc, MemberOrEllipsisLoc);
+ } else if (Type == CTOR_INITIALIZER_DELEGATING) {
+ BOMInit = new (Context)
+ CXXCtorInitializer(Context, TInfo, LParenLoc, Init, RParenLoc);
+ } else if (IsWritten) {
+ if (Member)
+ BOMInit = new (Context) CXXCtorInitializer(
+ Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc);
+ else
+ BOMInit = new (Context)
+ CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc,
+ LParenLoc, Init, RParenLoc);
+ } else {
+ if (IndirectMember) {
+ assert(Indices.empty() && "Indirect field improperly initialized");
+ BOMInit = new (Context)
+ CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc,
+ LParenLoc, Init, RParenLoc);
+ } else {
+ BOMInit = CXXCtorInitializer::Create(
+ Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc,
+ Indices.data(), Indices.size());
+ }
+ }
+
+ if (IsWritten)
+ BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices);
+ CtorInitializers[i] = BOMInit;
}
- return std::make_pair(CtorInitializers, NumInitializers);
+ return CtorInitializers;
}
NestedNameSpecifier *
@@ -8318,9 +8360,10 @@
// Load pending declaration chains.
for (unsigned I = 0; I != PendingDeclChains.size(); ++I) {
- loadPendingDeclChain(PendingDeclChains[I]);
PendingDeclChainsKnown.erase(PendingDeclChains[I]);
+ loadPendingDeclChain(PendingDeclChains[I]);
}
+ assert(PendingDeclChainsKnown.empty());
PendingDeclChains.clear();
// Make the most recent of the top-level declarations visible.
@@ -8389,10 +8432,12 @@
// Make sure that the TagType points at the definition.
const_cast<TagType*>(TagT)->decl = TD;
}
-
+
if (auto RD = dyn_cast<CXXRecordDecl>(D)) {
- for (auto R : RD->redecls()) {
- assert((R == D) == R->isThisDeclarationADefinition() &&
+ for (auto *R = getMostRecentExistingDecl(RD); R;
+ R = R->getPreviousDecl()) {
+ assert((R == D) ==
+ cast<CXXRecordDecl>(R)->isThisDeclarationADefinition() &&
"declaration thinks it's the definition but it isn't");
cast<CXXRecordDecl>(R)->DefinitionData = RD->DefinitionData;
}
@@ -8400,34 +8445,36 @@
continue;
}
-
+
if (auto ID = dyn_cast<ObjCInterfaceDecl>(D)) {
// Make sure that the ObjCInterfaceType points at the definition.
const_cast<ObjCInterfaceType *>(cast<ObjCInterfaceType>(ID->TypeForDecl))
->Decl = ID;
-
- for (auto R : ID->redecls())
- R->Data = ID->Data;
-
+
+ for (auto *R = getMostRecentExistingDecl(ID); R; R = R->getPreviousDecl())
+ cast<ObjCInterfaceDecl>(R)->Data = ID->Data;
+
continue;
}
-
+
if (auto PD = dyn_cast<ObjCProtocolDecl>(D)) {
- for (auto R : PD->redecls())
- R->Data = PD->Data;
-
+ for (auto *R = getMostRecentExistingDecl(PD); R; R = R->getPreviousDecl())
+ cast<ObjCProtocolDecl>(R)->Data = PD->Data;
+
continue;
}
-
+
auto RTD = cast<RedeclarableTemplateDecl>(D)->getCanonicalDecl();
- for (auto R : RTD->redecls())
- R->Common = RTD->Common;
+ for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl())
+ cast<RedeclarableTemplateDecl>(R)->Common = RTD->Common;
}
PendingDefinitions.clear();
// Load the bodies of any functions or methods we've encountered. We do
// this now (delayed) so that we can be sure that the declaration chains
// have been fully wired up.
+ // FIXME: There seems to be no point in delaying this, it does not depend
+ // on the redecl chains having been wired up.
for (PendingBodiesMap::iterator PB = PendingBodies.begin(),
PBEnd = PendingBodies.end();
PB != PBEnd; ++PB) {
@@ -8605,6 +8652,17 @@
--NumCurrentElementsDeserializing;
if (NumCurrentElementsDeserializing == 0) {
+ // Propagate exception specification updates along redeclaration chains.
+ while (!PendingExceptionSpecUpdates.empty()) {
+ auto Updates = std::move(PendingExceptionSpecUpdates);
+ PendingExceptionSpecUpdates.clear();
+ for (auto Update : Updates) {
+ auto *FPT = Update.second->getType()->castAs<FunctionProtoType>();
+ SemaObj->UpdateExceptionSpec(Update.second,
+ FPT->getExtProtoInfo().ExceptionSpec);
+ }
+ }
+
diagnoseOdrViolations();
// We are not in recursive loading, so it's safe to pass the "interesting"
@@ -8615,7 +8673,15 @@
}
void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
- D = D->getMostRecentDecl();
+ if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
+ // Remove any fake results before adding any real ones.
+ auto It = PendingFakeLookupResults.find(II);
+ if (It != PendingFakeLookupResults.end()) {
+ for (auto *ND : PendingFakeLookupResults[II])
+ SemaObj->IdResolver.RemoveDecl(ND);
+ PendingFakeLookupResults.erase(It);
+ }
+ }
if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) {
SemaObj->TUScope->AddDecl(D);
@@ -8653,8 +8719,7 @@
NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0),
NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
- PassingDeclsToConsumer(false), NumCXXBaseSpecifiersLoaded(0),
- ReadingKind(Read_None) {
+ PassingDeclsToConsumer(false), ReadingKind(Read_None) {
SourceMgr.setExternalSLocEntrySource(this);
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 339d0b8..de2c625 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -66,7 +66,12 @@
serialization::DeclID ReadDeclID(const RecordData &R, unsigned &I) {
return Reader.ReadDeclID(F, R, I);
}
-
+
+ void ReadDeclIDList(SmallVectorImpl<DeclID> &IDs) {
+ for (unsigned I = 0, Size = Record[Idx++]; I != Size; ++I)
+ IDs.push_back(ReadDeclID(Record, Idx));
+ }
+
Decl *ReadDecl(const RecordData &R, unsigned &I) {
return Reader.ReadDecl(F, R, I);
}
@@ -118,9 +123,6 @@
/// \brief RAII class used to capture the first ID within a redeclaration
/// chain and to introduce it into the list of pending redeclaration chains
/// on destruction.
- ///
- /// The caller can choose not to introduce this ID into the list of pending
- /// redeclaration chains by calling \c suppress().
class RedeclarableResult {
ASTReader &Reader;
GlobalDeclID FirstID;
@@ -144,9 +146,11 @@
}
~RedeclarableResult() {
- if (FirstID && Owning && isRedeclarableDeclKind(DeclKind) &&
- Reader.PendingDeclChainsKnown.insert(FirstID).second)
- Reader.PendingDeclChains.push_back(FirstID);
+ if (FirstID && Owning && isRedeclarableDeclKind(DeclKind)) {
+ auto Canon = Reader.GetDecl(FirstID)->getCanonicalDecl();
+ if (Reader.PendingDeclChainsKnown.insert(Canon).second)
+ Reader.PendingDeclChains.push_back(Canon);
+ }
}
/// \brief Retrieve the first ID.
@@ -155,12 +159,6 @@
/// \brief Get a known declaration that this should be merged with, if
/// any.
Decl *getKnownMergeTarget() const { return MergeWith; }
-
- /// \brief Do not introduce this declaration ID into the set of pending
- /// declaration chains.
- void suppress() {
- Owning = false;
- }
};
/// \brief Class used to capture the result of searching for an existing
@@ -224,10 +222,17 @@
TypedefNameForLinkage(nullptr), HasPendingBody(false) {}
template <typename DeclT>
+ static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D);
+ static Decl *getMostRecentDeclImpl(...);
+ static Decl *getMostRecentDecl(Decl *D);
+
+ template <typename DeclT>
static void attachPreviousDeclImpl(ASTReader &Reader,
- Redeclarable<DeclT> *D, Decl *Previous);
+ Redeclarable<DeclT> *D, Decl *Previous,
+ Decl *Canon);
static void attachPreviousDeclImpl(ASTReader &Reader, ...);
- static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous);
+ static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous,
+ Decl *Canon);
template <typename DeclT>
static void attachLatestDeclImpl(Redeclarable<DeclT> *D, Decl *Latest);
@@ -398,9 +403,14 @@
// FunctionDecl's body was written last after all other Stmts/Exprs.
// We only read it if FD doesn't already have a body (e.g., from another
// module).
- // FIXME: Also consider = default and = delete.
// FIXME: Can we diagnose ODR violations somehow?
if (Record[Idx++]) {
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ CD->NumCtorInitializers = Record[Idx++];
+ if (CD->NumCtorInitializers)
+ CD->CtorInitializers =
+ Reader.ReadCXXCtorInitializersRef(F, Record, Idx);
+ }
Reader.PendingBodies[FD] = GetCurrentCursorOffset();
HasPendingBody = true;
}
@@ -988,8 +998,9 @@
D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx));
D->setHasNonZeroConstructors(Record[Idx++]);
D->setHasDestructors(Record[Idx++]);
- std::tie(D->IvarInitializers, D->NumIvarInitializers) =
- Reader.ReadCXXCtorInitializers(F, Record, Idx);
+ D->NumIvarInitializers = Record[Idx++];
+ if (D->NumIvarInitializers)
+ D->IvarInitializers = Reader.ReadCXXCtorInitializersRef(F, Record, Idx);
}
@@ -1196,13 +1207,13 @@
D->LocStart = ReadSourceLocation(Record, Idx);
D->RBraceLoc = ReadSourceLocation(Record, Idx);
+ // Defer loading the anonymous namespace until we've finished merging
+ // this namespace; loading it might load a later declaration of the
+ // same namespace, and we have an invariant that older declarations
+ // get merged before newer ones try to merge.
+ GlobalDeclID AnonNamespace = 0;
if (Redecl.getFirstID() == ThisDeclID) {
- // Each module has its own anonymous namespace, which is disjoint from
- // any other module's anonymous namespaces, so don't attach the anonymous
- // namespace at all.
- NamespaceDecl *Anon = ReadDeclAs<NamespaceDecl>(Record, Idx);
- if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule)
- D->setAnonymousNamespace(Anon);
+ AnonNamespace = ReadDeclID(Record, Idx);
} else {
// Link this namespace back to the first declaration, which has already
// been deserialized.
@@ -1210,6 +1221,15 @@
}
mergeRedeclarable(D, Redecl);
+
+ if (AnonNamespace) {
+ // Each module has its own anonymous namespace, which is disjoint from
+ // any other module's anonymous namespaces, so don't attach the anonymous
+ // namespace at all.
+ NamespaceDecl *Anon = cast<NamespaceDecl>(Reader.GetDecl(AnonNamespace));
+ if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule)
+ D->setAnonymousNamespace(Anon);
+ }
}
void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
@@ -1393,8 +1413,6 @@
}
// FIXME: Move this out into a .def file?
- // FIXME: Issue a diagnostic on a mismatched MATCH_FIELD, rather than
- // asserting; this can happen in the case of an ODR violation.
bool DetectedOdrViolation = false;
#define OR_FIELD(Field) DD.Field |= MergeDD.Field;
#define MATCH_FIELD(Field) \
@@ -1609,17 +1627,20 @@
VisitCXXMethodDecl(D);
if (auto *CD = ReadDeclAs<CXXConstructorDecl>(Record, Idx))
- D->setInheritedConstructor(CD);
+ if (D->isCanonicalDecl())
+ D->setInheritedConstructor(CD->getCanonicalDecl());
D->IsExplicitSpecified = Record[Idx++];
- // FIXME: We should defer loading this until we need the constructor's body.
- std::tie(D->CtorInitializers, D->NumCtorInitializers) =
- Reader.ReadCXXCtorInitializers(F, Record, Idx);
}
void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
VisitCXXMethodDecl(D);
- D->OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx);
+ if (auto *OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx)) {
+ auto *Canon = cast<CXXDestructorDecl>(D->getCanonicalDecl());
+ // FIXME: Check consistency if we have an old and new operator delete.
+ if (!Canon->OperatorDelete)
+ Canon->OperatorDelete = OperatorDelete;
+ }
}
void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
@@ -1723,36 +1744,34 @@
return Redecl;
}
+static DeclID *newDeclIDList(ASTContext &Context, DeclID *Old,
+ SmallVectorImpl<DeclID> &IDs) {
+ assert(!IDs.empty() && "no IDs to add to list");
+ if (Old) {
+ IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]);
+ std::sort(IDs.begin(), IDs.end());
+ IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
+ }
+
+ auto *Result = new (Context) DeclID[1 + IDs.size()];
+ *Result = IDs.size();
+ std::copy(IDs.begin(), IDs.end(), Result + 1);
+ return Result;
+}
+
void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
if (ThisDeclID == Redecl.getFirstID()) {
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
- SmallVector<serialization::DeclID, 2> SpecIDs;
- SpecIDs.push_back(0);
-
- // Specializations.
- unsigned Size = Record[Idx++];
- SpecIDs[0] += Size;
- for (unsigned I = 0; I != Size; ++I)
- SpecIDs.push_back(ReadDeclID(Record, Idx));
+ SmallVector<serialization::DeclID, 32> SpecIDs;
+ ReadDeclIDList(SpecIDs);
- // Partial specializations.
- Size = Record[Idx++];
- SpecIDs[0] += Size;
- for (unsigned I = 0; I != Size; ++I)
- SpecIDs.push_back(ReadDeclID(Record, Idx));
-
- ClassTemplateDecl::Common *CommonPtr = D->getCommonPtr();
- if (SpecIDs[0]) {
- typedef serialization::DeclID DeclID;
-
- // FIXME: Append specializations!
- CommonPtr->LazySpecializations
- = new (Reader.getContext()) DeclID [SpecIDs.size()];
- memcpy(CommonPtr->LazySpecializations, SpecIDs.data(),
- SpecIDs.size() * sizeof(DeclID));
+ if (!SpecIDs.empty()) {
+ auto *CommonPtr = D->getCommonPtr();
+ CommonPtr->LazySpecializations = newDeclIDList(
+ Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
}
}
@@ -1774,30 +1793,13 @@
if (ThisDeclID == Redecl.getFirstID()) {
// This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
- SmallVector<serialization::DeclID, 2> SpecIDs;
- SpecIDs.push_back(0);
+ SmallVector<serialization::DeclID, 32> SpecIDs;
+ ReadDeclIDList(SpecIDs);
- // Specializations.
- unsigned Size = Record[Idx++];
- SpecIDs[0] += Size;
- for (unsigned I = 0; I != Size; ++I)
- SpecIDs.push_back(ReadDeclID(Record, Idx));
-
- // Partial specializations.
- Size = Record[Idx++];
- SpecIDs[0] += Size;
- for (unsigned I = 0; I != Size; ++I)
- SpecIDs.push_back(ReadDeclID(Record, Idx));
-
- VarTemplateDecl::Common *CommonPtr = D->getCommonPtr();
- if (SpecIDs[0]) {
- typedef serialization::DeclID DeclID;
-
- // FIXME: Append specializations!
- CommonPtr->LazySpecializations =
- new (Reader.getContext()) DeclID[SpecIDs.size()];
- memcpy(CommonPtr->LazySpecializations, SpecIDs.data(),
- SpecIDs.size() * sizeof(DeclID));
+ if (!SpecIDs.empty()) {
+ auto *CommonPtr = D->getCommonPtr();
+ CommonPtr->LazySpecializations = newDeclIDList(
+ Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
}
}
}
@@ -1909,17 +1911,13 @@
if (ThisDeclID == Redecl.getFirstID()) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
+ SmallVector<serialization::DeclID, 32> SpecIDs;
+ ReadDeclIDList(SpecIDs);
- // Read the function specialization declaration IDs. The specializations
- // themselves will be loaded if they're needed.
- if (unsigned NumSpecs = Record[Idx++]) {
- // FIXME: Append specializations!
- FunctionTemplateDecl::Common *CommonPtr = D->getCommonPtr();
- CommonPtr->LazySpecializations = new (Reader.getContext())
- serialization::DeclID[NumSpecs + 1];
- CommonPtr->LazySpecializations[0] = NumSpecs;
- for (unsigned I = 0; I != NumSpecs; ++I)
- CommonPtr->LazySpecializations[I + 1] = ReadDeclID(Record, Idx);
+ if (!SpecIDs.empty()) {
+ auto *CommonPtr = D->getCommonPtr();
+ CommonPtr->LazySpecializations = newDeclIDList(
+ Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
}
}
}
@@ -2091,12 +2089,14 @@
// and is used for space optimization.
if (FirstDeclID == 0)
FirstDeclID = ThisDeclID;
- else if (Record[Idx++]) {
- // We need to merge with FirstDeclID. Read it now to ensure that it is
- // before us in the redecl chain, then forget we saw it so that we will
- // merge with it.
- MergeWith = Reader.GetDecl(FirstDeclID);
- FirstDeclID = ThisDeclID;
+ else if (unsigned N = Record[Idx++]) {
+ // We have some declarations that must be before us in our redeclaration
+ // chain. Read them now, and remember that we ought to merge with one of
+ // them.
+ // FIXME: Provide a known merge target to the second and subsequent such
+ // declaration.
+ for (unsigned I = 0; I != N; ++I)
+ MergeWith = ReadDecl(Record, Idx/*, MergeWith*/);
}
T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
@@ -2106,6 +2106,7 @@
// which is the one that matters and mark the real previous DeclID to be
// loaded & attached later on.
D->RedeclLink = Redeclarable<T>::PreviousDeclLink(FirstDecl);
+ D->First = FirstDecl->getCanonicalDecl();
}
// Note that this declaration has been deserialized.
@@ -2124,22 +2125,15 @@
RedeclarableResult &Redecl,
DeclID TemplatePatternID) {
T *D = static_cast<T*>(DBase);
- T *DCanon = D->getCanonicalDecl();
- if (D != DCanon &&
- // IDs < NUM_PREDEF_DECL_IDS are not loaded from an AST file.
- Redecl.getFirstID() >= NUM_PREDEF_DECL_IDS &&
- (!Reader.getContext().getLangOpts().Modules ||
- Reader.getOwningModuleFile(DCanon) == Reader.getOwningModuleFile(D))) {
- // All redeclarations between this declaration and its originally-canonical
- // declaration get pulled in when we load DCanon; we don't need to
- // perform any more merging now.
- Redecl.suppress();
- }
// If modules are not available, there is no reason to perform this merge.
if (!Reader.getContext().getLangOpts().Modules)
return;
+ // If we're not the canonical declaration, we don't need to merge.
+ if (!DBase->isFirstDecl())
+ return;
+
if (auto *Existing = Redecl.getKnownMergeTarget())
// We already know of an existing declaration we should merge with.
mergeRedeclarable(D, cast<T>(Existing), Redecl, TemplatePatternID);
@@ -2180,6 +2174,7 @@
DClass->IsCompleteDefinition = false;
} else {
ExistingClass->DefinitionData = DClass->DefinitionData;
+ Reader.PendingDefinitions.insert(DClass);
}
}
DClass->DefinitionData = ExistingClass->DefinitionData;
@@ -2208,14 +2203,18 @@
T *ExistingCanon = Existing->getCanonicalDecl();
T *DCanon = D->getCanonicalDecl();
if (ExistingCanon != DCanon) {
- assert(DCanon->getGlobalID() == Redecl.getFirstID());
+ assert(DCanon->getGlobalID() == Redecl.getFirstID() &&
+ "already merged this declaration");
// Have our redeclaration link point back at the canonical declaration
// of the existing declaration, so that this declaration has the
// appropriate canonical declaration.
D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon);
+ D->First = ExistingCanon;
// When we merge a namespace, update its pointer to the first namespace.
+ // We cannot have loaded any redeclarations of this declaration yet, so
+ // there's nothing else that needs to be updated.
if (auto *Namespace = dyn_cast<NamespaceDecl>(D))
Namespace->AnonOrFirstNamespaceAndInline.setPointer(
assert_cast<NamespaceDecl*>(ExistingCanon));
@@ -2226,14 +2225,11 @@
DTemplate, assert_cast<RedeclarableTemplateDecl*>(ExistingCanon),
TemplatePatternID);
- // If this declaration was the canonical declaration, make a note of
- // that. We accept the linear algorithm here because the number of
- // unique canonical declarations of an entity should always be tiny.
+ // If this declaration was the canonical declaration, make a note of that.
if (DCanon == D) {
- SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
- if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
- == Merged.end())
- Merged.push_back(Redecl.getFirstID());
+ Reader.MergedDecls[ExistingCanon].push_back(Redecl.getFirstID());
+ if (Reader.PendingDeclChainsKnown.insert(ExistingCanon).second)
+ Reader.PendingDeclChains.push_back(ExistingCanon);
}
}
}
@@ -2633,8 +2629,11 @@
if (needsAnonymousDeclarationNumber(New)) {
setAnonymousDeclForMerging(Reader, New->getLexicalDeclContext(),
AnonymousDeclNumber, New);
- } else if (DC->isTranslationUnit() && Reader.SemaObj) {
- Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name);
+ } else if (DC->isTranslationUnit() && Reader.SemaObj &&
+ !Reader.getContext().getLangOpts().CPlusPlus) {
+ if (Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name))
+ Reader.PendingFakeLookupResults[Name.getAsIdentifierInfo()]
+ .push_back(New);
} else if (DeclContext *MergeDC = getPrimaryContextForMerging(Reader, DC)) {
// Add the declaration to its redeclaration context so later merging
// lookups will find it.
@@ -2653,12 +2652,11 @@
// If we found a typedef declaration that gives a name to some other
// declaration, then we want that inner declaration. Declarations from
// AST files are handled via ImportedTypedefNamesForLinkage.
- if (Found->isFromASTFile()) return 0;
- if (auto *TND = dyn_cast<TypedefNameDecl>(Found)) {
- if (auto *TT = TND->getTypeSourceInfo()->getType()->getAs<TagType>())
- if (TT->getDecl()->getTypedefNameForAnonDecl() == TND)
- return TT->getDecl();
- }
+ if (Found->isFromASTFile())
+ return 0;
+
+ if (auto *TND = dyn_cast<TypedefNameDecl>(Found))
+ return TND->getAnonDeclWithTypedefName();
return 0;
}
@@ -2712,8 +2710,6 @@
// unmergeable contexts.
FindExistingResult Result(Reader, D, /*Existing=*/nullptr,
AnonymousDeclNumber, TypedefNameForLinkage);
- // FIXME: We may still need to pull in the redeclaration chain; there can
- // be redeclarations via 'decltype'.
Result.suppress();
return Result;
}
@@ -2741,7 +2737,8 @@
if (isSameEntity(Existing, D))
return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
TypedefNameForLinkage);
- } else if (DC->isTranslationUnit() && Reader.SemaObj) {
+ } else if (DC->isTranslationUnit() && Reader.SemaObj &&
+ !Reader.getContext().getLangOpts().CPlusPlus) {
IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
// Temporarily consider the identifier to be up-to-date. We don't want to
@@ -2803,20 +2800,47 @@
}
template<typename DeclT>
+Decl *ASTDeclReader::getMostRecentDeclImpl(Redeclarable<DeclT> *D) {
+ return D->RedeclLink.getLatestNotUpdated();
+}
+Decl *ASTDeclReader::getMostRecentDeclImpl(...) {
+ llvm_unreachable("getMostRecentDecl on non-redeclarable declaration");
+}
+
+Decl *ASTDeclReader::getMostRecentDecl(Decl *D) {
+ assert(D);
+
+ switch (D->getKind()) {
+#define ABSTRACT_DECL(TYPE)
+#define DECL(TYPE, BASE) \
+ case Decl::TYPE: \
+ return getMostRecentDeclImpl(cast<TYPE##Decl>(D));
+#include "clang/AST/DeclNodes.inc"
+ }
+ llvm_unreachable("unknown decl kind");
+}
+
+Decl *ASTReader::getMostRecentExistingDecl(Decl *D) {
+ return ASTDeclReader::getMostRecentDecl(D->getCanonicalDecl());
+}
+
+template<typename DeclT>
void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
Redeclarable<DeclT> *D,
- Decl *Previous) {
+ Decl *Previous, Decl *Canon) {
D->RedeclLink.setPrevious(cast<DeclT>(Previous));
+ D->First = cast<DeclT>(Previous)->First;
}
namespace clang {
template<>
void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
Redeclarable<FunctionDecl> *D,
- Decl *Previous) {
+ Decl *Previous, Decl *Canon) {
FunctionDecl *FD = static_cast<FunctionDecl*>(D);
FunctionDecl *PrevFD = cast<FunctionDecl>(Previous);
FD->RedeclLink.setPrevious(PrevFD);
+ FD->First = PrevFD->First;
// If the previous declaration is an inline function declaration, then this
// declaration is too.
@@ -2839,16 +2863,17 @@
FD->IsInline = true;
}
- // If this declaration has an unresolved exception specification but the
- // previous declaration had a resolved one, resolve the exception
- // specification now.
+ // If we need to propagate an exception specification along the redecl
+ // chain, make a note of that so that we can do so later.
auto *FPT = FD->getType()->getAs<FunctionProtoType>();
auto *PrevFPT = PrevFD->getType()->getAs<FunctionProtoType>();
- if (FPT && PrevFPT &&
- isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
- !isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType())) {
- Reader.Context.adjustExceptionSpec(
- FD, PrevFPT->getExtProtoInfo().ExceptionSpec);
+ if (FPT && PrevFPT) {
+ bool IsUnresolved = isUnresolvedExceptionSpec(FPT->getExceptionSpecType());
+ bool WasUnresolved =
+ isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType());
+ if (IsUnresolved != WasUnresolved)
+ Reader.PendingExceptionSpecUpdates.insert(
+ std::make_pair(Canon, IsUnresolved ? PrevFD : FD));
}
}
}
@@ -2857,14 +2882,14 @@
}
void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
- Decl *Previous) {
+ Decl *Previous, Decl *Canon) {
assert(D && Previous);
switch (D->getKind()) {
#define ABSTRACT_DECL(TYPE)
-#define DECL(TYPE, BASE) \
- case Decl::TYPE: \
- attachPreviousDeclImpl(Reader, cast<TYPE##Decl>(D), Previous); \
+#define DECL(TYPE, BASE) \
+ case Decl::TYPE: \
+ attachPreviousDeclImpl(Reader, cast<TYPE##Decl>(D), Previous, Canon); \
break;
#include "clang/AST/DeclNodes.inc"
}
@@ -2924,29 +2949,6 @@
}
}
-ASTReader::MergedDeclsMap::iterator
-ASTReader::combineStoredMergedDecls(Decl *Canon, GlobalDeclID CanonID) {
- // If we don't have any stored merged declarations, just look in the
- // merged declarations set.
- StoredMergedDeclsMap::iterator StoredPos = StoredMergedDecls.find(CanonID);
- if (StoredPos == StoredMergedDecls.end())
- return MergedDecls.find(Canon);
-
- // Append the stored merged declarations to the merged declarations set.
- MergedDeclsMap::iterator Pos = MergedDecls.find(Canon);
- if (Pos == MergedDecls.end())
- Pos = MergedDecls.insert(std::make_pair(Canon,
- SmallVector<DeclID, 2>())).first;
- Pos->second.append(StoredPos->second.begin(), StoredPos->second.end());
- StoredMergedDecls.erase(StoredPos);
-
- // Sort and uniquify the set of merged declarations.
- llvm::array_pod_sort(Pos->second.begin(), Pos->second.end());
- Pos->second.erase(std::unique(Pos->second.begin(), Pos->second.end()),
- Pos->second.end());
- return Pos;
-}
-
/// \brief Read the declaration at the given offset from the AST file.
Decl *ASTReader::ReadDeclRecord(DeclID ID) {
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
@@ -3151,6 +3153,9 @@
case DECL_CXX_BASE_SPECIFIERS:
Error("attempt to read a C++ base-specifier record as a declaration");
return nullptr;
+ case DECL_CXX_CTOR_INITIALIZERS:
+ Error("attempt to read a C++ ctor initializer record as a declaration");
+ return nullptr;
case DECL_IMPORT:
// Note: last entry of the ImportDecl record is the number of stored source
// locations.
@@ -3356,41 +3361,45 @@
};
}
-void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
- Decl *D = GetDecl(ID);
- Decl *CanonDecl = D->getCanonicalDecl();
-
+void ASTReader::loadPendingDeclChain(Decl *CanonDecl) {
+ // The decl might have been merged into something else after being added to
+ // our list. If it was, just skip it.
+ if (!CanonDecl->isCanonicalDecl())
+ return;
+
// Determine the set of declaration IDs we'll be searching for.
- SmallVector<DeclID, 1> SearchDecls;
- GlobalDeclID CanonID = 0;
- if (D == CanonDecl) {
- SearchDecls.push_back(ID); // Always first.
- CanonID = ID;
- }
- MergedDeclsMap::iterator MergedPos = combineStoredMergedDecls(CanonDecl, ID);
+ SmallVector<DeclID, 16> SearchDecls;
+ GlobalDeclID CanonID = CanonDecl->getGlobalID();
+ if (CanonID)
+ SearchDecls.push_back(CanonDecl->getGlobalID()); // Always first.
+ MergedDeclsMap::iterator MergedPos = MergedDecls.find(CanonDecl);
if (MergedPos != MergedDecls.end())
SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end());
-
+
// Build up the list of redeclarations.
RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID);
ModuleMgr.visitDepthFirst(&RedeclChainVisitor::visit, &Visitor);
-
+
// Retrieve the chains.
ArrayRef<Decl *> Chain = Visitor.getChain();
if (Chain.empty())
return;
-
+
// Hook up the chains.
- Decl *MostRecent = CanonDecl->getMostRecentDecl();
+ //
+ // FIXME: We have three different dispatches on decl kind here; maybe
+ // we should instead generate one loop per kind and dispatch up-front?
+ Decl *MostRecent = ASTDeclReader::getMostRecentDecl(CanonDecl);
+ if (!MostRecent)
+ MostRecent = CanonDecl;
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
if (Chain[I] == CanonDecl)
continue;
- ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent);
+ ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent, CanonDecl);
MostRecent = Chain[I];
}
-
- ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
+ ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
}
namespace {
@@ -3650,13 +3659,12 @@
});
}
FD->setInnerLocStart(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
- if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
- std::tie(CD->CtorInitializers, CD->NumCtorInitializers) =
- Reader.ReadCXXCtorInitializers(ModuleFile, Record, Idx);
- if (auto *DD = dyn_cast<CXXDestructorDecl>(FD))
- // FIXME: Check consistency.
- DD->setOperatorDelete(Reader.ReadDeclAs<FunctionDecl>(ModuleFile,
- Record, Idx));
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ CD->NumCtorInitializers = Record[Idx++];
+ if (CD->NumCtorInitializers)
+ CD->CtorInitializers =
+ Reader.ReadCXXCtorInitializersRef(F, Record, Idx);
+ }
// Store the offset of the body so we can lazily load it later.
Reader.PendingBodies[FD] = GetCurrentCursorOffset();
HasPendingBody = true;
@@ -3723,24 +3731,36 @@
break;
}
+ case UPD_CXX_RESOLVED_DTOR_DELETE: {
+ // Set the 'operator delete' directly to avoid emitting another update
+ // record.
+ auto *Del = Reader.ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ auto *First = cast<CXXDestructorDecl>(D->getCanonicalDecl());
+ // FIXME: Check consistency if we have an old and new operator delete.
+ if (!First->OperatorDelete)
+ First->OperatorDelete = Del;
+ break;
+ }
+
case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
- // FIXME: This doesn't send the right notifications if there are
- // ASTMutationListeners other than an ASTWriter.
FunctionProtoType::ExceptionSpecInfo ESI;
SmallVector<QualType, 8> ExceptionStorage;
Reader.readExceptionSpec(ModuleFile, ExceptionStorage, ESI, Record, Idx);
- for (auto *Redecl : merged_redecls(D)) {
- auto *FD = cast<FunctionDecl>(Redecl);
- auto *FPT = FD->getType()->castAs<FunctionProtoType>();
- if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
- // AST invariant: if any exception spec in the redecl chain is
- // resolved, all are resolved. We don't need to go any further.
- // FIXME: If the exception spec is resolved, check that it matches.
- break;
- }
+
+ // Update this declaration's exception specification, if needed.
+ auto *FD = cast<FunctionDecl>(D);
+ auto *FPT = FD->getType()->castAs<FunctionProtoType>();
+ // FIXME: If the exception specification is already present, check that it
+ // matches.
+ if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
FD->setType(Reader.Context.getFunctionType(
FPT->getReturnType(), FPT->getParamTypes(),
FPT->getExtProtoInfo().withExceptionSpec(ESI)));
+
+ // When we get to the end of deserializing, see if there are other decls
+ // that we need to propagate this exception specification onto.
+ Reader.PendingExceptionSpecUpdates.insert(
+ std::make_pair(FD->getCanonicalDecl(), FD));
}
break;
}
@@ -3772,10 +3792,24 @@
case UPD_STATIC_LOCAL_NUMBER:
Reader.Context.setStaticLocalNumber(cast<VarDecl>(D), Record[Idx++]);
break;
+
case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
Reader.Context, ReadSourceRange(Record, Idx)));
break;
+
+ case UPD_DECL_EXPORTED:
+ unsigned SubmoduleID = readSubmoduleID(Record, Idx);
+ Module *Owner = SubmoduleID ? Reader.getSubmodule(SubmoduleID) : nullptr;
+ if (Owner && Owner->NameVisibility != Module::AllVisible) {
+ // If Owner is made visible at some later point, make this declaration
+ // visible too.
+ Reader.HiddenNamesMap[Owner].HiddenDecls.push_back(D);
+ } else {
+ // The declaration is now visible.
+ D->Hidden = false;
+ }
+ break;
}
}
}
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 4ef2e73..c7b49de 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -486,7 +486,7 @@
// Read string data
SmallString<16> Str(&Record[Idx], &Record[Idx] + Len);
- E->setString(Reader.getContext(), Str.str(), kind, isPascal);
+ E->setString(Reader.getContext(), Str, kind, isPascal);
Idx += Len;
// Read source locations
@@ -1928,7 +1928,20 @@
for (unsigned i = 0; i != NumVars; ++i)
Vars.push_back(Reader->Reader.ReadSubExpr());
C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setInits(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setUpdates(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setFinals(Vars);
C->setStep(Reader->Reader.ReadSubExpr());
+ C->setCalcStep(Reader->Reader.ReadSubExpr());
}
void OMPClauseReader::VisitOMPAlignedClause(OMPAlignedClause *C) {
@@ -1956,11 +1969,23 @@
void OMPClauseReader::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
- SmallVector<Expr *, 16> Vars;
- Vars.reserve(NumVars);
+ SmallVector<Expr *, 16> Exprs;
+ Exprs.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i)
- Vars.push_back(Reader->Reader.ReadSubExpr());
- C->setVarRefs(Vars);
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setSourceExprs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setDestinationExprs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setAssignmentOps(Exprs);
}
void OMPClauseReader::VisitOMPFlushClause(OMPFlushClause *C) {
@@ -2132,7 +2157,9 @@
// The NumClauses field was read in ReadStmtFromStream.
++Idx;
VisitOMPExecutableDirective(D);
+ D->setOpKind(static_cast<BinaryOperatorKind>(Record[Idx++]));
D->setX(Reader.ReadSubExpr());
+ D->setXRVal(Reader.ReadSubExpr());
D->setV(Reader.ReadSubExpr());
D->setExpr(Reader.ReadSubExpr());
}
@@ -2420,17 +2447,18 @@
ExprObjectKind OK = static_cast<ExprObjectKind>(Record[Idx++]);
Expr *Base = ReadSubExpr();
ValueDecl *MemberD = ReadDeclAs<ValueDecl>(F, Record, Idx);
- SourceLocation MemberLoc = ReadSourceLocation(F, Record, Idx);
- DeclarationNameInfo MemberNameInfo(MemberD->getDeclName(), MemberLoc);
- bool IsArrow = Record[Idx++];
-
- S = MemberExpr::Create(Context, Base, IsArrow, QualifierLoc,
- TemplateKWLoc, MemberD, FoundDecl, MemberNameInfo,
- HasTemplateKWAndArgsInfo ? &ArgInfo : nullptr,
- T, VK, OK);
- ReadDeclarationNameLoc(F, cast<MemberExpr>(S)->MemberDNLoc,
- MemberD->getDeclName(), Record, Idx);
- if (HadMultipleCandidates)
+ SourceLocation MemberLoc = ReadSourceLocation(F, Record, Idx);
+ DeclarationNameInfo MemberNameInfo(MemberD->getDeclName(), MemberLoc);
+ bool IsArrow = Record[Idx++];
+ SourceLocation OperatorLoc = ReadSourceLocation(F, Record, Idx);
+
+ S = MemberExpr::Create(Context, Base, IsArrow, OperatorLoc, QualifierLoc,
+ TemplateKWLoc, MemberD, FoundDecl, MemberNameInfo,
+ HasTemplateKWAndArgsInfo ? &ArgInfo : nullptr, T,
+ VK, OK);
+ ReadDeclarationNameLoc(F, cast<MemberExpr>(S)->MemberDNLoc,
+ MemberD->getDeclName(), Record, Idx);
+ if (HadMultipleCandidates)
cast<MemberExpr>(S)->setHadMultipleCandidates(true);
break;
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 3af2a40..eccff9d 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -867,6 +867,7 @@
RECORD(MODULE_NAME);
RECORD(MODULE_MAP_FILE);
RECORD(IMPORTS);
+ RECORD(KNOWN_MODULE_FILES);
RECORD(LANGUAGE_OPTIONS);
RECORD(TARGET_OPTIONS);
RECORD(ORIGINAL_FILE);
@@ -892,7 +893,6 @@
RECORD(STATISTICS);
RECORD(TENTATIVE_DEFINITIONS);
RECORD(UNUSED_FILESCOPED_DECLS);
- RECORD(LOCALLY_SCOPED_EXTERN_C_DECLS);
RECORD(SELECTOR_OFFSETS);
RECORD(METHOD_POOL);
RECORD(PP_COUNTER_VALUE);
@@ -924,7 +924,6 @@
RECORD(OBJC_CATEGORIES_MAP);
RECORD(FILE_SORTED_DECLS);
RECORD(IMPORTED_MODULES);
- RECORD(MERGED_DECLARATIONS);
RECORD(LOCAL_REDECLARATIONS);
RECORD(OBJC_CATEGORIES);
RECORD(MACRO_OFFSET);
@@ -1161,12 +1160,17 @@
Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
getClangFullRepositoryVersion());
- // Signature
- Record.clear();
- Record.push_back(getSignature());
- Stream.EmitRecord(SIGNATURE, Record);
-
if (WritingModule) {
+ // For implicit modules we output a signature that we can use to ensure
+ // duplicate module builds don't collide in the cache as their output order
+ // is non-deterministic.
+ // FIXME: Remove this when output is deterministic.
+ if (Context.getLangOpts().ImplicitModules) {
+ Record.clear();
+ Record.push_back(getSignature());
+ Stream.EmitRecord(SIGNATURE, Record);
+ }
+
// Module name
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));
@@ -1224,20 +1228,28 @@
serialization::ModuleManager &Mgr = Chain->getModuleManager();
Record.clear();
- for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end();
- M != MEnd; ++M) {
+ for (auto *M : Mgr) {
// Skip modules that weren't directly imported.
- if (!(*M)->isDirectlyImported())
+ if (!M->isDirectlyImported())
continue;
- Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding
- AddSourceLocation((*M)->ImportLoc, Record);
- Record.push_back((*M)->File->getSize());
- Record.push_back((*M)->File->getModificationTime());
- Record.push_back((*M)->Signature);
- AddPath((*M)->FileName, Record);
+ Record.push_back((unsigned)M->Kind); // FIXME: Stable encoding
+ AddSourceLocation(M->ImportLoc, Record);
+ Record.push_back(M->File->getSize());
+ Record.push_back(M->File->getModificationTime());
+ Record.push_back(M->Signature);
+ AddPath(M->FileName, Record);
}
Stream.EmitRecord(IMPORTS, Record);
+
+ // Also emit a list of known module files that were not imported,
+ // but are made available by this module.
+ // FIXME: Should we also include a signature here?
+ Record.clear();
+ for (auto *E : Mgr.getAdditionalKnownModuleFiles())
+ AddPath(E->getName(), Record);
+ if (!Record.empty())
+ Stream.EmitRecord(KNOWN_MODULE_FILES, Record);
}
// Language options.
@@ -1760,7 +1772,7 @@
Record.push_back(NumHeaderSearchEntries);
Record.push_back(TableData.size());
TableData.append(GeneratorTrait.strings_begin(),GeneratorTrait.strings_end());
- Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData.str());
+ Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData);
// Free all of the strings we had to duplicate.
for (unsigned I = 0, N = SavedStrings.size(); I != N; ++I)
@@ -2220,7 +2232,7 @@
Record.push_back(MACRO_TABLE);
Record.push_back(BucketOffset);
- Stream.EmitRecordWithBlob(MacroTableAbbrev, Record, MacroTable.str());
+ Stream.EmitRecordWithBlob(MacroTableAbbrev, Record, MacroTable);
Record.clear();
// Write the offsets table for macro IDs.
@@ -2687,6 +2699,29 @@
Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record);
}
+void ASTWriter::WriteCXXCtorInitializersOffsets() {
+ if (CXXCtorInitializersOffsets.empty())
+ return;
+
+ RecordData Record;
+
+ // Create a blob abbreviation for the C++ ctor initializer offsets.
+ using namespace llvm;
+
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(CXX_CTOR_INITIALIZERS_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned CtorInitializersOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the base specifier offsets table.
+ Record.clear();
+ Record.push_back(CXX_CTOR_INITIALIZERS_OFFSETS);
+ Record.push_back(CXXCtorInitializersOffsets.size());
+ Stream.EmitRecordWithBlob(CtorInitializersOffsetAbbrev, Record,
+ data(CXXCtorInitializersOffsets));
+}
+
void ASTWriter::WriteCXXBaseSpecifiersOffsets() {
if (CXXBaseSpecifiersOffsets.empty())
return;
@@ -2822,15 +2857,18 @@
using namespace llvm;
RecordData Record;
+ SmallVector<std::pair<FileID, DeclIDInFileInfo *>, 64> SortedFileDeclIDs(
+ FileDeclIDs.begin(), FileDeclIDs.end());
+ std::sort(SortedFileDeclIDs.begin(), SortedFileDeclIDs.end(),
+ llvm::less_first());
+
// Join the vectors of DeclIDs from all files.
- SmallVector<DeclID, 256> FileSortedIDs;
- for (FileDeclIDsTy::iterator
- FI = FileDeclIDs.begin(), FE = FileDeclIDs.end(); FI != FE; ++FI) {
- DeclIDInFileInfo &Info = *FI->second;
- Info.FirstDeclIndex = FileSortedIDs.size();
- for (LocDeclIDsTy::iterator
- DI = Info.DeclIDs.begin(), DE = Info.DeclIDs.end(); DI != DE; ++DI)
- FileSortedIDs.push_back(DI->second);
+ SmallVector<DeclID, 256> FileGroupedDeclIDs;
+ for (auto &FileDeclEntry : SortedFileDeclIDs) {
+ DeclIDInFileInfo &Info = *FileDeclEntry.second;
+ Info.FirstDeclIndex = FileGroupedDeclIDs.size();
+ for (auto &LocDeclEntry : Info.DeclIDs)
+ FileGroupedDeclIDs.push_back(LocDeclEntry.second);
}
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
@@ -2839,8 +2877,8 @@
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
Record.push_back(FILE_SORTED_DECLS);
- Record.push_back(FileSortedIDs.size());
- Stream.EmitRecordWithBlob(AbbrevCode, Record, data(FileSortedIDs));
+ Record.push_back(FileGroupedDeclIDs.size());
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, data(FileGroupedDeclIDs));
}
void ASTWriter::WriteComments() {
@@ -2991,13 +3029,12 @@
// Create the on-disk hash table representation. We walk through every
// selector we've seen and look it up in the method pool.
SelectorOffsets.resize(NextSelectorID - FirstSelectorID);
- for (llvm::DenseMap<Selector, SelectorID>::iterator
- I = SelectorIDs.begin(), E = SelectorIDs.end();
- I != E; ++I) {
- Selector S = I->first;
+ for (auto &SelectorAndID : SelectorIDs) {
+ Selector S = SelectorAndID.first;
+ SelectorID ID = SelectorAndID.second;
Sema::GlobalMethodPool::iterator F = SemaRef.MethodPool.find(S);
ASTMethodPoolTrait::data_type Data = {
- I->second,
+ ID,
ObjCMethodList(),
ObjCMethodList()
};
@@ -3007,7 +3044,7 @@
}
// Only write this selector if it's not in an existing AST or something
// changed.
- if (Chain && I->second < FirstSelectorID) {
+ if (Chain && ID < FirstSelectorID) {
// Selector already exists. Did it change?
bool changed = false;
for (ObjCMethodList *M = &Data.Instance;
@@ -3054,7 +3091,7 @@
Record.push_back(METHOD_POOL);
Record.push_back(BucketOffset);
Record.push_back(NumTableEntries);
- Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool.str());
+ Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool);
// Create a blob abbreviation for the selector table offsets.
Abbrev = new BitCodeAbbrev();
@@ -3085,11 +3122,9 @@
// Note: this writes out all references even for a dependent AST. But it is
// very tricky to fix, and given that @selector shouldn't really appear in
// headers, probably not worth it. It's not a correctness issue.
- for (DenseMap<Selector, SourceLocation>::iterator S =
- SemaRef.ReferencedSelectors.begin(),
- E = SemaRef.ReferencedSelectors.end(); S != E; ++S) {
- Selector Sel = (*S).first;
- SourceLocation Loc = (*S).second;
+ for (auto &SelectorAndLocation : SemaRef.ReferencedSelectors) {
+ Selector Sel = SelectorAndLocation.first;
+ SourceLocation Loc = SelectorAndLocation.second;
AddSelectorRef(Sel, Record);
AddSourceLocation(Loc, Record);
}
@@ -3115,7 +3150,7 @@
for (; Redecl; Redecl = Redecl->getPreviousDecl()) {
if (!Redecl->isFromASTFile())
return cast<NamedDecl>(Redecl);
- // If we come up a decl from a (chained-)PCH stop since we won't find a
+ // If we find a decl from a (chained-)PCH stop since we won't find a
// local one.
if (D->getOwningModuleID() == 0)
break;
@@ -3349,6 +3384,7 @@
using namespace llvm::support;
endian::Writer<little> LE(Out);
+ assert((uint16_t)DataLen == DataLen && (uint16_t)KeyLen == KeyLen);
LE.write<uint16_t>(DataLen);
// We emit the key length after the data length so that every
// string is preceded by a 16-bit length. This matches the PTH
@@ -3427,7 +3463,7 @@
}
emitMacroOverrides(Out, getOverriddenSubmodules(MD, Scratch));
}
- LE.write<uint32_t>(0xdeadbeef);
+ LE.write<uint32_t>((uint32_t)-1);
}
}
@@ -3468,22 +3504,26 @@
// table to enable checking of the predefines buffer in the case
// where the user adds new macro definitions when building the AST
// file.
+ SmallVector<const IdentifierInfo *, 128> IIs;
for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
IDEnd = PP.getIdentifierTable().end();
ID != IDEnd; ++ID)
- getIdentifierRef(ID->second);
+ IIs.push_back(ID->second);
+ // Sort the identifiers lexicographically before getting them references so
+ // that their order is stable.
+ std::sort(IIs.begin(), IIs.end(), llvm::less_ptr<IdentifierInfo>());
+ for (const IdentifierInfo *II : IIs)
+ getIdentifierRef(II);
// Create the on-disk hash table representation. We only store offsets
// for identifiers that appear here for the first time.
IdentifierOffsets.resize(NextIdentID - FirstIdentID);
- for (llvm::DenseMap<const IdentifierInfo *, IdentID>::iterator
- ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end();
- ID != IDEnd; ++ID) {
- assert(ID->first && "NULL identifier in identifier table");
- if (!Chain || !ID->first->isFromAST() ||
- ID->first->hasChangedSinceDeserialization())
- Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,
- Trait);
+ for (auto IdentIDPair : IdentifierIDs) {
+ IdentifierInfo *II = const_cast<IdentifierInfo *>(IdentIDPair.first);
+ IdentID ID = IdentIDPair.second;
+ assert(II && "NULL identifier in identifier table");
+ if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization())
+ Generator.insert(II, ID, Trait);
}
// Create the on-disk hash table in a buffer.
@@ -3509,7 +3549,7 @@
RecordData Record;
Record.push_back(IDENTIFIER_TABLE);
Record.push_back(BucketOffset);
- Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str());
+ Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable);
}
// Write the offsets table for identifier IDs.
@@ -3662,111 +3702,191 @@
};
} // end anonymous namespace
-template<typename Visitor>
-static void visitLocalLookupResults(const DeclContext *ConstDC,
- bool NeedToReconcileExternalVisibleStorage,
- Visitor AddLookupResult) {
+bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result,
+ DeclContext *DC) {
+ return Result.hasExternalDecls() && DC->NeedToReconcileExternalVisibleStorage;
+}
+
+bool ASTWriter::isLookupResultEntirelyExternal(StoredDeclsList &Result,
+ DeclContext *DC) {
+ for (auto *D : Result.getLookupResult())
+ if (!getDeclForLocalLookup(getLangOpts(), D)->isFromASTFile())
+ return false;
+
+ return true;
+}
+
+uint32_t
+ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,
+ llvm::SmallVectorImpl<char> &LookupTable) {
+ assert(!ConstDC->HasLazyLocalLexicalLookups &&
+ !ConstDC->HasLazyExternalLexicalLookups &&
+ "must call buildLookups first");
+
// FIXME: We need to build the lookups table, which is logically const.
DeclContext *DC = const_cast<DeclContext*>(ConstDC);
assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table");
- SmallVector<DeclarationName, 16> ExternalNames;
- for (auto &Lookup : *DC->buildLookup()) {
- if (Lookup.second.hasExternalDecls() ||
- NeedToReconcileExternalVisibleStorage) {
- // We don't know for sure what declarations are found by this name,
- // because the external source might have a different set from the set
- // that are in the lookup map, and we can't update it now without
- // risking invalidating our lookup iterator. So add it to a queue to
- // deal with later.
- ExternalNames.push_back(Lookup.first);
- continue;
- }
-
- AddLookupResult(Lookup.first, Lookup.second.getLookupResult());
- }
-
- // Add the names we needed to defer. Note, this shouldn't add any new decls
- // to the list we need to serialize: any new declarations we find here should
- // be imported from an external source.
- // FIXME: What if the external source isn't an ASTReader?
- for (const auto &Name : ExternalNames)
- AddLookupResult(Name, DC->lookup(Name));
-}
-
-void ASTWriter::AddUpdatedDeclContext(const DeclContext *DC) {
- if (UpdatedDeclContexts.insert(DC).second && WritingAST) {
- // Ensure we emit all the visible declarations.
- visitLocalLookupResults(DC, DC->NeedToReconcileExternalVisibleStorage,
- [&](DeclarationName Name,
- DeclContext::lookup_result Result) {
- for (auto *Decl : Result)
- GetDeclRef(getDeclForLocalLookup(getLangOpts(), Decl));
- });
- }
-}
-
-uint32_t
-ASTWriter::GenerateNameLookupTable(const DeclContext *DC,
- llvm::SmallVectorImpl<char> &LookupTable) {
- assert(!DC->LookupPtr.getInt() && "must call buildLookups first");
-
+ // Create the on-disk hash table representation.
llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait>
Generator;
ASTDeclContextNameLookupTrait Trait(*this);
- // Create the on-disk hash table representation.
- DeclarationName ConstructorName;
- DeclarationName ConversionName;
- SmallVector<NamedDecl *, 8> ConstructorDecls;
- SmallVector<NamedDecl *, 4> ConversionDecls;
+ // The first step is to collect the declaration names which we need to
+ // serialize into the name lookup table, and to collect them in a stable
+ // order.
+ SmallVector<DeclarationName, 16> Names;
- visitLocalLookupResults(DC, DC->NeedToReconcileExternalVisibleStorage,
- [&](DeclarationName Name,
- DeclContext::lookup_result Result) {
- if (Result.empty())
- return;
+ // We also build up small sets of the constructor and conversion function
+ // names which are visible.
+ llvm::SmallSet<DeclarationName, 8> ConstructorNameSet, ConversionNameSet;
- // Different DeclarationName values of certain kinds are mapped to
- // identical serialized keys, because we don't want to use type
- // identifiers in the keys (since type ids are local to the module).
- switch (Name.getNameKind()) {
+ for (auto &Lookup : *DC->buildLookup()) {
+ auto &Name = Lookup.first;
+ auto &Result = Lookup.second;
+
+ // If there are no local declarations in our lookup result, we don't
+ // need to write an entry for the name at all unless we're rewriting
+ // the decl context. If we can't write out a lookup set without
+ // performing more deserialization, just skip this entry.
+ if (isLookupResultExternal(Result, DC) && !isRewritten(cast<Decl>(DC)) &&
+ isLookupResultEntirelyExternal(Result, DC))
+ continue;
+
+ // We also skip empty results. If any of the results could be external and
+ // the currently available results are empty, then all of the results are
+ // external and we skip it above. So the only way we get here with an empty
+ // results is when no results could have been external *and* we have
+ // external results.
+ //
+ // FIXME: While we might want to start emitting on-disk entries for negative
+ // lookups into a decl context as an optimization, today we *have* to skip
+ // them because there are names with empty lookup results in decl contexts
+ // which we can't emit in any stable ordering: we lookup constructors and
+ // conversion functions in the enclosing namespace scope creating empty
+ // results for them. This in almost certainly a bug in Clang's name lookup,
+ // but that is likely to be hard or impossible to fix and so we tolerate it
+ // here by omitting lookups with empty results.
+ if (Lookup.second.getLookupResult().empty())
+ continue;
+
+ switch (Lookup.first.getNameKind()) {
+ default:
+ Names.push_back(Lookup.first);
+ break;
+
case DeclarationName::CXXConstructorName:
- // There may be different CXXConstructorName DeclarationName values
- // in a DeclContext because a UsingDecl that inherits constructors
- // has the DeclarationName of the inherited constructors.
- if (!ConstructorName)
- ConstructorName = Name;
- ConstructorDecls.append(Result.begin(), Result.end());
- return;
+ assert(isa<CXXRecordDecl>(DC) &&
+ "Cannot have a constructor name outside of a class!");
+ ConstructorNameSet.insert(Name);
+ break;
case DeclarationName::CXXConversionFunctionName:
- if (!ConversionName)
- ConversionName = Name;
- ConversionDecls.append(Result.begin(), Result.end());
- return;
-
- default:
+ assert(isa<CXXRecordDecl>(DC) &&
+ "Cannot have a conversion function name outside of a class!");
+ ConversionNameSet.insert(Name);
break;
}
-
- Generator.insert(Name, Result, Trait);
- });
-
- // Add the constructors.
- if (!ConstructorDecls.empty()) {
- Generator.insert(ConstructorName,
- DeclContext::lookup_result(ConstructorDecls),
- Trait);
}
- // Add the conversion functions.
- if (!ConversionDecls.empty()) {
- Generator.insert(ConversionName,
- DeclContext::lookup_result(ConversionDecls),
- Trait);
+ // Sort the names into a stable order.
+ std::sort(Names.begin(), Names.end());
+
+ if (auto *D = dyn_cast<CXXRecordDecl>(DC)) {
+ // We need to establish an ordering of constructor and conversion function
+ // names, and they don't have an intrinsic ordering.
+
+ // First we try the easy case by forming the current context's constructor
+ // name and adding that name first. This is a very useful optimization to
+ // avoid walking the lexical declarations in many cases, and it also
+ // handles the only case where a constructor name can come from some other
+ // lexical context -- when that name is an implicit constructor merged from
+ // another declaration in the redecl chain. Any non-implicit constructor or
+ // conversion function which doesn't occur in all the lexical contexts
+ // would be an ODR violation.
+ auto ImplicitCtorName = Context->DeclarationNames.getCXXConstructorName(
+ Context->getCanonicalType(Context->getRecordType(D)));
+ if (ConstructorNameSet.erase(ImplicitCtorName))
+ Names.push_back(ImplicitCtorName);
+
+ // If we still have constructors or conversion functions, we walk all the
+ // names in the decl and add the constructors and conversion functions
+ // which are visible in the order they lexically occur within the context.
+ if (!ConstructorNameSet.empty() || !ConversionNameSet.empty())
+ for (Decl *ChildD : cast<CXXRecordDecl>(DC)->decls())
+ if (auto *ChildND = dyn_cast<NamedDecl>(ChildD)) {
+ auto Name = ChildND->getDeclName();
+ switch (Name.getNameKind()) {
+ default:
+ continue;
+
+ case DeclarationName::CXXConstructorName:
+ if (ConstructorNameSet.erase(Name))
+ Names.push_back(Name);
+ break;
+
+ case DeclarationName::CXXConversionFunctionName:
+ if (ConversionNameSet.erase(Name))
+ Names.push_back(Name);
+ break;
+ }
+
+ if (ConstructorNameSet.empty() && ConversionNameSet.empty())
+ break;
+ }
+
+ assert(ConstructorNameSet.empty() && "Failed to find all of the visible "
+ "constructors by walking all the "
+ "lexical members of the context.");
+ assert(ConversionNameSet.empty() && "Failed to find all of the visible "
+ "conversion functions by walking all "
+ "the lexical members of the context.");
}
+ // Next we need to do a lookup with each name into this decl context to fully
+ // populate any results from external sources. We don't actually use the
+ // results of these lookups because we only want to use the results after all
+ // results have been loaded and the pointers into them will be stable.
+ for (auto &Name : Names)
+ DC->lookup(Name);
+
+ // Now we need to insert the results for each name into the hash table. For
+ // constructor names and conversion function names, we actually need to merge
+ // all of the results for them into one list of results each and insert
+ // those.
+ SmallVector<NamedDecl *, 8> ConstructorDecls;
+ SmallVector<NamedDecl *, 8> ConversionDecls;
+
+ // Now loop over the names, either inserting them or appending for the two
+ // special cases.
+ for (auto &Name : Names) {
+ DeclContext::lookup_result Result = DC->noload_lookup(Name);
+
+ switch (Name.getNameKind()) {
+ default:
+ Generator.insert(Name, Result, Trait);
+ break;
+
+ case DeclarationName::CXXConstructorName:
+ ConstructorDecls.append(Result.begin(), Result.end());
+ break;
+
+ case DeclarationName::CXXConversionFunctionName:
+ ConversionDecls.append(Result.begin(), Result.end());
+ break;
+ }
+ }
+
+ // Handle our two special cases if we ended up having any. We arbitrarily use
+ // the first declaration's name here because the name itself isn't part of
+ // the key, only the kind of name is used.
+ if (!ConstructorDecls.empty())
+ Generator.insert(ConstructorDecls.front()->getDeclName(),
+ DeclContext::lookup_result(ConstructorDecls), Trait);
+ if (!ConversionDecls.empty())
+ Generator.insert(ConversionDecls.front()->getDeclName(),
+ DeclContext::lookup_result(ConversionDecls), Trait);
+
// Create the on-disk hash table in a buffer.
llvm::raw_svector_ostream Out(LookupTable);
// Make sure that no bucket is at offset 0
@@ -3785,9 +3905,8 @@
if (DC->getPrimaryContext() != DC)
return 0;
- // Since there is no name lookup into functions or methods, don't bother to
- // build a visible-declarations table for these entities.
- if (DC->isFunctionOrMethod())
+ // Skip contexts which don't support name lookup.
+ if (!DC->isLookupContext())
return 0;
// If not in C++, we perform name lookup for the translation unit via the
@@ -3814,7 +3933,7 @@
Record.push_back(DECL_CONTEXT_VISIBLE);
Record.push_back(BucketOffset);
Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record,
- LookupTable.str());
+ LookupTable);
++NumVisibleDeclContexts;
return Offset;
}
@@ -3839,7 +3958,7 @@
Record.push_back(UPDATE_VISIBLE);
Record.push_back(getDeclID(cast<Decl>(DC)));
Record.push_back(BucketOffset);
- Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable.str());
+ Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable);
}
/// \brief Write an FP_PRAGMA_OPTIONS block for the given FPOptions.
@@ -3889,18 +4008,6 @@
}
}
- if (!First->isFromASTFile() && Chain) {
- Decl *FirstFromAST = MostRecent;
- for (Decl *Prev = MostRecent; Prev; Prev = Prev->getPreviousDecl()) {
- if (Prev->isFromASTFile())
- FirstFromAST = Prev;
- }
-
- // FIXME: Do we need to do this for the first declaration from each
- // redeclaration chain that was merged into this one?
- Chain->MergedDecls[FirstFromAST].push_back(getDeclID(First));
- }
-
LocalRedeclChains[Offset] = Size;
// Reverse the set of local redeclarations, so that we store them in
@@ -3995,25 +4102,6 @@
Stream.EmitRecord(OBJC_CATEGORIES, Categories);
}
-void ASTWriter::WriteMergedDecls() {
- if (!Chain || Chain->MergedDecls.empty())
- return;
-
- RecordData Record;
- for (ASTReader::MergedDeclsMap::iterator I = Chain->MergedDecls.begin(),
- IEnd = Chain->MergedDecls.end();
- I != IEnd; ++I) {
- DeclID CanonID = I->first->isFromASTFile()? I->first->getGlobalID()
- : GetDeclRef(I->first);
- assert(CanonID && "Merged declaration not known?");
-
- Record.push_back(CanonID);
- Record.push_back(I->second.size());
- Record.append(I->second.begin(), I->second.end());
- }
- Stream.EmitRecord(MERGED_DECLARATIONS, Record);
-}
-
void ASTWriter::WriteLateParsedTemplates(Sema &SemaRef) {
Sema::LateParsedTemplateMapT &LPTMap = SemaRef.LateParsedTemplateMap;
@@ -4021,11 +4109,10 @@
return;
RecordData Record;
- for (Sema::LateParsedTemplateMapT::iterator It = LPTMap.begin(),
- ItEnd = LPTMap.end();
- It != ItEnd; ++It) {
- LateParsedTemplate *LPT = It->second;
- AddDeclRef(It->first, Record);
+ for (auto LPTMapEntry : LPTMap) {
+ const FunctionDecl *FD = LPTMapEntry.first;
+ LateParsedTemplate *LPT = LPTMapEntry.second;
+ AddDeclRef(FD, Record);
AddDeclRef(LPT->D, Record);
Record.push_back(LPT->Toks.size());
@@ -4162,7 +4249,8 @@
FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID),
CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0),
NumLexicalDeclContexts(0), NumVisibleDeclContexts(0),
- NextCXXBaseSpecifiersID(1), TypeExtQualAbbrev(0),
+ NextCXXBaseSpecifiersID(1), NextCXXCtorInitializersID(1),
+ TypeExtQualAbbrev(0),
TypeFunctionProtoAbbrev(0), DeclParmVarAbbrev(0),
DeclContextLexicalAbbrev(0), DeclContextVisibleLookupAbbrev(0),
UpdateVisibleAbbrev(0), DeclRecordAbbrev(0), DeclTypedefAbbrev(0),
@@ -4250,30 +4338,8 @@
DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID;
if (Context.BuiltinVaListDecl)
DeclIDs[Context.getBuiltinVaListDecl()] = PREDEF_DECL_BUILTIN_VA_LIST_ID;
-
- if (!Chain) {
- // Make sure that we emit IdentifierInfos (and any attached
- // declarations) for builtins. We don't need to do this when we're
- // emitting chained PCH files, because all of the builtins will be
- // in the original PCH file.
- // FIXME: Modules won't like this at all.
- IdentifierTable &Table = PP.getIdentifierTable();
- SmallVector<const char *, 32> BuiltinNames;
- if (!Context.getLangOpts().NoBuiltin) {
- Context.BuiltinInfo.GetBuiltinNames(BuiltinNames);
- }
- for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I)
- getIdentifierRef(&Table.get(BuiltinNames[I]));
- }
-
- // If we saw any DeclContext updates before we started writing the AST file,
- // make sure all visible decls in those DeclContexts are written out.
- if (!UpdatedDeclContexts.empty()) {
- auto OldUpdatedDeclContexts = std::move(UpdatedDeclContexts);
- UpdatedDeclContexts.clear();
- for (auto *DC : OldUpdatedDeclContexts)
- AddUpdatedDeclContext(DC);
- }
+ if (Context.ExternCContext)
+ DeclIDs[Context.ExternCContext] = PREDEF_DECL_EXTERN_C_CONTEXT_ID;
// Build a record containing all of the tentative definitions in this file, in
// TentativeDefinitions order. Generally, this record will be empty for
@@ -4297,31 +4363,15 @@
// entire table, since later PCH files in a PCH chain are only interested in
// the results at the end of the chain.
RecordData WeakUndeclaredIdentifiers;
- if (!SemaRef.WeakUndeclaredIdentifiers.empty()) {
- for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator
- I = SemaRef.WeakUndeclaredIdentifiers.begin(),
- E = SemaRef.WeakUndeclaredIdentifiers.end(); I != E; ++I) {
- AddIdentifierRef(I->first, WeakUndeclaredIdentifiers);
- AddIdentifierRef(I->second.getAlias(), WeakUndeclaredIdentifiers);
- AddSourceLocation(I->second.getLocation(), WeakUndeclaredIdentifiers);
- WeakUndeclaredIdentifiers.push_back(I->second.getUsed());
- }
+ for (auto &WeakUndeclaredIdentifier : SemaRef.WeakUndeclaredIdentifiers) {
+ IdentifierInfo *II = WeakUndeclaredIdentifier.first;
+ WeakInfo &WI = WeakUndeclaredIdentifier.second;
+ AddIdentifierRef(II, WeakUndeclaredIdentifiers);
+ AddIdentifierRef(WI.getAlias(), WeakUndeclaredIdentifiers);
+ AddSourceLocation(WI.getLocation(), WeakUndeclaredIdentifiers);
+ WeakUndeclaredIdentifiers.push_back(WI.getUsed());
}
- // Build a record containing all of the locally-scoped extern "C"
- // declarations in this header file. Generally, this record will be
- // empty.
- RecordData LocallyScopedExternCDecls;
- // FIXME: This is filling in the AST file in densemap order which is
- // nondeterminstic!
- for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
- TD = SemaRef.LocallyScopedExternCDecls.begin(),
- TDEnd = SemaRef.LocallyScopedExternCDecls.end();
- TD != TDEnd; ++TD) {
- if (!TD->second->isFromASTFile())
- AddDeclRef(TD->second, LocallyScopedExternCDecls);
- }
-
// Build a record containing all of the ext_vector declarations.
RecordData ExtVectorDecls;
AddLazyVectorDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls);
@@ -4341,10 +4391,6 @@
for (const TypedefNameDecl *TD : SemaRef.UnusedLocalTypedefNameCandidates)
AddDeclRef(TD, UnusedLocalTypedefNameCandidates);
- // Build a record containing all of dynamic classes declarations.
- RecordData DynamicClasses;
- AddLazyVectorDecls(*this, SemaRef.DynamicClasses, DynamicClasses);
-
// Build a record containing all of pending implicit instantiations.
RecordData PendingInstantiations;
for (std::deque<Sema::PendingImplicitInstantiation>::iterator
@@ -4428,6 +4474,10 @@
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv);
WriteDeclContextVisibleUpdate(TU);
+
+ // If we have any extern "C" names, write out a visible update for them.
+ if (Context.ExternCContext)
+ WriteDeclContextVisibleUpdate(Context.ExternCContext);
// If the translation unit has an anonymous namespace, and we don't already
// have an update block for it, write it as an update block.
@@ -4460,16 +4510,21 @@
// Make sure all decls associated with an identifier are registered for
// serialization.
+ llvm::SmallVector<const IdentifierInfo*, 256> IIs;
for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
IDEnd = PP.getIdentifierTable().end();
ID != IDEnd; ++ID) {
const IdentifierInfo *II = ID->second;
- if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization()) {
- for (IdentifierResolver::iterator D = SemaRef.IdResolver.begin(II),
- DEnd = SemaRef.IdResolver.end();
- D != DEnd; ++D) {
- GetDeclRef(*D);
- }
+ if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization())
+ IIs.push_back(II);
+ }
+ // Sort the identifiers to visit based on their name.
+ std::sort(IIs.begin(), IIs.end(), llvm::less_ptr<IdentifierInfo>());
+ for (const IdentifierInfo *II : IIs) {
+ for (IdentifierResolver::iterator D = SemaRef.IdResolver.begin(II),
+ DEnd = SemaRef.IdResolver.end();
+ D != DEnd; ++D) {
+ GetDeclRef(*D);
}
}
@@ -4576,6 +4631,7 @@
if (!DeclUpdatesOffsetsRecord.empty())
Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord);
WriteCXXBaseSpecifiersOffsets();
+ WriteCXXCtorInitializersOffsets();
WriteFileDeclIDsMap();
WriteSourceManagerBlock(Context.getSourceManager(), PP);
@@ -4612,11 +4668,6 @@
Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS,
WeakUndeclaredIdentifiers);
- // Write the record containing locally-scoped extern "C" definitions.
- if (!LocallyScopedExternCDecls.empty())
- Stream.EmitRecord(LOCALLY_SCOPED_EXTERN_C_DECLS,
- LocallyScopedExternCDecls);
-
// Write the record containing ext_vector type names.
if (!ExtVectorDecls.empty())
Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls);
@@ -4625,10 +4676,6 @@
if (!VTableUses.empty())
Stream.EmitRecord(VTABLE_USES, VTableUses);
- // Write the record containing dynamic classes declarations.
- if (!DynamicClasses.empty())
- Stream.EmitRecord(DYNAMIC_CLASSES, DynamicClasses);
-
// Write the record containing potentially unused local typedefs.
if (!UnusedLocalTypedefNameCandidates.empty())
Stream.EmitRecord(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES,
@@ -4704,7 +4751,6 @@
WriteDeclReplacementsBlock();
WriteRedeclarations();
- WriteMergedDecls();
WriteObjCCategories();
WriteLateParsedTemplates(SemaRef);
if(!WritingModule)
@@ -4759,7 +4805,7 @@
case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
auto *RD = cast<CXXRecordDecl>(D);
- AddUpdatedDeclContext(RD->getPrimaryContext());
+ UpdatedDeclContexts.insert(RD->getPrimaryContext());
AddCXXDefinitionData(RD, Record);
Record.push_back(WriteDeclContextLexicalBlock(
*Context, const_cast<CXXRecordDecl *>(RD)));
@@ -4803,6 +4849,10 @@
break;
}
+ case UPD_CXX_RESOLVED_DTOR_DELETE:
+ AddDeclRef(Update.getDecl(), Record);
+ break;
+
case UPD_CXX_RESOLVED_EXCEPTION_SPEC:
addExceptionSpec(
*this,
@@ -4821,10 +4871,15 @@
case UPD_STATIC_LOCAL_NUMBER:
Record.push_back(Update.getNumber());
break;
+
case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
AddSourceRange(D->getAttr<OMPThreadPrivateDeclAttr>()->getRange(),
Record);
break;
+
+ case UPD_DECL_EXPORTED:
+ Record.push_back(inferSubmoduleIDFromLocation(Update.getLoc()));
+ break;
}
}
@@ -4834,8 +4889,6 @@
Record.push_back(Def->isInlined());
AddSourceLocation(Def->getInnerLocStart(), Record);
AddFunctionDefinition(Def, Record);
- if (auto *DD = dyn_cast<CXXDestructorDecl>(Def))
- Record.push_back(GetDeclRef(DD->getOperatorDelete()));
}
OffsetsRecord.push_back(GetDeclRef(D));
@@ -4843,11 +4896,7 @@
Stream.EmitRecord(DECL_UPDATES, Record);
- // Flush any statements that were written as part of this update record.
- FlushStmts();
-
- // Flush C++ base specifiers, if there are any.
- FlushCXXBaseSpecifiers();
+ FlushPendingAfterDecl();
}
}
@@ -4959,8 +5008,16 @@
AddDeclRef(Temp->getDestructor(), Record);
}
+void ASTWriter::AddCXXCtorInitializersRef(ArrayRef<CXXCtorInitializer *> Inits,
+ RecordDataImpl &Record) {
+ assert(!Inits.empty() && "Empty ctor initializer sets are not recorded");
+ CXXCtorInitializersToWrite.push_back(
+ QueuedCXXCtorInitializers(NextCXXCtorInitializersID, Inits));
+ Record.push_back(NextCXXCtorInitializersID++);
+}
+
void ASTWriter::AddCXXBaseSpecifiersRef(CXXBaseSpecifier const *Bases,
- CXXBaseSpecifier const *BasesEnd,
+ CXXBaseSpecifier const *BasesEnd,
RecordDataImpl &Record) {
assert(Bases != BasesEnd && "Empty base-specifier sets are not recorded");
CXXBaseSpecifiersToWrite.push_back(
@@ -5035,46 +5092,40 @@
Record.push_back(GetOrCreateTypeID(T));
}
-TypeID ASTWriter::GetOrCreateTypeID( QualType T) {
+TypeID ASTWriter::GetOrCreateTypeID(QualType T) {
assert(Context);
- return MakeTypeID(*Context, T,
- std::bind1st(std::mem_fun(&ASTWriter::GetOrCreateTypeIdx), this));
+ return MakeTypeID(*Context, T, [&](QualType T) -> TypeIdx {
+ if (T.isNull())
+ return TypeIdx();
+ assert(!T.getLocalFastQualifiers());
+
+ TypeIdx &Idx = TypeIdxs[T];
+ if (Idx.getIndex() == 0) {
+ if (DoneWritingDeclsAndTypes) {
+ assert(0 && "New type seen after serializing all the types to emit!");
+ return TypeIdx();
+ }
+
+ // We haven't seen this type before. Assign it a new ID and put it
+ // into the queue of types to emit.
+ Idx = TypeIdx(NextTypeID++);
+ DeclTypesToEmit.push(T);
+ }
+ return Idx;
+ });
}
TypeID ASTWriter::getTypeID(QualType T) const {
assert(Context);
- return MakeTypeID(*Context, T,
- std::bind1st(std::mem_fun(&ASTWriter::getTypeIdx), this));
-}
-
-TypeIdx ASTWriter::GetOrCreateTypeIdx(QualType T) {
- if (T.isNull())
- return TypeIdx();
- assert(!T.getLocalFastQualifiers());
-
- TypeIdx &Idx = TypeIdxs[T];
- if (Idx.getIndex() == 0) {
- if (DoneWritingDeclsAndTypes) {
- assert(0 && "New type seen after serializing all the types to emit!");
+ return MakeTypeID(*Context, T, [&](QualType T) -> TypeIdx {
+ if (T.isNull())
return TypeIdx();
- }
+ assert(!T.getLocalFastQualifiers());
- // We haven't seen this type before. Assign it a new ID and put it
- // into the queue of types to emit.
- Idx = TypeIdx(NextTypeID++);
- DeclTypesToEmit.push(T);
- }
- return Idx;
-}
-
-TypeIdx ASTWriter::getTypeIdx(QualType T) const {
- if (T.isNull())
- return TypeIdx();
- assert(!T.getLocalFastQualifiers());
-
- TypeIdxMap::const_iterator I = TypeIdxs.find(T);
- assert(I != TypeIdxs.end() && "Type not emitted!");
- return I->second;
+ TypeIdxMap::const_iterator I = TypeIdxs.find(T);
+ assert(I != TypeIdxs.end() && "Type not emitted!");
+ return I->second;
+ });
}
void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) {
@@ -5527,7 +5578,8 @@
void ASTWriter::FlushCXXBaseSpecifiers() {
RecordData Record;
- for (unsigned I = 0, N = CXXBaseSpecifiersToWrite.size(); I != N; ++I) {
+ unsigned N = CXXBaseSpecifiersToWrite.size();
+ for (unsigned I = 0; I != N; ++I) {
Record.clear();
// Record the offset of this base-specifier set.
@@ -5551,6 +5603,8 @@
FlushStmts();
}
+ assert(N == CXXBaseSpecifiersToWrite.size() &&
+ "added more base specifiers while writing base specifiers");
CXXBaseSpecifiersToWrite.clear();
}
@@ -5592,6 +5646,36 @@
}
}
+void ASTWriter::FlushCXXCtorInitializers() {
+ RecordData Record;
+
+ unsigned N = CXXCtorInitializersToWrite.size();
+ (void)N; // Silence unused warning in non-assert builds.
+ for (auto &Init : CXXCtorInitializersToWrite) {
+ Record.clear();
+
+ // Record the offset of this mem-initializer list.
+ unsigned Index = Init.ID - 1;
+ if (Index == CXXCtorInitializersOffsets.size())
+ CXXCtorInitializersOffsets.push_back(Stream.GetCurrentBitNo());
+ else {
+ if (Index > CXXCtorInitializersOffsets.size())
+ CXXCtorInitializersOffsets.resize(Index + 1);
+ CXXCtorInitializersOffsets[Index] = Stream.GetCurrentBitNo();
+ }
+
+ AddCXXCtorInitializers(Init.Inits.data(), Init.Inits.size(), Record);
+ Stream.EmitRecord(serialization::DECL_CXX_CTOR_INITIALIZERS, Record);
+
+ // Flush any expressions that were written as part of the initializers.
+ FlushStmts();
+ }
+
+ assert(N == CXXCtorInitializersToWrite.size() &&
+ "added more ctor initializers while writing ctor initializers");
+ CXXCtorInitializersToWrite.clear();
+}
+
void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record) {
auto &Data = D->data();
Record.push_back(Data.IsLambda);
@@ -5697,6 +5781,8 @@
Chain = Reader;
+ // Note, this will get called multiple times, once one the reader starts up
+ // and again each time it's done reading a PCH or module.
FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls();
FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes();
FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers();
@@ -5781,7 +5867,7 @@
assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!");
assert(!WritingAST && "Already writing the AST!");
- AddUpdatedDeclContext(DC);
+ UpdatedDeclContexts.insert(DC);
UpdatingVisibleDecls.push_back(D);
}
@@ -5835,21 +5921,36 @@
}
void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) {
- assert(!WritingAST && "Already writing the AST!");
- FD = FD->getCanonicalDecl();
- if (!FD->isFromASTFile())
- return; // Not a function declared in PCH and defined outside.
-
- DeclUpdates[FD].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC);
+ assert(!DoneWritingDeclsAndTypes && "Already done writing updates!");
+ if (!Chain) return;
+ Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) {
+ // If we don't already know the exception specification for this redecl
+ // chain, add an update record for it.
+ if (isUnresolvedExceptionSpec(cast<FunctionDecl>(D)
+ ->getType()
+ ->castAs<FunctionProtoType>()
+ ->getExceptionSpecType()))
+ DeclUpdates[D].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC);
+ });
}
void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) {
assert(!WritingAST && "Already writing the AST!");
- FD = FD->getCanonicalDecl();
- if (!FD->isFromASTFile())
- return; // Not a function declared in PCH and defined outside.
+ if (!Chain) return;
+ Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) {
+ DeclUpdates[D].push_back(
+ DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType));
+ });
+}
- DeclUpdates[FD].push_back(DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType));
+void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD,
+ const FunctionDecl *Delete) {
+ assert(!WritingAST && "Already writing the AST!");
+ assert(Delete && "Not given an operator delete");
+ if (!Chain) return;
+ Chain->forEachFormerlyCanonicalImportedDecl(DD, [&](const Decl *D) {
+ DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete));
+ });
}
void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
@@ -5866,8 +5967,7 @@
if (!D->isFromASTFile())
return;
- DeclUpdates[D].push_back(
- DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
+ DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
}
void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
@@ -5923,3 +6023,11 @@
DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE));
}
+
+void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D,
+ SourceLocation Loc) {
+ assert(!WritingAST && "Already writing the AST!");
+ assert(D->isHidden() && "expected a hidden declaration");
+ assert(D->isFromASTFile() && "hidden decl not from AST file");
+ DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_EXPORTED, Loc));
+}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 7f2e805..3632672 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -133,11 +133,66 @@
void AddFunctionDefinition(const FunctionDecl *FD) {
assert(FD->doesThisDeclarationHaveABody());
- if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
- Writer.AddCXXCtorInitializers(CD->CtorInitializers,
- CD->NumCtorInitializers, Record);
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ Record.push_back(CD->NumCtorInitializers);
+ if (CD->NumCtorInitializers)
+ Writer.AddCXXCtorInitializersRef(
+ llvm::makeArrayRef(CD->init_begin(), CD->init_end()), Record);
+ }
Writer.AddStmt(FD->getBody());
}
+
+ /// Get the specialization decl from an entry in the specialization list.
+ template <typename EntryType>
+ typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
+ getSpecializationDecl(EntryType &T) {
+ return RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::getDecl(&T);
+ }
+
+ /// Get the list of partial specializations from a template's common ptr.
+ template<typename T>
+ decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) {
+ return Common->PartialSpecializations;
+ }
+ ArrayRef<Decl> getPartialSpecializations(FunctionTemplateDecl::Common *) {
+ return None;
+ }
+
+ template<typename Decl>
+ void AddTemplateSpecializations(Decl *D) {
+ auto *Common = D->getCommonPtr();
+
+ // If we have any lazy specializations, and the external AST source is
+ // our chained AST reader, we can just write out the DeclIDs. Otherwise,
+ // we need to resolve them to actual declarations.
+ if (Writer.Chain != Writer.Context->getExternalSource() &&
+ Common->LazySpecializations) {
+ D->LoadLazySpecializations();
+ assert(!Common->LazySpecializations);
+ }
+
+ auto &Specializations = Common->Specializations;
+ auto &&PartialSpecializations = getPartialSpecializations(Common);
+ ArrayRef<DeclID> LazySpecializations;
+ if (auto *LS = Common->LazySpecializations)
+ LazySpecializations = ArrayRef<DeclID>(LS + 1, LS + 1 + LS[0]);
+
+ Record.push_back(Specializations.size() +
+ PartialSpecializations.size() +
+ LazySpecializations.size());
+ for (auto &Entry : Specializations) {
+ auto *D = getSpecializationDecl(Entry);
+ assert(D->isCanonicalDecl() && "non-canonical decl in set");
+ Writer.AddDeclRef(D, Record);
+ }
+ for (auto &Entry : PartialSpecializations) {
+ auto *D = getSpecializationDecl(Entry);
+ assert(D->isCanonicalDecl() && "non-canonical decl in set");
+ Writer.AddDeclRef(D, Record);
+ }
+ for (DeclID ID : LazySpecializations)
+ Record.push_back(ID);
+ }
};
}
@@ -157,7 +212,7 @@
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Record.push_back(FD->doesThisDeclarationHaveABody());
if (FD->doesThisDeclarationHaveABody())
- Writer.AddStmt(FD->getBody());
+ AddFunctionDefinition(FD);
}
}
@@ -188,7 +243,7 @@
while (auto *NS = dyn_cast<NamespaceDecl>(DC->getRedeclContext())) {
if (!NS->isFromASTFile())
break;
- Writer.AddUpdatedDeclContext(NS->getPrimaryContext());
+ Writer.UpdatedDeclContexts.insert(NS->getPrimaryContext());
if (!NS->isInlineNamespace())
break;
DC = NS->getParent();
@@ -659,8 +714,10 @@
Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
Record.push_back(D->hasNonZeroConstructors());
Record.push_back(D->hasDestructors());
- Writer.AddCXXCtorInitializers(D->IvarInitializers, D->NumIvarInitializers,
- Record);
+ Record.push_back(D->NumIvarInitializers);
+ if (D->NumIvarInitializers)
+ Writer.AddCXXCtorInitializersRef(
+ llvm::makeArrayRef(D->init_begin(), D->init_end()), Record);
Code = serialization::DECL_OBJC_IMPLEMENTATION;
}
@@ -921,17 +978,31 @@
if (Writer.hasChain() && !D->isOriginalNamespace() &&
D->getOriginalNamespace()->isFromASTFile()) {
NamespaceDecl *NS = D->getOriginalNamespace();
- Writer.AddUpdatedDeclContext(NS);
+ Writer.UpdatedDeclContexts.insert(NS);
- // Make sure all visible decls are written. They will be recorded later.
- if (StoredDeclsMap *Map = NS->buildLookup()) {
- for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
- D != DEnd; ++D) {
- DeclContext::lookup_result R = D->second.getLookupResult();
- for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
- ++I)
- Writer.GetDeclRef(*I);
- }
+ // Make sure all visible decls are written. They will be recorded later. We
+ // do this using a side data structure so we can sort the names into
+ // a deterministic order.
+ StoredDeclsMap *Map = NS->buildLookup();
+ SmallVector<std::pair<DeclarationName, DeclContext::lookup_result>, 16>
+ LookupResults;
+ LookupResults.reserve(Map->size());
+ for (auto &Entry : *Map)
+ LookupResults.push_back(
+ std::make_pair(Entry.first, Entry.second.getLookupResult()));
+
+ std::sort(LookupResults.begin(), LookupResults.end(), llvm::less_first());
+ for (auto &NameAndResult : LookupResults) {
+ DeclarationName Name = NameAndResult.first;
+ (void)Name;
+ assert(Name.getNameKind() != DeclarationName::CXXConstructorName &&
+ "Cannot have a constructor name in a namespace!");
+ assert(Name.getNameKind() != DeclarationName::CXXConversionFunctionName &&
+ "Cannot have a conversion function name in a namespace!");
+
+ DeclContext::lookup_result Result = NameAndResult.second;
+ for (NamedDecl *ND : Result)
+ Writer.GetDeclRef(ND);
}
}
@@ -1068,8 +1139,6 @@
Writer.AddDeclRef(D->getInheritedConstructor(), Record);
Record.push_back(D->IsExplicitSpecified);
- Writer.AddCXXCtorInitializers(D->CtorInitializers, D->NumCtorInitializers,
- Record);
Code = serialization::DECL_CXX_CONSTRUCTOR;
}
@@ -1077,7 +1146,7 @@
void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
VisitCXXMethodDecl(D);
- Writer.AddDeclRef(D->OperatorDelete, Record);
+ Writer.AddDeclRef(D->getOperatorDelete(), Record);
Code = serialization::DECL_CXX_DESTRUCTOR;
}
@@ -1172,24 +1241,8 @@
void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
- if (D->isFirstDecl()) {
- typedef llvm::FoldingSetVector<ClassTemplateSpecializationDecl> CTSDSetTy;
- CTSDSetTy &CTSDSet = D->getSpecializations();
- Record.push_back(CTSDSet.size());
- for (CTSDSetTy::iterator I=CTSDSet.begin(), E = CTSDSet.end(); I!=E; ++I) {
- assert(I->isCanonicalDecl() && "Expected only canonical decls in set");
- Writer.AddDeclRef(&*I, Record);
- }
-
- typedef llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl>
- CTPSDSetTy;
- CTPSDSetTy &CTPSDSet = D->getPartialSpecializations();
- Record.push_back(CTPSDSet.size());
- for (CTPSDSetTy::iterator I=CTPSDSet.begin(), E=CTPSDSet.end(); I!=E; ++I) {
- assert(I->isCanonicalDecl() && "Expected only canonical decls in set");
- Writer.AddDeclRef(&*I, Record);
- }
- }
+ if (D->isFirstDecl())
+ AddTemplateSpecializations(D);
Code = serialization::DECL_CLASS_TEMPLATE;
}
@@ -1247,26 +1300,8 @@
void ASTDeclWriter::VisitVarTemplateDecl(VarTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
- if (D->isFirstDecl()) {
- typedef llvm::FoldingSetVector<VarTemplateSpecializationDecl> VTSDSetTy;
- VTSDSetTy &VTSDSet = D->getSpecializations();
- Record.push_back(VTSDSet.size());
- for (VTSDSetTy::iterator I = VTSDSet.begin(), E = VTSDSet.end(); I != E;
- ++I) {
- assert(I->isCanonicalDecl() && "Expected only canonical decls in set");
- Writer.AddDeclRef(&*I, Record);
- }
-
- typedef llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>
- VTPSDSetTy;
- VTPSDSetTy &VTPSDSet = D->getPartialSpecializations();
- Record.push_back(VTPSDSet.size());
- for (VTPSDSetTy::iterator I = VTPSDSet.begin(), E = VTPSDSet.end(); I != E;
- ++I) {
- assert(I->isCanonicalDecl() && "Expected only canonical decls in set");
- Writer.AddDeclRef(&*I, Record);
- }
- }
+ if (D->isFirstDecl())
+ AddTemplateSpecializations(D);
Code = serialization::DECL_VAR_TEMPLATE;
}
@@ -1331,19 +1366,8 @@
void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
- if (D->isFirstDecl()) {
- // This FunctionTemplateDecl owns the CommonPtr; write it.
-
- // Write the function specialization declarations.
- Record.push_back(D->getSpecializations().size());
- for (llvm::FoldingSetVector<FunctionTemplateSpecializationInfo>::iterator
- I = D->getSpecializations().begin(),
- E = D->getSpecializations().end() ; I != E; ++I) {
- assert(I->Function->isCanonicalDecl() &&
- "Expected only canonical decls in set");
- Writer.AddDeclRef(I->Function, Record);
- }
- }
+ if (D->isFirstDecl())
+ AddTemplateSpecializations(D);
Code = serialization::DECL_FUNCTION_TEMPLATE;
}
@@ -1454,24 +1478,41 @@
assert(isRedeclarableDeclKind(static_cast<T *>(D)->getKind()) &&
"Not considered redeclarable?");
+ // There is more than one declaration of this entity, so we will need to
+ // write a redeclaration chain.
+ Writer.AddDeclRef(First, Record);
+ Writer.Redeclarations.insert(First);
+
auto *Previous = D->getPreviousDecl();
- auto *FirstToEmit = First;
- if (Context.getLangOpts().Modules && Writer.Chain && !Previous) {
- // In a modules build, we can have imported declarations after a local
- // canonical declaration. If we do, we want to treat the first imported
- // declaration as our canonical declaration on reload, in order to
- // rebuild the redecl chain in the right order.
+
+ // In a modules build, we can have imported declarations after a local
+ // canonical declaration. If this is the first local declaration, emit
+ // a list of all such imported declarations so that we can ensure they
+ // are loaded before we are. This allows us to rebuild the redecl chain
+ // in the right order on reload (all declarations imported by a module
+ // should be before all declarations provided by that module).
+ bool EmitImportedMergedCanonicalDecls = false;
+ if (Context.getLangOpts().Modules && Writer.Chain) {
+ auto *PreviousLocal = Previous;
+ while (PreviousLocal && PreviousLocal->isFromASTFile())
+ PreviousLocal = PreviousLocal->getPreviousDecl();
+ if (!PreviousLocal)
+ EmitImportedMergedCanonicalDecls = true;
+ }
+ if (EmitImportedMergedCanonicalDecls) {
+ llvm::SmallMapVector<ModuleFile*, Decl*, 16> FirstInModule;
for (auto *Redecl = MostRecent; Redecl;
Redecl = Redecl->getPreviousDecl())
if (Redecl->isFromASTFile())
- FirstToEmit = Redecl;
- }
-
- // There is more than one declaration of this entity, so we will need to
- // write a redeclaration chain.
- Writer.AddDeclRef(FirstToEmit, Record);
- Record.push_back(FirstToEmit != First);
- Writer.Redeclarations.insert(First);
+ FirstInModule[Writer.Chain->getOwningModuleFile(Redecl)] = Redecl;
+ // FIXME: If FirstInModule has entries for modules A and B, and B imports
+ // A (directly or indirectly), we don't need to write the entry for A.
+ Record.push_back(FirstInModule.size());
+ for (auto I = FirstInModule.rbegin(), E = FirstInModule.rend();
+ I != E; ++I)
+ Writer.AddDeclRef(I->second, Record);
+ } else
+ Record.push_back(0);
// Make sure that we serialize both the previous and the most-recent
// declarations, which (transitively) ensures that all declarations in the
@@ -2042,12 +2083,10 @@
D->getDeclKindName() + "'");
Stream.EmitRecord(W.Code, Record, W.AbbrevToUse);
- // Flush any expressions that were written as part of this declaration.
- FlushStmts();
-
- // Flush C++ base specifiers, if there are any.
- FlushCXXBaseSpecifiers();
-
+ // Flush any expressions, base specifiers, and ctor initializers that
+ // were written as part of this declaration.
+ FlushPendingAfterDecl();
+
// Note declarations that should be deserialized eagerly so that we can add
// them to a record in the AST file later.
if (isRequiredDecl(D, Context))
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index e980ce7..6e647c3 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -550,12 +550,13 @@
Record.push_back(E->getValueKind());
Record.push_back(E->getObjectKind());
Writer.AddStmt(E->getBase());
- Writer.AddDeclRef(E->getMemberDecl(), Record);
- Writer.AddSourceLocation(E->getMemberLoc(), Record);
- Record.push_back(E->isArrow());
- Writer.AddDeclarationNameLoc(E->MemberDNLoc,
- E->getMemberDecl()->getDeclName(), Record);
- Code = serialization::EXPR_MEMBER;
+ Writer.AddDeclRef(E->getMemberDecl(), Record);
+ Writer.AddSourceLocation(E->getMemberLoc(), Record);
+ Record.push_back(E->isArrow());
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddDeclarationNameLoc(E->MemberDNLoc,
+ E->getMemberDecl()->getDeclName(), Record);
+ Code = serialization::EXPR_MEMBER;
}
void ASTStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) {
@@ -1820,9 +1821,20 @@
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
- for (auto *VE : C->varlists())
+ for (auto *VE : C->varlists()) {
Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->inits()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->updates()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->finals()) {
+ Writer->Writer.AddStmt(VE);
+ }
Writer->Writer.AddStmt(C->getStep());
+ Writer->Writer.AddStmt(C->getCalcStep());
}
void OMPClauseWriter::VisitOMPAlignedClause(OMPAlignedClause *C) {
@@ -1846,6 +1858,12 @@
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
for (auto *VE : C->varlists())
Writer->Writer.AddStmt(VE);
+ for (auto *E : C->source_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->destination_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->assignment_ops())
+ Writer->Writer.AddStmt(E);
}
void OMPClauseWriter::VisitOMPFlushClause(OMPFlushClause *C) {
@@ -1987,7 +2005,9 @@
VisitStmt(D);
Record.push_back(D->getNumClauses());
VisitOMPExecutableDirective(D);
+ Record.push_back(D->getOpKind());
Writer.AddStmt(D->getX());
+ Writer.AddStmt(D->getXRVal());
Writer.AddStmt(D->getV());
Writer.AddStmt(D->getExpr());
Code = serialization::STMT_OMP_ATOMIC_DIRECTIVE;
diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp
index 4791388..1b52b44 100644
--- a/lib/Serialization/GlobalModuleIndex.cpp
+++ b/lib/Serialization/GlobalModuleIndex.cpp
@@ -757,7 +757,7 @@
Record.clear();
Record.push_back(IDENTIFIER_INDEX);
Record.push_back(BucketOffset);
- Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str());
+ Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable);
}
Stream.ExitBlock();
@@ -841,12 +841,12 @@
return EC_IOError;
// Remove the old index file. It isn't relevant any more.
- llvm::sys::fs::remove(IndexPath.str());
+ llvm::sys::fs::remove(IndexPath);
// Rename the newly-written index file to the proper name.
- if (llvm::sys::fs::rename(IndexTmpPath.str(), IndexPath.str())) {
+ if (llvm::sys::fs::rename(IndexTmpPath, IndexPath)) {
// Rename failed; just remove the
- llvm::sys::fs::remove(IndexTmpPath.str());
+ llvm::sys::fs::remove(IndexTmpPath);
return EC_IOError;
}
diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
index 6c48a41..3b237d5 100644
--- a/lib/Serialization/Module.cpp
+++ b/lib/Serialization/Module.cpp
@@ -38,6 +38,7 @@
SelectorLookupTableData(nullptr), SelectorLookupTable(nullptr),
LocalNumDecls(0), DeclOffsets(nullptr), BaseDeclID(0),
LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(nullptr),
+ LocalNumCXXCtorInitializers(0), CXXCtorInitializersOffsets(nullptr),
FileSortedDecls(nullptr), NumFileSortedDecls(0),
RedeclarationsMap(nullptr), LocalNumRedeclarationsInMap(0),
ObjCCategoriesMap(nullptr), LocalNumObjCCategoriesInMap(0),
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index ac98ca0..a50c2b1 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/lib/Serialization/ModuleManager.cpp
@@ -58,8 +58,7 @@
unsigned Generation,
off_t ExpectedSize, time_t ExpectedModTime,
ASTFileSignature ExpectedSignature,
- std::function<ASTFileSignature(llvm::BitstreamReader &)>
- ReadSignature,
+ ASTFileSignatureReader ReadSignature,
ModuleFile *&Module,
std::string &ErrorStr) {
Module = nullptr;
@@ -227,6 +226,15 @@
InMemoryBuffers[Entry] = std::move(Buffer);
}
+bool ModuleManager::addKnownModuleFile(StringRef FileName) {
+ const FileEntry *File;
+ if (lookupModuleFile(FileName, 0, 0, File))
+ return true;
+ if (!Modules.count(File))
+ AdditionalKnownModuleFiles.insert(File);
+ return false;
+}
+
ModuleManager::VisitState *ModuleManager::allocateVisitState() {
// Fast path: if we have a cached state, use it.
if (FirstVisitState) {
@@ -263,6 +271,8 @@
}
void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
+ AdditionalKnownModuleFiles.remove(MF->File);
+
if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
return;
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 45768b2..0beb917 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -28,6 +28,7 @@
static bool isArc4RandomAvailable(const ASTContext &Ctx) {
const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
return T.getVendor() == llvm::Triple::Apple ||
+ T.getOS() == llvm::Triple::CloudABI ||
T.getOS() == llvm::Triple::FreeBSD ||
T.getOS() == llvm::Triple::NetBSD ||
T.getOS() == llvm::Triple::OpenBSD ||
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index ba5b4fa..d1d6ac2 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -295,7 +295,7 @@
HelpText<"Check calls to various UNIX/Posix functions">,
DescFile<"UnixAPIChecker.cpp">;
-def MallocPessimistic : Checker<"Malloc">,
+def MallocChecker: Checker<"Malloc">,
HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().">,
DescFile<"MallocChecker.cpp">;
@@ -315,10 +315,6 @@
HelpText<"Check improper use of chroot">,
DescFile<"ChrootChecker.cpp">;
-def MallocOptimistic : Checker<"MallocWithAnnotations">,
- HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free(). Assumes that all user-defined functions which might free a pointer are annotated.">,
- DescFile<"MallocChecker.cpp">;
-
def PthreadLockChecker : Checker<"PthreadLock">,
HelpText<"Simple lock -> unlock checker">,
DescFile<"PthreadLockChecker.cpp">;
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index 4ee0223..2e442c7 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -162,7 +162,7 @@
os.flush();
BugReport *report =
new BugReport(*BT_null,
- buf.empty() ? BT_null->getDescription() : buf.str(),
+ buf.empty() ? BT_null->getDescription() : StringRef(buf),
N);
bugreporter::trackNullOrUndefValue(N, bugreporter::getDerefExpr(S), *report);
diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
index 1926600..02c1209 100644
--- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -336,7 +336,7 @@
llvm::raw_svector_ostream os(PropNameWithUnderscore);
os << '_' << PropName;
}
- if (IvarName == PropNameWithUnderscore.str())
+ if (IvarName == PropNameWithUnderscore)
return Iv;
}
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 0930808..4155998 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -161,17 +161,16 @@
{
public:
MallocChecker()
- : II_alloca(nullptr), II_alloca_builtin(nullptr), II_malloc(nullptr),
- II_free(nullptr), II_realloc(nullptr), II_calloc(nullptr),
- II_valloc(nullptr), II_reallocf(nullptr), II_strndup(nullptr),
- II_strdup(nullptr), II_kmalloc(nullptr), II_if_nameindex(nullptr),
+ : II_alloca(nullptr), II_malloc(nullptr), II_free(nullptr),
+ II_realloc(nullptr), II_calloc(nullptr), II_valloc(nullptr),
+ II_reallocf(nullptr), II_strndup(nullptr), II_strdup(nullptr),
+ II_kmalloc(nullptr), II_if_nameindex(nullptr),
II_if_freenameindex(nullptr) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
enum CheckKind {
- CK_MallocPessimistic,
- CK_MallocOptimistic,
+ CK_MallocChecker,
CK_NewDeleteChecker,
CK_NewDeleteLeaksChecker,
CK_MismatchedDeallocatorChecker,
@@ -184,9 +183,10 @@
MOK_Any
};
+ DefaultBool IsOptimistic;
+
DefaultBool ChecksEnabled[CK_NumCheckKinds];
CheckName CheckNames[CK_NumCheckKinds];
- typedef llvm::SmallVector<CheckKind, CK_NumCheckKinds> CKVecTy;
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -222,9 +222,9 @@
mutable std::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds];
mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
- mutable IdentifierInfo *II_alloca, *II_alloca_builtin, *II_malloc, *II_free,
- *II_realloc, *II_calloc, *II_valloc, *II_reallocf,
- *II_strndup, *II_strdup, *II_kmalloc, *II_if_nameindex,
+ mutable IdentifierInfo *II_alloca, *II_malloc, *II_free, *II_realloc,
+ *II_calloc, *II_valloc, *II_reallocf, *II_strndup,
+ *II_strdup, *II_kmalloc, *II_if_nameindex,
*II_if_freenameindex;
mutable Optional<uint64_t> KernelZeroFlagVal;
@@ -332,16 +332,15 @@
///@{
/// Tells if a given family/call/symbol is tracked by the current checker.
- /// Looks through incoming CheckKind(s) and returns the kind of the checker
- /// responsible for this family/call/symbol.
- Optional<CheckKind> getCheckIfTracked(CheckKind CK,
- AllocationFamily Family) const;
- Optional<CheckKind> getCheckIfTracked(CKVecTy CKVec,
- AllocationFamily Family) const;
- Optional<CheckKind> getCheckIfTracked(CKVecTy CKVec, CheckerContext &C,
- const Stmt *AllocDeallocStmt) const;
- Optional<CheckKind> getCheckIfTracked(CKVecTy CKVec, CheckerContext &C,
- SymbolRef Sym) const;
+ /// Sets CheckKind to the kind of the checker responsible for this
+ /// family/call/symbol.
+ Optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
+ bool IsALeakCheck = false) const;
+ Optional<CheckKind> getCheckIfTracked(CheckerContext &C,
+ const Stmt *AllocDeallocStmt,
+ bool IsALeakCheck = false) const;
+ Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
+ bool IsALeakCheck = false) const;
///@}
static bool SummarizeValue(raw_ostream &os, SVal V);
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
@@ -508,7 +507,6 @@
if (II_malloc)
return;
II_alloca = &Ctx.Idents.get("alloca");
- II_alloca_builtin = &Ctx.Idents.get("__builtin_alloca");
II_malloc = &Ctx.Idents.get("malloc");
II_free = &Ctx.Idents.get("free");
II_realloc = &Ctx.Idents.get("realloc");
@@ -577,7 +575,7 @@
}
if (Family == AF_Alloca && CheckAlloc) {
- if (FunI == II_alloca || FunI == II_alloca_builtin)
+ if (FunI == II_alloca)
return true;
}
}
@@ -585,7 +583,7 @@
if (Family != AF_Malloc)
return false;
- if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs()) {
+ if (IsOptimistic && FD->hasAttrs()) {
for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
if(OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds) {
@@ -763,7 +761,7 @@
State = MallocUpdateRefState(C, CE, State);
} else if (FunI == II_strndup) {
State = MallocUpdateRefState(C, CE, State);
- } else if (FunI == II_alloca || FunI == II_alloca_builtin) {
+ } else if (FunI == II_alloca) {
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
AF_Alloca);
} else if (isStandardNewDelete(FD, C.getASTContext())) {
@@ -792,8 +790,7 @@
}
}
- if (ChecksEnabled[CK_MallocOptimistic] ||
- ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
+ if (IsOptimistic || ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
// Check all the attributes, if there are any.
// There can be multiple of these attributes.
if (FD->hasAttrs())
@@ -1248,7 +1245,8 @@
const MemSpaceRegion *MS = R->getMemorySpace();
- // Parameters, locals, statics and globals shouldn't be freed.
+ // Parameters, locals, statics, globals, and memory returned by
+ // __builtin_alloca() shouldn't be freed.
if (!(isa<UnknownSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS))) {
// FIXME: at the time this code was written, malloc() regions were
// represented by conjured symbols, which are all in UnknownSpaceRegion.
@@ -1257,8 +1255,12 @@
// Of course, free() can work on memory allocated outside the current
// function, so UnknownSpaceRegion is always a possibility.
// False negatives are better than false positives.
-
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
+
+ if (isa<AllocaRegion>(R))
+ ReportFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
+ else
+ ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
+
return nullptr;
}
@@ -1343,33 +1345,26 @@
}
Optional<MallocChecker::CheckKind>
-MallocChecker::getCheckIfTracked(MallocChecker::CheckKind CK,
- AllocationFamily Family) const {
-
- if (CK == CK_NumCheckKinds || !ChecksEnabled[CK])
- return Optional<MallocChecker::CheckKind>();
-
- // C/C++ checkers.
- if (CK == CK_MismatchedDeallocatorChecker)
- return CK;
-
+MallocChecker::getCheckIfTracked(AllocationFamily Family,
+ bool IsALeakCheck) const {
switch (Family) {
case AF_Malloc:
- case AF_IfNameIndex:
- case AF_Alloca: {
- // C checkers.
- if (CK == CK_MallocOptimistic ||
- CK == CK_MallocPessimistic) {
- return CK;
- }
+ case AF_Alloca:
+ case AF_IfNameIndex: {
+ if (ChecksEnabled[CK_MallocChecker])
+ return CK_MallocChecker;
+
return Optional<MallocChecker::CheckKind>();
}
case AF_CXXNew:
case AF_CXXNewArray: {
- // C++ checkers.
- if (CK == CK_NewDeleteChecker ||
- CK == CK_NewDeleteLeaksChecker) {
- return CK;
+ if (IsALeakCheck) {
+ if (ChecksEnabled[CK_NewDeleteLeaksChecker])
+ return CK_NewDeleteLeaksChecker;
+ }
+ else {
+ if (ChecksEnabled[CK_NewDeleteChecker])
+ return CK_NewDeleteChecker;
}
return Optional<MallocChecker::CheckKind>();
}
@@ -1380,45 +1375,20 @@
llvm_unreachable("unhandled family");
}
-static MallocChecker::CKVecTy MakeVecFromCK(MallocChecker::CheckKind CK1,
- MallocChecker::CheckKind CK2 = MallocChecker::CK_NumCheckKinds,
- MallocChecker::CheckKind CK3 = MallocChecker::CK_NumCheckKinds,
- MallocChecker::CheckKind CK4 = MallocChecker::CK_NumCheckKinds) {
- MallocChecker::CKVecTy CKVec;
- CKVec.push_back(CK1);
- if (CK2 != MallocChecker::CK_NumCheckKinds) {
- CKVec.push_back(CK2);
- if (CK3 != MallocChecker::CK_NumCheckKinds) {
- CKVec.push_back(CK3);
- if (CK4 != MallocChecker::CK_NumCheckKinds)
- CKVec.push_back(CK4);
- }
- }
- return CKVec;
+Optional<MallocChecker::CheckKind>
+MallocChecker::getCheckIfTracked(CheckerContext &C,
+ const Stmt *AllocDeallocStmt,
+ bool IsALeakCheck) const {
+ return getCheckIfTracked(getAllocationFamily(C, AllocDeallocStmt),
+ IsALeakCheck);
}
Optional<MallocChecker::CheckKind>
-MallocChecker::getCheckIfTracked(CKVecTy CKVec, AllocationFamily Family) const {
- for (auto CK: CKVec) {
- auto RetCK = getCheckIfTracked(CK, Family);
- if (RetCK.hasValue())
- return RetCK;
- }
- return Optional<MallocChecker::CheckKind>();
-}
-
-Optional<MallocChecker::CheckKind>
-MallocChecker::getCheckIfTracked(CKVecTy CKVec, CheckerContext &C,
- const Stmt *AllocDeallocStmt) const {
- return getCheckIfTracked(CKVec, getAllocationFamily(C, AllocDeallocStmt));
-}
-
-Optional<MallocChecker::CheckKind>
-MallocChecker::getCheckIfTracked(CKVecTy CKVec, CheckerContext &C,
- SymbolRef Sym) const {
+MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
+ bool IsALeakCheck) const {
const RefState *RS = C.getState()->get<RegionState>(Sym);
assert(RS);
- return getCheckIfTracked(CKVec, RS->getAllocationFamily());
+ return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
}
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
@@ -1512,10 +1482,12 @@
SourceRange Range,
const Expr *DeallocExpr) const {
- auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
- CK_MallocPessimistic,
- CK_NewDeleteChecker),
- C, DeallocExpr);
+ if (!ChecksEnabled[CK_MallocChecker] &&
+ !ChecksEnabled[CK_NewDeleteChecker])
+ return;
+
+ Optional<MallocChecker::CheckKind> CheckKind =
+ getCheckIfTracked(C, DeallocExpr);
if (!CheckKind.hasValue())
return;
@@ -1555,11 +1527,13 @@
void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
SourceRange Range) const {
- auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
- CK_MallocPessimistic,
- CK_MismatchedDeallocatorChecker),
- AF_Alloca);
- if (!CheckKind.hasValue())
+ Optional<MallocChecker::CheckKind> CheckKind;
+
+ if (ChecksEnabled[CK_MallocChecker])
+ CheckKind = CK_MallocChecker;
+ else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])
+ CheckKind = CK_MismatchedDeallocatorChecker;
+ else
return;
if (ExplodedNode *N = C.generateSink()) {
@@ -1635,10 +1609,12 @@
const Expr *AllocExpr) const {
- auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
- CK_MallocPessimistic,
- CK_NewDeleteChecker),
- C, AllocExpr);
+ if (!ChecksEnabled[CK_MallocChecker] &&
+ !ChecksEnabled[CK_NewDeleteChecker])
+ return;
+
+ Optional<MallocChecker::CheckKind> CheckKind =
+ getCheckIfTracked(C, AllocExpr);
if (!CheckKind.hasValue())
return;
@@ -1688,10 +1664,11 @@
void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
SymbolRef Sym) const {
- auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
- CK_MallocPessimistic,
- CK_NewDeleteChecker),
- C, Sym);
+ if (!ChecksEnabled[CK_MallocChecker] &&
+ !ChecksEnabled[CK_NewDeleteChecker])
+ return;
+
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
if (!CheckKind.hasValue())
return;
@@ -1714,10 +1691,11 @@
bool Released, SymbolRef Sym,
SymbolRef PrevSym) const {
- auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
- CK_MallocPessimistic,
- CK_NewDeleteChecker),
- C, Sym);
+ if (!ChecksEnabled[CK_MallocChecker] &&
+ !ChecksEnabled[CK_NewDeleteChecker])
+ return;
+
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
if (!CheckKind.hasValue())
return;
@@ -1742,8 +1720,10 @@
void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
- auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_NewDeleteChecker),
- C, Sym);
+ if (!ChecksEnabled[CK_NewDeleteChecker])
+ return;
+
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
if (!CheckKind.hasValue())
return;
@@ -1930,10 +1910,20 @@
void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
CheckerContext &C) const {
- auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
- CK_MallocPessimistic,
- CK_NewDeleteLeaksChecker),
- C, Sym);
+ if (!ChecksEnabled[CK_MallocChecker] &&
+ !ChecksEnabled[CK_NewDeleteLeaksChecker])
+ return;
+
+ const RefState *RS = C.getState()->get<RegionState>(Sym);
+ assert(RS && "cannot leak an untracked symbol");
+ AllocationFamily Family = RS->getAllocationFamily();
+
+ if (Family == AF_Alloca)
+ return;
+
+ Optional<MallocChecker::CheckKind>
+ CheckKind = getCheckIfTracked(Family, true);
+
if (!CheckKind.hasValue())
return;
@@ -2054,8 +2044,7 @@
return;
ASTContext &Ctx = C.getASTContext();
- if ((ChecksEnabled[CK_MallocOptimistic] ||
- ChecksEnabled[CK_MallocPessimistic]) &&
+ if (ChecksEnabled[CK_MallocChecker] &&
(isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Free) ||
isCMemFunction(FD, Ctx, AF_IfNameIndex,
MemoryOperationKind::MOK_Free)))
@@ -2547,10 +2536,10 @@
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
const RefState *RefS = State->get<RegionState>(I.getKey());
AllocationFamily Family = RefS->getAllocationFamily();
- auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
- CK_MallocPessimistic,
- CK_NewDeleteChecker),
- Family);
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
+ if (!CheckKind.hasValue())
+ CheckKind = getCheckIfTracked(Family, true);
+
I.getKey()->dumpToStream(Out);
Out << " : ";
I.getData().dump(Out);
@@ -2564,6 +2553,8 @@
void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
registerCStringCheckerBasic(mgr);
MallocChecker *checker = mgr.registerChecker<MallocChecker>();
+ checker->IsOptimistic = mgr.getAnalyzerOptions().getBooleanOption(
+ "Optimistic", false, checker);
checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true;
checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] =
mgr.getCurrentCheckName();
@@ -2577,11 +2568,12 @@
void ento::register##name(CheckerManager &mgr) { \
registerCStringCheckerBasic(mgr); \
MallocChecker *checker = mgr.registerChecker<MallocChecker>(); \
+ checker->IsOptimistic = mgr.getAnalyzerOptions().getBooleanOption( \
+ "Optimistic", false, checker); \
checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
checker->CheckNames[MallocChecker::CK_##name] = mgr.getCurrentCheckName(); \
}
-REGISTER_CHECKER(MallocPessimistic)
-REGISTER_CHECKER(MallocOptimistic)
+REGISTER_CHECKER(MallocChecker)
REGISTER_CHECKER(NewDeleteChecker)
REGISTER_CHECKER(MismatchedDeallocatorChecker)
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 55c7a65..6b8596e 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -2844,6 +2844,40 @@
return nullptr;
}
+namespace {
+ enum Retaining_t {
+ NonRetaining,
+ Retaining
+ };
+}
+
+static Optional<Retaining_t> getRetainSemantics(const ObjCPropertyDecl *Prop) {
+ assert(Prop->getPropertyIvarDecl() &&
+ "should only be used for properties with synthesized implementations");
+
+ if (!Prop->hasWrittenStorageAttribute()) {
+ // Don't assume anything about the retain semantics of readonly properties.
+ if (Prop->isReadOnly())
+ return None;
+
+ // Don't assume anything about readwrite properties with manually-supplied
+ // setters.
+ const ObjCMethodDecl *Setter = Prop->getSetterMethodDecl();
+ bool HasManualSetter = std::any_of(Setter->redecls_begin(),
+ Setter->redecls_end(),
+ [](const Decl *SetterRedecl) -> bool {
+ return cast<ObjCMethodDecl>(SetterRedecl)->hasBody();
+ });
+ if (HasManualSetter)
+ return None;
+
+ // If the setter /is/ synthesized, we're already relying on the retain
+ // semantics of the property. Continue as normal.
+ }
+
+ return Prop->isRetaining() ? Retaining : NonRetaining;
+}
+
void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
CheckerContext &C) const {
Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
@@ -2882,9 +2916,11 @@
// Also don't do anything if the ivar is unretained. If so, we know that
// there's no outstanding retain count for the value.
- if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl()))
- if (!Prop->isRetaining())
- return;
+ if (Kind == RetEffect::ObjC)
+ if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl()))
+ if (auto retainSemantics = getRetainSemantics(Prop))
+ if (retainSemantics.getValue() == NonRetaining)
+ return;
// Note that this value has been loaded from an ivar.
C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess()));
@@ -2899,12 +2935,21 @@
return;
}
- // Try to find the property associated with this ivar.
- const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl());
+ bool didUpdateState = false;
+ if (Kind == RetEffect::ObjC) {
+ // Check if the ivar is known to be unretained. If so, we know that
+ // there's no outstanding retain count for the value.
+ if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl())) {
+ if (auto retainSemantics = getRetainSemantics(Prop)) {
+ if (retainSemantics.getValue() == NonRetaining) {
+ State = setRefBinding(State, Sym, PlusZero);
+ didUpdateState = true;
+ }
+ }
+ }
+ }
- if (Prop && !Prop->isRetaining())
- State = setRefBinding(State, Sym, PlusZero);
- else
+ if (!didUpdateState)
State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
C.addTransition(State);
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index d717e3f..1696bcf 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -13,12 +13,14 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+using namespace ento;
using namespace llvm;
AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() {
@@ -100,12 +102,37 @@
static StringRef toString(bool b) { return b ? "true" : "false"; }
-bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) {
+StringRef AnalyzerOptions::getCheckerOption(StringRef CheckerName,
+ StringRef OptionName,
+ StringRef Default,
+ bool SearchInParents) {
+ // Search for a package option if the option for the checker is not specified
+ // and search in parents is enabled.
+ ConfigTable::const_iterator E = Config.end();
+ do {
+ ConfigTable::const_iterator I =
+ Config.find((Twine(CheckerName) + ":" + OptionName).str());
+ if (I != E)
+ return StringRef(I->getValue());
+ size_t Pos = CheckerName.rfind('.');
+ if (Pos == StringRef::npos)
+ return Default;
+ CheckerName = CheckerName.substr(0, Pos);
+ } while (!CheckerName.empty() && SearchInParents);
+ return Default;
+}
+
+bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal,
+ const CheckerBase *C,
+ bool SearchInParents) {
// FIXME: We should emit a warning here if the value is something other than
// "true", "false", or the empty string (meaning the default value),
// but the AnalyzerOptions doesn't have access to a diagnostic engine.
+ StringRef Default = toString(DefaultVal);
StringRef V =
- Config.insert(std::make_pair(Name, toString(DefaultVal))).first->second;
+ C ? getCheckerOption(C->getTagDescription(), Name, Default,
+ SearchInParents)
+ : StringRef(Config.insert(std::make_pair(Name, Default)).first->second);
return llvm::StringSwitch<bool>(V)
.Case("true", true)
.Case("false", false)
@@ -113,9 +140,10 @@
}
bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name,
- bool DefaultVal) {
+ bool DefaultVal, const CheckerBase *C,
+ bool SearchInParents) {
if (!V.hasValue())
- V = getBooleanOption(Name, DefaultVal);
+ V = getBooleanOption(Name, DefaultVal, C, SearchInParents);
return V.getValue();
}
@@ -199,19 +227,35 @@
/* Default = */ false);
}
-int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
+int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal,
+ const CheckerBase *C,
+ bool SearchInParents) {
SmallString<10> StrBuf;
llvm::raw_svector_ostream OS(StrBuf);
OS << DefaultVal;
- StringRef V = Config.insert(std::make_pair(Name, OS.str())).first->second;
+ StringRef V = C ? getCheckerOption(C->getTagDescription(), Name, OS.str(),
+ SearchInParents)
+ : StringRef(Config.insert(std::make_pair(Name, OS.str()))
+ .first->second);
+
int Res = DefaultVal;
bool b = V.getAsInteger(10, Res);
assert(!b && "analyzer-config option should be numeric");
- (void) b;
+ (void)b;
return Res;
}
+StringRef AnalyzerOptions::getOptionAsString(StringRef Name,
+ StringRef DefaultVal,
+ const CheckerBase *C,
+ bool SearchInParents) {
+ return C ? getCheckerOption(C->getTagDescription(), Name, DefaultVal,
+ SearchInParents)
+ : StringRef(
+ Config.insert(std::make_pair(Name, DefaultVal)).first->second);
+}
+
unsigned AnalyzerOptions::getAlwaysInlineSize() {
if (!AlwaysInlineSize.hasValue())
AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3);
@@ -281,4 +325,3 @@
bool AnalyzerOptions::shouldConditionalizeStaticInitializers() {
return getBooleanOption("cfg-conditional-static-initializers", true);
}
-
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 5cdb7eb..8b7f18f 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -2648,17 +2648,6 @@
} // end llvm namespace
#endif
-#ifndef NDEBUG
-template <typename ITERATOR>
-ExplodedNode *GetGraphNode(ITERATOR I) { return *I; }
-
-template <> ExplodedNode*
-GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator>
- (llvm::DenseMap<ExplodedNode*, Expr*>::iterator I) {
- return I->first;
-}
-#endif
-
void ExprEngine::ViewGraph(bool trim) {
#ifndef NDEBUG
if (trim) {
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 88b5464..026cc02 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -282,7 +282,7 @@
llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");
if (std::error_code EC =
- llvm::sys::fs::createUniqueFile(Model.str(), FD, ResultPath)) {
+ llvm::sys::fs::createUniqueFile(Model, FD, ResultPath)) {
llvm::errs() << "warning: could not create file in '" << Directory
<< "': " << EC.message() << '\n';
return;
@@ -302,12 +302,12 @@
<< "-" << i << ".html";
llvm::sys::path::append(Model, Directory,
filename.str());
- EC = llvm::sys::fs::openFileForWrite(Model.str(),
+ EC = llvm::sys::fs::openFileForWrite(Model,
FD,
llvm::sys::fs::F_RW |
llvm::sys::fs::F_Excl);
if (EC && EC != std::errc::file_exists) {
- llvm::errs() << "warning: could not create file '" << Model.str()
+ llvm::errs() << "warning: could not create file '" << Model
<< "': " << EC.message() << '\n';
return;
}
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index b971fff..c490031 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -432,11 +432,15 @@
// Sort the diagnostics so that they are always emitted in a deterministic
// order.
- if (!BatchDiags.empty())
- std::sort(BatchDiags.begin(), BatchDiags.end(),
- [](const PathDiagnostic *X, const PathDiagnostic *Y) {
- return X != Y && compare(*X, *Y);
- });
+ int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) =
+ [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) {
+ assert(*X != *Y && "PathDiagnostics not uniqued!");
+ if (compare(**X, **Y))
+ return -1;
+ assert(compare(**Y, **X) && "Not a total order!");
+ return 1;
+ };
+ array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp);
FlushDiagnosticsImpl(BatchDiags, Files);
@@ -452,7 +456,7 @@
}
PathDiagnosticConsumer::FilesMade::~FilesMade() {
- for (PDFileEntry &Entry : *this)
+ for (PDFileEntry &Entry : Set)
Entry.~PDFileEntry();
}
@@ -462,11 +466,11 @@
llvm::FoldingSetNodeID NodeID;
NodeID.Add(PD);
void *InsertPos;
- PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
+ PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
if (!Entry) {
Entry = Alloc.Allocate<PDFileEntry>();
Entry = new (Entry) PDFileEntry(NodeID);
- InsertNode(Entry, InsertPos);
+ Set.InsertNode(Entry, InsertPos);
}
// Allocate persistent storage for the file name.
@@ -483,7 +487,7 @@
llvm::FoldingSetNodeID NodeID;
NodeID.Add(PD);
void *InsertPos;
- PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
+ PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
if (!Entry)
return nullptr;
return &Entry->files;
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 4505622..6d41fc2 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -767,7 +767,7 @@
typedef SmallVector<const FieldDecl *, 8> FieldVector;
-void getSymbolicOffsetFields(BindingKey K, FieldVector &Fields) {
+static void getSymbolicOffsetFields(BindingKey K, FieldVector &Fields) {
assert(K.hasSymbolicOffset() && "Not implemented for concrete offset keys");
const MemRegion *Base = K.getConcreteOffsetRegion();
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 6812b11..621718e 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -735,7 +735,7 @@
SmallString<128> P;
int FD;
llvm::sys::fs::createTemporaryFile("llvm_ubi", "", FD, P);
- llvm::errs() << "Writing '" << P.str() << "'.\n";
+ llvm::errs() << "Writing '" << P << "'.\n";
auto Stream = llvm::make_unique<llvm::raw_fd_ostream>(FD, true);
diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp
index 9a484c1..adae178 100644
--- a/lib/Tooling/CommonOptionsParser.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -54,6 +54,7 @@
"\tsuffix of a path in the compile command database.\n"
"\n";
+namespace {
class ArgumentsAdjustingCompilations : public CompilationDatabase {
public:
ArgumentsAdjustingCompilations(
@@ -89,6 +90,7 @@
return Commands;
}
};
+} // namespace
CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv,
cl::OptionCategory &Category,
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index 7613988..383fb1a 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -29,9 +29,8 @@
#include "llvm/Support/Path.h"
#include <sstream>
#include <system_error>
-
-namespace clang {
-namespace tooling {
+using namespace clang;
+using namespace tooling;
CompilationDatabase::~CompilationDatabase() {}
@@ -109,6 +108,7 @@
CompilationDatabasePlugin::~CompilationDatabasePlugin() {}
+namespace {
// Helper for recursively searching through a chain of actions and collecting
// all inputs, direct and indirect, of compile jobs.
struct CompileJobAnalyzer {
@@ -183,6 +183,7 @@
private:
ArrayRef<std::string> Arr;
};
+} // namespace
/// \brief Strips any positional args and possible argv[0] from a command-line
/// provided by the user to construct a FixedCompilationDatabase.
@@ -324,6 +325,9 @@
return std::vector<CompileCommand>();
}
+namespace clang {
+namespace tooling {
+
// This anchor is used to force the linker to link in the generated object file
// and thus register the JSONCompilationDatabasePlugin.
extern volatile int JSONAnchorSource;
diff --git a/lib/Tooling/FileMatchTrie.cpp b/lib/Tooling/FileMatchTrie.cpp
index dc9999e..86ed036 100644
--- a/lib/Tooling/FileMatchTrie.cpp
+++ b/lib/Tooling/FileMatchTrie.cpp
@@ -17,18 +17,20 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <sstream>
+using namespace clang;
+using namespace tooling;
-namespace clang {
-namespace tooling {
-
+namespace {
/// \brief Default \c PathComparator using \c llvm::sys::fs::equivalent().
struct DefaultPathComparator : public PathComparator {
- virtual ~DefaultPathComparator() {}
bool equivalent(StringRef FileA, StringRef FileB) const override {
return FileA == FileB || llvm::sys::fs::equivalent(FileA, FileB);
}
};
+}
+namespace clang {
+namespace tooling {
/// \brief A node of the \c FileMatchTrie.
///
/// Each node has storage for up to one path and a map mapping a path segment to
@@ -156,6 +158,8 @@
// The children of this node stored in a map based on the next path segment.
llvm::StringMap<FileMatchTrieNode> Children;
};
+} // end namespace tooling
+} // end namespace clang
FileMatchTrie::FileMatchTrie()
: Root(new FileMatchTrieNode), Comparator(new DefaultPathComparator()) {}
@@ -183,6 +187,3 @@
Error << "Path is ambiguous";
return Result;
}
-
-} // end namespace tooling
-} // end namespace clang
diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp
index 3b5f7e2..7dc211e 100644
--- a/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/lib/Tooling/JSONCompilationDatabase.cpp
@@ -176,7 +176,7 @@
std::string Error;
llvm::raw_string_ostream ES(Error);
- StringRef Match = MatchTrie.findEquivalent(NativeFilePath.str(), ES);
+ StringRef Match = MatchTrie.findEquivalent(NativeFilePath, ES);
if (Match.empty())
return std::vector<CompileCommand>();
llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
@@ -307,13 +307,13 @@
SmallString<128> AbsolutePath(
Directory->getValue(DirectoryStorage));
llvm::sys::path::append(AbsolutePath, FileName);
- llvm::sys::path::native(AbsolutePath.str(), NativeFilePath);
+ llvm::sys::path::native(AbsolutePath, NativeFilePath);
} else {
llvm::sys::path::native(FileName, NativeFilePath);
}
IndexByFile[NativeFilePath].push_back(
CompileCommandRef(Directory, Command));
- MatchTrie.insert(NativeFilePath.str());
+ MatchTrie.insert(NativeFilePath);
}
return true;
}