diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-05-29 16:25:46 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-05-29 16:25:46 +0000 |
commit | b5aee35cc5d62f11d98539f62e4fe63f0ac9edc6 (patch) | |
tree | 3e6ab962dbc73cfe1445a60d2eb4dfba7c939a22 /lib | |
parent | aa803409c3bd3930126db630c29f63d42f255153 (diff) | |
download | src-b5aee35cc5d62f11d98539f62e4fe63f0ac9edc6.tar.gz src-b5aee35cc5d62f11d98539f62e4fe63f0ac9edc6.zip |
Vendor import of clang trunk r304149:vendor/clang/clang-trunk-r304149
Notes
Notes:
svn path=/vendor/clang/dist/; revision=319142
svn path=/vendor/clang/clang-trunk-r304149/; revision=319143; tag=vendor/clang/clang-trunk-r304149
Diffstat (limited to 'lib')
61 files changed, 2167 insertions, 772 deletions
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 81cd1cc42658..032a20afa834 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -274,9 +274,17 @@ void Decl::setLexicalDeclContext(DeclContext *DC) { } else { getMultipleDC()->LexicalDC = DC; } - Hidden = cast<Decl>(DC)->Hidden; - if (Hidden && !isFromASTFile() && hasLocalOwningModuleStorage()) - setLocalOwningModule(cast<Decl>(DC)->getOwningModule()); + + // FIXME: We shouldn't be changing the lexical context of declarations + // imported from AST files. + if (!isFromASTFile()) { + Hidden = cast<Decl>(DC)->Hidden && hasLocalOwningModuleStorage(); + if (Hidden) + setLocalOwningModule(cast<Decl>(DC)->getOwningModule()); + } + + assert((!Hidden || getOwningModule()) && + "hidden declaration has no owning module"); } void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, @@ -440,8 +448,8 @@ const Attr *Decl::getDefiningAttr() const { return nullptr; } -StringRef getRealizedPlatform(const AvailabilityAttr *A, - const ASTContext &Context) { +static StringRef getRealizedPlatform(const AvailabilityAttr *A, + const ASTContext &Context) { // Check if this is an App Extension "platform", and if so chop off // the suffix for matching with the actual platform. StringRef RealizedPlatform = A->getPlatform()->getName(); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index bd8b3abd9275..c19812e341c0 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1230,8 +1230,7 @@ namespace { IsNullPtr = V.isNullPointer(); } - void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false, - bool IsNullPtr_ = false, uint64_t Offset_ = 0) { + void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) { #ifndef NDEBUG // We only allow a few types of invalid bases. Enforce that here. if (BInvalid) { @@ -1242,11 +1241,20 @@ namespace { #endif Base = B; - Offset = CharUnits::fromQuantity(Offset_); + Offset = CharUnits::fromQuantity(0); InvalidBase = BInvalid; CallIndex = I; Designator = SubobjectDesignator(getType(B)); - IsNullPtr = IsNullPtr_; + IsNullPtr = false; + } + + void setNull(QualType PointerTy, uint64_t TargetVal) { + Base = (Expr *)nullptr; + Offset = CharUnits::fromQuantity(TargetVal); + InvalidBase = false; + CallIndex = 0; + Designator = SubobjectDesignator(PointerTy->getPointeeType()); + IsNullPtr = true; } void setInvalid(APValue::LValueBase B, unsigned I = 0) { @@ -5494,8 +5502,8 @@ public: return true; } bool ZeroInitialization(const Expr *E) { - auto Offset = Info.Ctx.getTargetNullPointerValue(E->getType()); - Result.set((Expr*)nullptr, 0, false, true, Offset); + auto TargetVal = Info.Ctx.getTargetNullPointerValue(E->getType()); + Result.setNull(E->getType(), TargetVal); return true; } diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 6e14dd055cf8..cc7a6941f63a 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -1689,6 +1689,8 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, // ::= _N # bool // _O # <array in parameter> // ::= _T # __float80 (Intel) + // ::= _S # char16_t + // ::= _U # char32_t // ::= _W # wchar_t // ::= _Z # __float80 (Digital Mars) switch (T->getKind()) { diff --git a/lib/AST/StmtCXX.cpp b/lib/AST/StmtCXX.cpp index aade13ed3bd4..8466cd61f055 100644 --- a/lib/AST/StmtCXX.cpp +++ b/lib/AST/StmtCXX.cpp @@ -88,7 +88,7 @@ const VarDecl *CXXForRangeStmt::getLoopVariable() const { } CoroutineBodyStmt *CoroutineBodyStmt::Create( - const ASTContext &C, CoroutineBodyStmt::CtorArgs const& Args) { + const ASTContext &C, CoroutineBodyStmt::CtorArgs const &Args) { std::size_t Size = totalSizeToAlloc<Stmt *>( CoroutineBodyStmt::FirstParamMove + Args.ParamMoves.size()); @@ -108,6 +108,8 @@ CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args) SubStmts[CoroutineBodyStmt::Allocate] = Args.Allocate; SubStmts[CoroutineBodyStmt::Deallocate] = Args.Deallocate; SubStmts[CoroutineBodyStmt::ReturnValue] = Args.ReturnValue; + SubStmts[CoroutineBodyStmt::ResultDecl] = Args.ResultDecl; + SubStmts[CoroutineBodyStmt::ReturnStmt] = Args.ReturnStmt; SubStmts[CoroutineBodyStmt::ReturnStmtOnAllocFailure] = Args.ReturnStmtOnAllocFailure; std::copy(Args.ParamMoves.begin(), Args.ParamMoves.end(), diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index 6b58916162f6..7c0f5543da04 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -92,6 +92,8 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { IsAutosynthesized = false; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { Stmt *Body = FD->getBody(); + if (auto *CoroBody = dyn_cast_or_null<CoroutineBodyStmt>(Body)) + Body = CoroBody->getBody(); if (Manager && Manager->synthesizeBodies()) { Stmt *SynthesizedBody = getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(FD); diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index a6fd931cb174..ac3d7c559679 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -64,6 +64,7 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts, bool HasFeature = llvm::StringSwitch<bool>(Feature) .Case("altivec", LangOpts.AltiVec) .Case("blocks", LangOpts.Blocks) + .Case("coroutines", LangOpts.CoroutinesTS) .Case("cplusplus", LangOpts.CPlusPlus) .Case("cplusplus11", LangOpts.CPlusPlus11) .Case("freestanding", LangOpts.Freestanding) diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 156aa0b11f7d..c5cff74ac97d 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -183,48 +183,22 @@ unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) { return IterBool.first->second; } -/// AddLineNote - Add a line note to the line table that indicates that there -/// is a \#line at the specified FID/Offset location which changes the presumed -/// location to LineNo/FilenameID. -void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, - unsigned LineNo, int FilenameID) { - std::vector<LineEntry> &Entries = LineEntries[FID]; - - assert((Entries.empty() || Entries.back().FileOffset < Offset) && - "Adding line entries out of order!"); - - SrcMgr::CharacteristicKind Kind = SrcMgr::C_User; - unsigned IncludeOffset = 0; - - if (!Entries.empty()) { - // If this is a '#line 4' after '#line 42 "foo.h"', make sure to remember - // that we are still in "foo.h". - if (FilenameID == -1) - FilenameID = Entries.back().FilenameID; - - // If we are after a line marker that switched us to system header mode, or - // that set #include information, preserve it. - Kind = Entries.back().FileKind; - IncludeOffset = Entries.back().IncludeOffset; - } - - Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, Kind, - IncludeOffset)); -} - -/// AddLineNote This is the same as the previous version of AddLineNote, but is -/// used for GNU line markers. If EntryExit is 0, then this doesn't change the -/// presumed \#include stack. If it is 1, this is a file entry, if it is 2 then -/// this is a file exit. FileKind specifies whether this is a system header or -/// extern C system header. -void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, - unsigned LineNo, int FilenameID, - unsigned EntryExit, +/// Add a line note to the line table that indicates that there is a \#line or +/// GNU line marker at the specified FID/Offset location which changes the +/// presumed location to LineNo/FilenameID. If EntryExit is 0, then this doesn't +/// change the presumed \#include stack. If it is 1, this is a file entry, if +/// it is 2 then this is a file exit. FileKind specifies whether this is a +/// system header or extern C system header. +void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, unsigned LineNo, + int FilenameID, unsigned EntryExit, SrcMgr::CharacteristicKind FileKind) { - assert(FilenameID != -1 && "Unspecified filename should use other accessor"); - std::vector<LineEntry> &Entries = LineEntries[FID]; + // An unspecified FilenameID means use the last filename if available, or the + // main source file otherwise. + if (FilenameID == -1 && !Entries.empty()) + FilenameID = Entries.back().FilenameID; + assert((Entries.empty() || Entries.back().FileOffset < Offset) && "Adding line entries out of order!"); @@ -281,47 +255,20 @@ unsigned SourceManager::getLineTableFilenameID(StringRef Name) { return getLineTable().getLineTableFilenameID(Name); } - /// AddLineNote - Add a line note to the line table for the FileID and offset /// specified by Loc. If FilenameID is -1, it is considered to be /// unspecified. void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, - int FilenameID) { - std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); - - bool Invalid = false; - const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); - if (!Entry.isFile() || Invalid) - return; - - const SrcMgr::FileInfo &FileInfo = Entry.getFile(); - - // Remember that this file has #line directives now if it doesn't already. - const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives(); - - getLineTable().AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID); -} - -/// AddLineNote - Add a GNU line marker to the line table. -void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID, bool IsFileEntry, - bool IsFileExit, bool IsSystemHeader, - bool IsExternCHeader) { - // If there is no filename and no flags, this is treated just like a #line, - // which does not change the flags of the previous line marker. - if (FilenameID == -1) { - assert(!IsFileEntry && !IsFileExit && !IsSystemHeader && !IsExternCHeader && - "Can't set flags without setting the filename!"); - return AddLineNote(Loc, LineNo, FilenameID); - } - + bool IsFileExit, + SrcMgr::CharacteristicKind FileKind) { std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); bool Invalid = false; const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); if (!Entry.isFile() || Invalid) return; - + const SrcMgr::FileInfo &FileInfo = Entry.getFile(); // Remember that this file has #line directives now if it doesn't already. @@ -329,14 +276,6 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, (void) getLineTable(); - SrcMgr::CharacteristicKind FileKind; - if (IsExternCHeader) - FileKind = SrcMgr::C_ExternCSystem; - else if (IsSystemHeader) - FileKind = SrcMgr::C_System; - else - FileKind = SrcMgr::C_User; - unsigned EntryExit = 0; if (IsFileEntry) EntryExit = 1; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 1b9fbed17731..6be83d22a256 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -2169,15 +2169,20 @@ public: : DataLayoutStringR600); assert(DataLayout->getAllocaAddrSpace() == AS.Private); - AddrSpaceMap = - llvm::StringSwitch<const LangAS::Map *>(Triple.getEnvironmentName()) - .Case("opencl", &AMDGPUOpenCLPrivateIsZeroMap) - .Case("amdgiz", &AMDGPUNonOpenCLGenericIsZeroMap) - .Case("amdgizcl", &AMDGPUOpenCLGenericIsZeroMap) - .Default(&AMDGPUNonOpenCLPrivateIsZeroMap); UseAddrSpaceMapMangling = true; } + void adjust(LangOptions &Opts) override { + TargetInfo::adjust(Opts); + if (isGenericZero(getTriple())) { + AddrSpaceMap = Opts.OpenCL ? &AMDGPUOpenCLGenericIsZeroMap + : &AMDGPUNonOpenCLGenericIsZeroMap; + } else { + AddrSpaceMap = Opts.OpenCL ? &AMDGPUOpenCLPrivateIsZeroMap + : &AMDGPUNonOpenCLPrivateIsZeroMap; + } + } + uint64_t getPointerWidthV(unsigned AddrSpace) const override { if (GPU <= GK_CAYMAN) return 32; @@ -2619,6 +2624,7 @@ class X86TargetInfo : public TargetInfo { bool HasFMA = false; bool HasF16C = false; bool HasAVX512CD = false; + bool HasAVX512VPOPCNTDQ = false; bool HasAVX512ER = false; bool HasAVX512PF = false; bool HasAVX512DQ = false; @@ -3435,23 +3441,32 @@ void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features, switch (Level) { case AVX512F: Features["avx512f"] = true; + LLVM_FALLTHROUGH; case AVX2: Features["avx2"] = true; + LLVM_FALLTHROUGH; case AVX: Features["avx"] = true; Features["xsave"] = true; + LLVM_FALLTHROUGH; case SSE42: Features["sse4.2"] = true; + LLVM_FALLTHROUGH; case SSE41: Features["sse4.1"] = true; + LLVM_FALLTHROUGH; case SSSE3: Features["ssse3"] = true; + LLVM_FALLTHROUGH; case SSE3: Features["sse3"] = true; + LLVM_FALLTHROUGH; case SSE2: Features["sse2"] = true; + LLVM_FALLTHROUGH; case SSE1: Features["sse"] = true; + LLVM_FALLTHROUGH; case NoSSE: break; } @@ -3462,29 +3477,37 @@ void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features, case NoSSE: case SSE1: Features["sse"] = false; + LLVM_FALLTHROUGH; case SSE2: Features["sse2"] = Features["pclmul"] = Features["aes"] = Features["sha"] = false; + LLVM_FALLTHROUGH; case SSE3: Features["sse3"] = false; setXOPLevel(Features, NoXOP, false); + LLVM_FALLTHROUGH; case SSSE3: Features["ssse3"] = false; + LLVM_FALLTHROUGH; case SSE41: Features["sse4.1"] = false; + LLVM_FALLTHROUGH; case SSE42: Features["sse4.2"] = false; + LLVM_FALLTHROUGH; case AVX: Features["fma"] = Features["avx"] = Features["f16c"] = Features["xsave"] = Features["xsaveopt"] = false; setXOPLevel(Features, FMA4, false); + LLVM_FALLTHROUGH; case AVX2: Features["avx2"] = false; + LLVM_FALLTHROUGH; case AVX512F: Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] = - Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] = - Features["avx512vl"] = Features["avx512vbmi"] = - Features["avx512ifma"] = false; + Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] = + Features["avx512vl"] = Features["avx512vbmi"] = + Features["avx512ifma"] = Features["avx512vpopcntdq"] = false; } } @@ -3494,10 +3517,13 @@ void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features, switch (Level) { case AMD3DNowAthlon: Features["3dnowa"] = true; + LLVM_FALLTHROUGH; case AMD3DNow: Features["3dnow"] = true; + LLVM_FALLTHROUGH; case MMX: Features["mmx"] = true; + LLVM_FALLTHROUGH; case NoMMX3DNow: break; } @@ -3508,8 +3534,10 @@ void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features, case NoMMX3DNow: case MMX: Features["mmx"] = false; + LLVM_FALLTHROUGH; case AMD3DNow: Features["3dnow"] = false; + LLVM_FALLTHROUGH; case AMD3DNowAthlon: Features["3dnowa"] = false; } @@ -3521,12 +3549,15 @@ void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level, switch (Level) { case XOP: Features["xop"] = true; + LLVM_FALLTHROUGH; case FMA4: Features["fma4"] = true; setSSELevel(Features, AVX, true); + LLVM_FALLTHROUGH; case SSE4A: Features["sse4a"] = true; setSSELevel(Features, SSE3, true); + LLVM_FALLTHROUGH; case NoXOP: break; } @@ -3537,8 +3568,10 @@ void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level, case NoXOP: case SSE4A: Features["sse4a"] = false; + LLVM_FALLTHROUGH; case FMA4: Features["fma4"] = false; + LLVM_FALLTHROUGH; case XOP: Features["xop"] = false; } @@ -3584,7 +3617,8 @@ void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features, setSSELevel(Features, AVX512F, Enabled); } else if (Name == "avx512cd" || Name == "avx512er" || Name == "avx512pf" || Name == "avx512dq" || Name == "avx512bw" || Name == "avx512vl" || - Name == "avx512vbmi" || Name == "avx512ifma") { + Name == "avx512vbmi" || Name == "avx512ifma" || + Name == "avx512vpopcntdq") { if (Enabled) setSSELevel(Features, AVX512F, Enabled); // Enable BWI instruction if VBMI is being enabled. @@ -3668,6 +3702,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, HasF16C = true; } else if (Feature == "+avx512cd") { HasAVX512CD = true; + } else if (Feature == "+avx512vpopcntdq") { + HasAVX512VPOPCNTDQ = true; } else if (Feature == "+avx512er") { HasAVX512ER = true; } else if (Feature == "+avx512pf") { @@ -3986,10 +4022,13 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, switch (XOPLevel) { case XOP: Builder.defineMacro("__XOP__"); + LLVM_FALLTHROUGH; case FMA4: Builder.defineMacro("__FMA4__"); + LLVM_FALLTHROUGH; case SSE4A: Builder.defineMacro("__SSE4A__"); + LLVM_FALLTHROUGH; case NoXOP: break; } @@ -4002,6 +4041,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasAVX512CD) Builder.defineMacro("__AVX512CD__"); + if (HasAVX512VPOPCNTDQ) + Builder.defineMacro("__AVX512VPOPCNTDQ__"); if (HasAVX512ER) Builder.defineMacro("__AVX512ER__"); if (HasAVX512PF) @@ -4051,24 +4092,33 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, switch (SSELevel) { case AVX512F: Builder.defineMacro("__AVX512F__"); + LLVM_FALLTHROUGH; case AVX2: Builder.defineMacro("__AVX2__"); + LLVM_FALLTHROUGH; case AVX: Builder.defineMacro("__AVX__"); + LLVM_FALLTHROUGH; case SSE42: Builder.defineMacro("__SSE4_2__"); + LLVM_FALLTHROUGH; case SSE41: Builder.defineMacro("__SSE4_1__"); + LLVM_FALLTHROUGH; case SSSE3: Builder.defineMacro("__SSSE3__"); + LLVM_FALLTHROUGH; case SSE3: Builder.defineMacro("__SSE3__"); + LLVM_FALLTHROUGH; case SSE2: Builder.defineMacro("__SSE2__"); Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied. + LLVM_FALLTHROUGH; case SSE1: Builder.defineMacro("__SSE__"); Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied. + LLVM_FALLTHROUGH; case NoSSE: break; } @@ -4097,10 +4147,13 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, switch (MMX3DNowLevel) { case AMD3DNowAthlon: Builder.defineMacro("__3dNOW_A__"); + LLVM_FALLTHROUGH; case AMD3DNow: Builder.defineMacro("__3dNOW__"); + LLVM_FALLTHROUGH; case MMX: Builder.defineMacro("__MMX__"); + LLVM_FALLTHROUGH; case NoMMX3DNow: break; } @@ -4112,6 +4165,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, } if (CPU >= CK_i586) Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + + if (HasFloat128) + Builder.defineMacro("__SIZEOF_FLOAT128__", "16"); } bool X86TargetInfo::hasFeature(StringRef Feature) const { @@ -4121,6 +4177,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("avx2", SSELevel >= AVX2) .Case("avx512f", SSELevel >= AVX512F) .Case("avx512cd", HasAVX512CD) + .Case("avx512vpopcntdq", HasAVX512VPOPCNTDQ) .Case("avx512er", HasAVX512ER) .Case("avx512pf", HasAVX512PF) .Case("avx512dq", HasAVX512DQ) @@ -4206,6 +4263,7 @@ bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const { .Case("avx512bw", true) .Case("avx512dq", true) .Case("avx512cd", true) + .Case("avx512vpopcntdq", true) .Case("avx512er", true) .Case("avx512pf", true) .Case("avx512vbmi", true) @@ -4589,7 +4647,9 @@ static void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) { class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo { public: MinGWX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : WindowsX86_32TargetInfo(Triple, Opts) {} + : WindowsX86_32TargetInfo(Triple, Opts) { + HasFloat128 = true; + } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); @@ -4881,6 +4941,7 @@ public: // with x86 FP ops. Weird. LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); + HasFloat128 = true; } void getTargetDefines(const LangOptions &Opts, diff --git a/lib/Basic/XRayLists.cpp b/lib/Basic/XRayLists.cpp index dccf3baa75e2..0a439c7af90d 100644 --- a/lib/Basic/XRayLists.cpp +++ b/lib/Basic/XRayLists.cpp @@ -26,6 +26,8 @@ XRayFunctionFilter::ImbueAttribute XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const { // First apply the always instrument list, than if it isn't an "always" see // whether it's treated as a "never" instrument function. + if (AlwaysInstrument->inSection("fun", FunctionName, "arg1")) + return ImbueAttribute::ALWAYS_ARG1; if (AlwaysInstrument->inSection("fun", FunctionName)) return ImbueAttribute::ALWAYS; if (NeverInstrument->inSection("fun", FunctionName)) diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index e2d5f8f870de..2134fb9e03e4 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -7332,39 +7332,42 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, AVX512PF, AVX512VBMI, AVX512IFMA, + AVX512VPOPCNTDQ, MAX }; - X86Features Feature = StringSwitch<X86Features>(FeatureStr) - .Case("cmov", X86Features::CMOV) - .Case("mmx", X86Features::MMX) - .Case("popcnt", X86Features::POPCNT) - .Case("sse", X86Features::SSE) - .Case("sse2", X86Features::SSE2) - .Case("sse3", X86Features::SSE3) - .Case("ssse3", X86Features::SSSE3) - .Case("sse4.1", X86Features::SSE4_1) - .Case("sse4.2", X86Features::SSE4_2) - .Case("avx", X86Features::AVX) - .Case("avx2", X86Features::AVX2) - .Case("sse4a", X86Features::SSE4_A) - .Case("fma4", X86Features::FMA4) - .Case("xop", X86Features::XOP) - .Case("fma", X86Features::FMA) - .Case("avx512f", X86Features::AVX512F) - .Case("bmi", X86Features::BMI) - .Case("bmi2", X86Features::BMI2) - .Case("aes", X86Features::AES) - .Case("pclmul", X86Features::PCLMUL) - .Case("avx512vl", X86Features::AVX512VL) - .Case("avx512bw", X86Features::AVX512BW) - .Case("avx512dq", X86Features::AVX512DQ) - .Case("avx512cd", X86Features::AVX512CD) - .Case("avx512er", X86Features::AVX512ER) - .Case("avx512pf", X86Features::AVX512PF) - .Case("avx512vbmi", X86Features::AVX512VBMI) - .Case("avx512ifma", X86Features::AVX512IFMA) - .Default(X86Features::MAX); + X86Features Feature = + StringSwitch<X86Features>(FeatureStr) + .Case("cmov", X86Features::CMOV) + .Case("mmx", X86Features::MMX) + .Case("popcnt", X86Features::POPCNT) + .Case("sse", X86Features::SSE) + .Case("sse2", X86Features::SSE2) + .Case("sse3", X86Features::SSE3) + .Case("ssse3", X86Features::SSSE3) + .Case("sse4.1", X86Features::SSE4_1) + .Case("sse4.2", X86Features::SSE4_2) + .Case("avx", X86Features::AVX) + .Case("avx2", X86Features::AVX2) + .Case("sse4a", X86Features::SSE4_A) + .Case("fma4", X86Features::FMA4) + .Case("xop", X86Features::XOP) + .Case("fma", X86Features::FMA) + .Case("avx512f", X86Features::AVX512F) + .Case("bmi", X86Features::BMI) + .Case("bmi2", X86Features::BMI2) + .Case("aes", X86Features::AES) + .Case("pclmul", X86Features::PCLMUL) + .Case("avx512vl", X86Features::AVX512VL) + .Case("avx512bw", X86Features::AVX512BW) + .Case("avx512dq", X86Features::AVX512DQ) + .Case("avx512cd", X86Features::AVX512CD) + .Case("avx512er", X86Features::AVX512ER) + .Case("avx512pf", X86Features::AVX512PF) + .Case("avx512vbmi", X86Features::AVX512VBMI) + .Case("avx512ifma", X86Features::AVX512IFMA) + .Case("avx512vpopcntdq", X86Features::AVX512VPOPCNTDQ) + .Default(X86Features::MAX); assert(Feature != X86Features::MAX && "Invalid feature!"); // Matching the struct layout from the compiler-rt/libgcc structure that is @@ -7517,7 +7520,12 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_storesd128_mask: { return EmitX86MaskedStore(*this, Ops, 16); } - + case X86::BI__builtin_ia32_vpopcntd_512: + case X86::BI__builtin_ia32_vpopcntq_512: { + llvm::Type *ResultType = ConvertType(E->getType()); + llvm::Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ResultType); + return Builder.CreateCall(F, Ops); + } case X86::BI__builtin_ia32_cvtmask2b128: case X86::BI__builtin_ia32_cvtmask2b256: case X86::BI__builtin_ia32_cvtmask2b512: @@ -8442,6 +8450,80 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(F, Ops); } } + + case PPC::BI__builtin_vsx_xxpermdi: { + ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]); + assert(ArgCI && "Third arg must be constant integer!"); + + unsigned Index = ArgCI->getZExtValue(); + Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int64Ty, 2)); + Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int64Ty, 2)); + + // Element zero comes from the first input vector and element one comes from + // the second. The element indices within each vector are numbered in big + // endian order so the shuffle mask must be adjusted for this on little + // endian platforms (i.e. index is complemented and source vector reversed). + unsigned ElemIdx0; + unsigned ElemIdx1; + if (getTarget().isLittleEndian()) { + ElemIdx0 = (~Index & 1) + 2; + ElemIdx1 = (~Index & 2) >> 1; + } else { // BigEndian + ElemIdx0 = (Index & 2) >> 1; + ElemIdx1 = 2 + (Index & 1); + } + + Constant *ShuffleElts[2] = {ConstantInt::get(Int32Ty, ElemIdx0), + ConstantInt::get(Int32Ty, ElemIdx1)}; + Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts); + + Value *ShuffleCall = + Builder.CreateShuffleVector(Ops[0], Ops[1], ShuffleMask); + QualType BIRetType = E->getType(); + auto RetTy = ConvertType(BIRetType); + return Builder.CreateBitCast(ShuffleCall, RetTy); + } + + case PPC::BI__builtin_vsx_xxsldwi: { + ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]); + assert(ArgCI && "Third argument must be a compile time constant"); + unsigned Index = ArgCI->getZExtValue() & 0x3; + Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int32Ty, 4)); + Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int32Ty, 4)); + + // Create a shuffle mask + unsigned ElemIdx0; + unsigned ElemIdx1; + unsigned ElemIdx2; + unsigned ElemIdx3; + if (getTarget().isLittleEndian()) { + // Little endian element N comes from element 8+N-Index of the + // concatenated wide vector (of course, using modulo arithmetic on + // the total number of elements). + ElemIdx0 = (8 - Index) % 8; + ElemIdx1 = (9 - Index) % 8; + ElemIdx2 = (10 - Index) % 8; + ElemIdx3 = (11 - Index) % 8; + } else { + // Big endian ElemIdx<N> = Index + N + ElemIdx0 = Index; + ElemIdx1 = Index + 1; + ElemIdx2 = Index + 2; + ElemIdx3 = Index + 3; + } + + Constant *ShuffleElts[4] = {ConstantInt::get(Int32Ty, ElemIdx0), + ConstantInt::get(Int32Ty, ElemIdx1), + ConstantInt::get(Int32Ty, ElemIdx2), + ConstantInt::get(Int32Ty, ElemIdx3)}; + + Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts); + Value *ShuffleCall = + Builder.CreateShuffleVector(Ops[0], Ops[1], ShuffleMask); + QualType BIRetType = E->getType(); + auto RetTy = ConvertType(BIRetType); + return Builder.CreateBitCast(ShuffleCall, RetTy); + } } } diff --git a/lib/CodeGen/CGCoroutine.cpp b/lib/CodeGen/CGCoroutine.cpp index 0ef680ef6609..c468c1bb4b5f 100644 --- a/lib/CodeGen/CGCoroutine.cpp +++ b/lib/CodeGen/CGCoroutine.cpp @@ -11,9 +11,11 @@ // //===----------------------------------------------------------------------===// +#include "CGCleanup.h" #include "CodeGenFunction.h" #include "llvm/ADT/ScopeExit.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtVisitor.h" using namespace clang; using namespace CodeGen; @@ -57,6 +59,15 @@ struct clang::CodeGen::CGCoroData { // builtin. llvm::CallInst *CoroId = nullptr; + // Stores the llvm.coro.begin emitted in the function so that we can replace + // all coro.frame intrinsics with direct SSA value of coro.begin that returns + // the address of the coroutine frame of the current coroutine. + llvm::CallInst *CoroBegin = nullptr; + + // Stores the last emitted coro.free for the deallocate expressions, we use it + // to wrap dealloc code with if(auto mem = coro.free) dealloc(mem). + llvm::CallInst *LastCoroFree = nullptr; + // If coro.id came from the builtin, remember the expression to give better // diagnostic. If CoroIdExpr is nullptr, the coro.id was created by // EmitCoroutineBody. @@ -142,6 +153,20 @@ static RValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro, AwaitKind Kind, AggValueSlot aggSlot, bool ignoreResult) { auto *E = S.getCommonExpr(); + + // FIXME: rsmith 5/22/2017. Does it still make sense for us to have a + // UO_Coawait at all? As I recall, the only purpose it ever had was to + // represent a dependent co_await expression that couldn't yet be resolved to + // a CoawaitExpr. But now we have (and need!) a separate DependentCoawaitExpr + // node to store unqualified lookup results, it seems that the UnaryOperator + // portion of the representation serves no purpose (and as seen in this patch, + // it's getting in the way). Can we remove it? + + // Skip passthrough operator co_await (present when awaiting on an LValue). + if (auto *UO = dyn_cast<UnaryOperator>(E)) + if (UO->getOpcode() == UO_Coawait) + E = UO->getSubExpr(); + auto Binder = CodeGenFunction::OpaqueValueMappingData::bind(CGF, S.getOpaqueValue(), E); auto UnbindOnExit = llvm::make_scope_exit([&] { Binder.unbind(CGF); }); @@ -215,7 +240,67 @@ void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) { EmitBranchThroughCleanup(CurCoro.Data->FinalJD); } -// For WinEH exception representation backend need to know what funclet coro.end +// Hunts for the parameter reference in the parameter copy/move declaration. +namespace { +struct GetParamRef : public StmtVisitor<GetParamRef> { +public: + DeclRefExpr *Expr = nullptr; + GetParamRef() {} + void VisitDeclRefExpr(DeclRefExpr *E) { + assert(Expr == nullptr && "multilple declref in param move"); + Expr = E; + } + void VisitStmt(Stmt *S) { + for (auto *C : S->children()) { + if (C) + Visit(C); + } + } +}; +} + +// This class replaces references to parameters to their copies by changing +// the addresses in CGF.LocalDeclMap and restoring back the original values in +// its destructor. + +namespace { + struct ParamReferenceReplacerRAII { + CodeGenFunction::DeclMapTy SavedLocals; + CodeGenFunction::DeclMapTy& LocalDeclMap; + + ParamReferenceReplacerRAII(CodeGenFunction::DeclMapTy &LocalDeclMap) + : LocalDeclMap(LocalDeclMap) {} + + void addCopy(DeclStmt const *PM) { + // Figure out what param it refers to. + + assert(PM->isSingleDecl()); + VarDecl const*VD = static_cast<VarDecl const*>(PM->getSingleDecl()); + Expr const *InitExpr = VD->getInit(); + GetParamRef Visitor; + Visitor.Visit(const_cast<Expr*>(InitExpr)); + assert(Visitor.Expr); + auto *DREOrig = cast<DeclRefExpr>(Visitor.Expr); + auto *PD = DREOrig->getDecl(); + + auto it = LocalDeclMap.find(PD); + assert(it != LocalDeclMap.end() && "parameter is not found"); + SavedLocals.insert({ PD, it->second }); + + auto copyIt = LocalDeclMap.find(VD); + assert(copyIt != LocalDeclMap.end() && "parameter copy is not found"); + it->second = copyIt->getSecond(); + } + + ~ParamReferenceReplacerRAII() { + for (auto&& SavedLocal : SavedLocals) { + LocalDeclMap.insert({SavedLocal.first, SavedLocal.second}); + } + } + }; +} + +// For WinEH exception representation backend needs to know what funclet coro.end // belongs to. That information is passed in a funclet bundle. static SmallVector<llvm::OperandBundleDef, 1> getBundlesForCoroEnd(CodeGenFunction &CGF) { @@ -257,24 +342,135 @@ namespace { struct CallCoroDelete final : public EHScopeStack::Cleanup { Stmt *Deallocate; - // TODO: Wrap deallocate in if(coro.free(...)) Deallocate. + // Emit "if (coro.free(CoroId, CoroBegin)) Deallocate;" + + // Note: That deallocation will be emitted twice: once for a normal exit and + // once for exceptional exit. This usage is safe because Deallocate does not + // contain any declarations. The SubStmtBuilder::makeNewAndDeleteExpr() + // builds a single call to a deallocation function which is safe to emit + // multiple times. void Emit(CodeGenFunction &CGF, Flags) override { - // Note: That deallocation will be emitted twice: once for a normal exit and - // once for exceptional exit. This usage is safe because Deallocate does not - // contain any declarations. The SubStmtBuilder::makeNewAndDeleteExpr() - // builds a single call to a deallocation function which is safe to emit - // multiple times. + // Remember the current point, as we are going to emit deallocation code + // first to get to coro.free instruction that is an argument to a delete + // call. + BasicBlock *SaveInsertBlock = CGF.Builder.GetInsertBlock(); + + auto *FreeBB = CGF.createBasicBlock("coro.free"); + CGF.EmitBlock(FreeBB); CGF.EmitStmt(Deallocate); + + auto *AfterFreeBB = CGF.createBasicBlock("after.coro.free"); + CGF.EmitBlock(AfterFreeBB); + + // We should have captured coro.free from the emission of deallocate. + auto *CoroFree = CGF.CurCoro.Data->LastCoroFree; + if (!CoroFree) { + CGF.CGM.Error(Deallocate->getLocStart(), + "Deallocation expressoin does not refer to coro.free"); + return; + } + + // Get back to the block we were originally and move coro.free there. + auto *InsertPt = SaveInsertBlock->getTerminator(); + CoroFree->moveBefore(InsertPt); + CGF.Builder.SetInsertPoint(InsertPt); + + // Add if (auto *mem = coro.free) Deallocate; + auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy); + auto *Cond = CGF.Builder.CreateICmpNE(CoroFree, NullPtr); + CGF.Builder.CreateCondBr(Cond, FreeBB, AfterFreeBB); + + // No longer need old terminator. + InsertPt->eraseFromParent(); + CGF.Builder.SetInsertPoint(AfterFreeBB); } explicit CallCoroDelete(Stmt *DeallocStmt) : Deallocate(DeallocStmt) {} }; } +namespace { +struct GetReturnObjectManager { + CodeGenFunction &CGF; + CGBuilderTy &Builder; + const CoroutineBodyStmt &S; + + Address GroActiveFlag; + CodeGenFunction::AutoVarEmission GroEmission; + + GetReturnObjectManager(CodeGenFunction &CGF, const CoroutineBodyStmt &S) + : CGF(CGF), Builder(CGF.Builder), S(S), GroActiveFlag(Address::invalid()), + GroEmission(CodeGenFunction::AutoVarEmission::invalid()) {} + + // The gro variable has to outlive coroutine frame and coroutine promise, but, + // it can only be initialized after coroutine promise was created, thus, we + // split its emission in two parts. EmitGroAlloca emits an alloca and sets up + // cleanups. Later when coroutine promise is available we initialize the gro + // and sets the flag that the cleanup is now active. + + void EmitGroAlloca() { + auto *GroDeclStmt = dyn_cast<DeclStmt>(S.getResultDecl()); + if (!GroDeclStmt) { + // If get_return_object returns void, no need to do an alloca. + return; + } + + auto *GroVarDecl = cast<VarDecl>(GroDeclStmt->getSingleDecl()); + + // Set GRO flag that it is not initialized yet + GroActiveFlag = + CGF.CreateTempAlloca(Builder.getInt1Ty(), CharUnits::One(), "gro.active"); + Builder.CreateStore(Builder.getFalse(), GroActiveFlag); + + GroEmission = CGF.EmitAutoVarAlloca(*GroVarDecl); + + // Remember the top of EHStack before emitting the cleanup. + auto old_top = CGF.EHStack.stable_begin(); + CGF.EmitAutoVarCleanups(GroEmission); + auto top = CGF.EHStack.stable_begin(); + + // Make the cleanup conditional on gro.active + for (auto b = CGF.EHStack.find(top), e = CGF.EHStack.find(old_top); + b != e; b++) { + if (auto *Cleanup = dyn_cast<EHCleanupScope>(&*b)) { + assert(!Cleanup->hasActiveFlag() && "cleanup already has active flag?"); + Cleanup->setActiveFlag(GroActiveFlag); + Cleanup->setTestFlagInEHCleanup(); + Cleanup->setTestFlagInNormalCleanup(); + } + } + } + + void EmitGroInit() { + if (!GroActiveFlag.isValid()) { + // No Gro variable was allocated. Simply emit the call to + // get_return_object. + CGF.EmitStmt(S.getResultDecl()); + return; + } + + CGF.EmitAutoVarInit(GroEmission); + Builder.CreateStore(Builder.getTrue(), GroActiveFlag); + } +}; +} + +static void emitBodyAndFallthrough(CodeGenFunction &CGF, + const CoroutineBodyStmt &S, Stmt *Body) { + CGF.EmitStmt(Body); + const bool CanFallthrough = CGF.Builder.GetInsertBlock(); + if (CanFallthrough) + if (Stmt *OnFallthrough = S.getFallthroughHandler()) + CGF.EmitStmt(OnFallthrough); +} + void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) { auto *NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy()); auto &TI = CGM.getContext().getTargetInfo(); unsigned NewAlign = TI.getNewAlign() / TI.getCharWidth(); + auto *EntryBB = Builder.GetInsertBlock(); + auto *AllocBB = createBasicBlock("coro.alloc"); + auto *InitBB = createBasicBlock("coro.init"); auto *FinalBB = createBasicBlock("coro.final"); auto *RetBB = createBasicBlock("coro.ret"); @@ -284,12 +480,20 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) { createCoroData(*this, CurCoro, CoroId); CurCoro.Data->SuspendBB = RetBB; + // Backend is allowed to elide memory allocations, to help it, emit + // auto mem = coro.alloc() ? 0 : ... allocation code ...; + auto *CoroAlloc = Builder.CreateCall( + CGM.getIntrinsic(llvm::Intrinsic::coro_alloc), {CoroId}); + + Builder.CreateCondBr(CoroAlloc, AllocBB, InitBB); + + EmitBlock(AllocBB); auto *AllocateCall = EmitScalarExpr(S.getAllocate()); + auto *AllocOrInvokeContBB = Builder.GetInsertBlock(); // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided. if (auto *RetOnAllocFailure = S.getReturnStmtOnAllocFailure()) { auto *RetOnFailureBB = createBasicBlock("coro.ret.on.failure"); - auto *InitBB = createBasicBlock("coro.init"); // See if allocation was successful. auto *NullPtr = llvm::ConstantPointerNull::get(Int8PtrTy); @@ -299,40 +503,96 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) { // If not, return OnAllocFailure object. EmitBlock(RetOnFailureBB); EmitStmt(RetOnAllocFailure); - - EmitBlock(InitBB); } + else { + Builder.CreateBr(InitBB); + } + + EmitBlock(InitBB); + + // Pass the result of the allocation to coro.begin. + auto *Phi = Builder.CreatePHI(VoidPtrTy, 2); + Phi->addIncoming(NullPtr, EntryBB); + Phi->addIncoming(AllocateCall, AllocOrInvokeContBB); + auto *CoroBegin = Builder.CreateCall( + CGM.getIntrinsic(llvm::Intrinsic::coro_begin), {CoroId, Phi}); + CurCoro.Data->CoroBegin = CoroBegin; + + GetReturnObjectManager GroManager(*this, S); + GroManager.EmitGroAlloca(); CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB); { + ParamReferenceReplacerRAII ParamReplacer(LocalDeclMap); CodeGenFunction::RunCleanupsScope ResumeScope(*this); EHStack.pushCleanup<CallCoroDelete>(NormalAndEHCleanup, S.getDeallocate()); + // Create parameter copies. We do it before creating a promise, since an + // evolution of coroutine TS may allow promise constructor to observe + // parameter copies. + for (auto *PM : S.getParamMoves()) { + EmitStmt(PM); + ParamReplacer.addCopy(cast<DeclStmt>(PM)); + // TODO: if(CoroParam(...)) need to surround ctor and dtor + // for the copy, so that llvm can elide it if the copy is + // not needed. + } + EmitStmt(S.getPromiseDeclStmt()); + Address PromiseAddr = GetAddrOfLocalVar(S.getPromiseDecl()); + auto *PromiseAddrVoidPtr = + new llvm::BitCastInst(PromiseAddr.getPointer(), VoidPtrTy, "", CoroId); + // Update CoroId to refer to the promise. We could not do it earlier because + // promise local variable was not emitted yet. + CoroId->setArgOperand(1, PromiseAddrVoidPtr); + + // Now we have the promise, initialize the GRO + GroManager.EmitGroInit(); + EHStack.pushCleanup<CallCoroEnd>(EHCleanup); + CurCoro.Data->CurrentAwaitKind = AwaitKind::Init; + EmitStmt(S.getInitSuspendStmt()); CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB); - // FIXME: Emit initial suspend and more before the body. - CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal; - EmitStmt(S.getBody()); + + if (auto *OnException = S.getExceptionHandler()) { + auto Loc = S.getLocStart(); + CXXCatchStmt Catch(Loc, /*exDecl=*/nullptr, OnException); + auto *TryStmt = CXXTryStmt::Create(getContext(), Loc, S.getBody(), &Catch); + + EnterCXXTryStmt(*TryStmt); + emitBodyAndFallthrough(*this, S, TryStmt->getTryBlock()); + ExitCXXTryStmt(*TryStmt); + } + else { + emitBodyAndFallthrough(*this, S, S.getBody()); + } // See if we need to generate final suspend. const bool CanFallthrough = Builder.GetInsertBlock(); const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0; if (CanFallthrough || HasCoreturns) { EmitBlock(FinalBB); - // FIXME: Emit final suspend. + CurCoro.Data->CurrentAwaitKind = AwaitKind::Final; + EmitStmt(S.getFinalSuspendStmt()); + } + else { + // We don't need FinalBB. Emit it to make sure the block is deleted. + EmitBlock(FinalBB, /*IsFinished=*/true); } } EmitBlock(RetBB); + // Emit coro.end before getReturnStmt (and parameter destructors), since + // resume and destroy parts of the coroutine should not include them. llvm::Function *CoroEnd = CGM.getIntrinsic(llvm::Intrinsic::coro_end); Builder.CreateCall(CoroEnd, {NullPtr, Builder.getFalse()}); - // FIXME: Emit return for the coroutine return object. + if (Stmt *Ret = S.getReturnStmt()) + EmitStmt(Ret); } // Emit coroutine intrinsic and patch up arguments of the token type. @@ -342,6 +602,17 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E, switch (IID) { default: break; + // The coro.frame builtin is replaced with an SSA value of the coro.begin + // intrinsic. + case llvm::Intrinsic::coro_frame: { + if (CurCoro.Data && CurCoro.Data->CoroBegin) { + return RValue::get(CurCoro.Data->CoroBegin); + } + CGM.Error(E->getLocStart(), "this builtin expect that __builtin_coro_begin " + "has been used earlier in this function"); + auto NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy()); + return RValue::get(NullPtr); + } // The following three intrinsics take a token parameter referring to a token // returned by earlier call to @llvm.coro.id. Since we cannot represent it in // builtins, we patch it up here. @@ -368,10 +639,22 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E, llvm::Value *F = CGM.getIntrinsic(IID); llvm::CallInst *Call = Builder.CreateCall(F, Args); + // Note: The following code is to enable to emit coro.id and coro.begin by + // hand to experiment with coroutines in C. // If we see @llvm.coro.id remember it in the CoroData. We will update // coro.alloc, coro.begin and coro.free intrinsics to refer to it. if (IID == llvm::Intrinsic::coro_id) { createCoroData(*this, CurCoro, Call, E); } + else if (IID == llvm::Intrinsic::coro_begin) { + if (CurCoro.Data) + CurCoro.Data->CoroBegin = Call; + } + else if (IID == llvm::Intrinsic::coro_free) { + // Remember the last coro_free as we need it to build the conditional + // deletion of the coroutine frame. + if (CurCoro.Data) + CurCoro.Data->LastCoroFree = Call; + } return RValue::get(Call); } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index a6d5dd85c234..b918a663ce5c 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1432,11 +1432,12 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, Load->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node); } if (TBAAInfo) { - llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, - TBAAOffset); - if (TBAAPath) - CGM.DecorateInstructionWithTBAA(Load, TBAAPath, - false /*ConvertTypeToTag*/); + bool MayAlias = BaseInfo.getMayAlias(); + llvm::MDNode *TBAA = MayAlias + ? CGM.getTBAAInfo(getContext().CharTy) + : CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, TBAAOffset); + if (TBAA) + CGM.DecorateInstructionWithTBAA(Load, TBAA, MayAlias); } if (EmitScalarRangeCheck(Load, Ty, Loc)) { @@ -1522,11 +1523,12 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr, Store->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node); } if (TBAAInfo) { - llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, - TBAAOffset); - if (TBAAPath) - CGM.DecorateInstructionWithTBAA(Store, TBAAPath, - false /*ConvertTypeToTag*/); + bool MayAlias = BaseInfo.getMayAlias(); + llvm::MDNode *TBAA = MayAlias + ? CGM.getTBAAInfo(getContext().CharTy) + : CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, TBAAOffset); + if (TBAA) + CGM.DecorateInstructionWithTBAA(Store, TBAA, MayAlias); } } @@ -3535,6 +3537,11 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, getFieldAlignmentSource(BaseInfo.getAlignmentSource()); LValueBaseInfo FieldBaseInfo(fieldAlignSource, BaseInfo.getMayAlias()); + const RecordDecl *rec = field->getParent(); + if (rec->isUnion() || rec->hasAttr<MayAliasAttr>()) + FieldBaseInfo.setMayAlias(true); + bool mayAlias = FieldBaseInfo.getMayAlias(); + if (field->isBitField()) { const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(field->getParent()); @@ -3556,11 +3563,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, return LValue::MakeBitfield(Addr, Info, fieldType, FieldBaseInfo); } - const RecordDecl *rec = field->getParent(); QualType type = field->getType(); - - bool mayAlias = rec->hasAttr<MayAliasAttr>(); - Address addr = base.getAddress(); unsigned cvr = base.getVRQualifiers(); bool TBAAPath = CGM.getCodeGenOpts().StructPathTBAA; diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 601d662e55e6..63300e25d37e 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -760,6 +760,7 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty, IsCombiner ? ".omp_combiner." : ".omp_initializer.", &CGM.getModule()); CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo); Fn->removeFnAttr(llvm::Attribute::NoInline); + Fn->removeFnAttr(llvm::Attribute::OptimizeNone); Fn->addFnAttr(llvm::Attribute::AlwaysInline); CodeGenFunction CGF(CGM); // Map "T omp_in;" variable to "*omp_in_parm" value in all expressions. @@ -2903,6 +2904,19 @@ CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() { Desc); CGM.getCXXABI().registerGlobalDtor(CGF, RegUnregVar, UnRegFn, Desc); }); + if (CGM.supportsCOMDAT()) { + // It is sufficient to call registration function only once, so create a + // COMDAT group for registration/unregistration functions and associated + // data. That would reduce startup time and code size. Registration + // function serves as a COMDAT group key. + auto ComdatKey = M.getOrInsertComdat(RegFn->getName()); + RegFn->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + RegFn->setVisibility(llvm::GlobalValue::HiddenVisibility); + RegFn->setComdat(ComdatKey); + UnRegFn->setComdat(ComdatKey); + DeviceImages->setComdat(ComdatKey); + Desc->setComdat(ComdatKey); + } return RegFn; } @@ -3502,6 +3516,7 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc, CGM.SetInternalFunctionAttributes(/*D=*/nullptr, TaskPrivatesMap, TaskPrivatesMapFnInfo); TaskPrivatesMap->removeFnAttr(llvm::Attribute::NoInline); + TaskPrivatesMap->removeFnAttr(llvm::Attribute::OptimizeNone); TaskPrivatesMap->addFnAttr(llvm::Attribute::AlwaysInline); CodeGenFunction CGF(CGM); CGF.disableDebugInfo(); diff --git a/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp index c3391d087b75..bbedac962d55 100644 --- a/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp +++ b/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp @@ -861,6 +861,7 @@ llvm::Value *CGOpenMPRuntimeNVPTX::emitTeamsOutlinedFunction( D, ThreadIDVar, InnermostKind, CodeGen); llvm::Function *OutlinedFun = cast<llvm::Function>(OutlinedFunVal); OutlinedFun->removeFnAttr(llvm::Attribute::NoInline); + OutlinedFun->removeFnAttr(llvm::Attribute::OptimizeNone); OutlinedFun->addFnAttr(llvm::Attribute::AlwaysInline); return OutlinedFun; @@ -1243,10 +1244,10 @@ static void emitReductionListCopy( /// local = local @ remote /// else /// local = remote -llvm::Value *emitReduceScratchpadFunction(CodeGenModule &CGM, - ArrayRef<const Expr *> Privates, - QualType ReductionArrayTy, - llvm::Value *ReduceFn) { +static llvm::Value * +emitReduceScratchpadFunction(CodeGenModule &CGM, + ArrayRef<const Expr *> Privates, + QualType ReductionArrayTy, llvm::Value *ReduceFn) { auto &C = CGM.getContext(); auto Int32Ty = C.getIntTypeForBitwidth(32, /* Signed */ true); @@ -1372,9 +1373,9 @@ llvm::Value *emitReduceScratchpadFunction(CodeGenModule &CGM, /// for elem in Reduce List: /// scratchpad[elem_id][index] = elem /// -llvm::Value *emitCopyToScratchpad(CodeGenModule &CGM, - ArrayRef<const Expr *> Privates, - QualType ReductionArrayTy) { +static llvm::Value *emitCopyToScratchpad(CodeGenModule &CGM, + ArrayRef<const Expr *> Privates, + QualType ReductionArrayTy) { auto &C = CGM.getContext(); auto Int32Ty = C.getIntTypeForBitwidth(32, /* Signed */ true); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 9d0f802ece07..e4e5fce02279 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -400,8 +400,11 @@ void CodeGenModule::Release() { } if (OpenMPRuntime) if (llvm::Function *OpenMPRegistrationFunction = - OpenMPRuntime->emitRegistrationFunction()) - AddGlobalCtor(OpenMPRegistrationFunction, 0); + OpenMPRuntime->emitRegistrationFunction()) { + auto ComdatKey = OpenMPRegistrationFunction->hasComdat() ? + OpenMPRegistrationFunction : nullptr; + AddGlobalCtor(OpenMPRegistrationFunction, 0, ComdatKey); + } if (PGOReader) { getModule().setProfileSummary(PGOReader->getSummary().getMD(VMContext)); if (PGOStats.hasDiagnostics()) @@ -904,7 +907,16 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, return; } - if (D->hasAttr<OptimizeNoneAttr>()) { + // Track whether we need to add the optnone LLVM attribute, + // starting with the default for this optimization level. + bool ShouldAddOptNone = + !CodeGenOpts.DisableO0ImplyOptNone && CodeGenOpts.OptimizationLevel == 0; + // We can't add optnone in the following cases, it won't pass the verifier. + ShouldAddOptNone &= !D->hasAttr<MinSizeAttr>(); + ShouldAddOptNone &= !F->hasFnAttribute(llvm::Attribute::AlwaysInline); + ShouldAddOptNone &= !D->hasAttr<AlwaysInlineAttr>(); + + if (ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) { B.addAttribute(llvm::Attribute::OptimizeNone); // OptimizeNone implies noinline; we should not be inlining such functions. @@ -958,7 +970,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, // function. if (!D->hasAttr<OptimizeNoneAttr>()) { if (D->hasAttr<ColdAttr>()) { - B.addAttribute(llvm::Attribute::OptimizeForSize); + if (!ShouldAddOptNone) + B.addAttribute(llvm::Attribute::OptimizeForSize); B.addAttribute(llvm::Attribute::Cold); } @@ -1508,6 +1521,10 @@ bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc, case ImbueAttr::ALWAYS: Fn->addFnAttr("function-instrument", "xray-always"); break; + case ImbueAttr::ALWAYS_ARG1: + Fn->addFnAttr("function-instrument", "xray-always"); + Fn->addFnAttr("xray-log-args", "1"); + break; case ImbueAttr::NEVER: Fn->addFnAttr("function-instrument", "xray-never"); break; diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 83aa1fdf5722..d0ba74119b7d 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -4821,6 +4821,9 @@ private: bool isSwiftErrorInRegister() const override { return true; } + + bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy, + unsigned elts) const override; }; class AArch64TargetCodeGenInfo : public TargetCodeGenInfo { @@ -4994,6 +4997,17 @@ bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const { return false; } +bool AArch64ABIInfo::isLegalVectorTypeForSwift(CharUnits totalSize, + llvm::Type *eltTy, + unsigned elts) const { + if (!llvm::isPowerOf2_32(elts)) + return false; + if (totalSize.getQuantity() != 8 && + (totalSize.getQuantity() != 16 || elts == 1)) + return false; + return true; +} + bool AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { // Homogeneous aggregates for AAPCS64 must have base types of a floating // point type or a short-vector type. This is the same as the 32-bit ABI, @@ -5382,6 +5396,8 @@ private: bool isSwiftErrorInRegister() const override { return true; } + bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy, + unsigned elts) const override; }; class ARMTargetCodeGenInfo : public TargetCodeGenInfo { @@ -5894,6 +5910,20 @@ bool ARMABIInfo::isIllegalVectorType(QualType Ty) const { return false; } +bool ARMABIInfo::isLegalVectorTypeForSwift(CharUnits vectorSize, + llvm::Type *eltTy, + unsigned numElts) const { + if (!llvm::isPowerOf2_32(numElts)) + return false; + unsigned size = getDataLayout().getTypeStoreSizeInBits(eltTy); + if (size > 64) + return false; + if (vectorSize.getQuantity() != 8 && + (vectorSize.getQuantity() != 16 || numElts == 1)) + return false; + return true; +} + bool ARMABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { // Homogeneous aggregates for AAPCS-VFP must have base types of float, // double, or 64-bit or 128-bit vectors. diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 43d6aa8f99b8..247626d8200e 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -30,6 +30,7 @@ add_clang_library(clangDriver ToolChains/AMDGPU.cpp ToolChains/AVR.cpp ToolChains/Bitrig.cpp + ToolChains/BareMetal.cpp ToolChains/Clang.cpp ToolChains/CloudABI.cpp ToolChains/CommonArgs.cpp diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index f36deff5d734..d07ac96a3108 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -22,6 +22,7 @@ #include "ToolChains/FreeBSD.h" #include "ToolChains/Fuchsia.h" #include "ToolChains/Gnu.h" +#include "ToolChains/BareMetal.h" #include "ToolChains/Haiku.h" #include "ToolChains/Hexagon.h" #include "ToolChains/Lanai.h" @@ -598,6 +599,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { bool CCCPrintPhases; InputArgList Args = ParseArgStrings(ArgList.slice(1)); + if (Diags.hasErrorOccurred()) + return nullptr; // Silence driver warnings if requested Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w)); @@ -1216,6 +1219,13 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { return false; } + if (Arg *A = C.getArgs().getLastArg(options::OPT_autocomplete)) { + // Print out all options that start with a given argument. This is used for + // shell autocompletion. + llvm::outs() << llvm::join(Opts->findByPrefix(A->getValue()), " ") << '\n'; + return false; + } + if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) { ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(C.getArgs()); switch (RLT) { @@ -3819,6 +3829,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, if (Target.getVendor() == llvm::Triple::Myriad) TC = llvm::make_unique<toolchains::MyriadToolChain>(*this, Target, Args); + else if (toolchains::BareMetal::handlesTarget(Target)) + TC = llvm::make_unique<toolchains::BareMetal>(*this, Target, Args); else if (Target.isOSBinFormatELF()) TC = llvm::make_unique<toolchains::Generic_ELF>(*this, Target, Args); else if (Target.isOSBinFormatMachO()) diff --git a/lib/Driver/ToolChains/BareMetal.cpp b/lib/Driver/ToolChains/BareMetal.cpp new file mode 100644 index 000000000000..66246f6d71cd --- /dev/null +++ b/lib/Driver/ToolChains/BareMetal.cpp @@ -0,0 +1,210 @@ +//===--- BaremMetal.cpp - Bare Metal ToolChain ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "BareMetal.h" + +#include "CommonArgs.h" +#include "InputInfo.h" +#include "Gnu.h" + +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm::opt; +using namespace clang; +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; + +BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); +} + +BareMetal::~BareMetal() {} + +/// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ? +static bool isARMBareMetal(const llvm::Triple &Triple) { + if (Triple.getArch() != llvm::Triple::arm && + Triple.getArch() != llvm::Triple::thumb) + return false; + + if (Triple.getVendor() != llvm::Triple::UnknownVendor) + return false; + + if (Triple.getOS() != llvm::Triple::UnknownOS) + return false; + + if (Triple.getEnvironment() != llvm::Triple::EABI && + Triple.getEnvironment() != llvm::Triple::EABIHF) + return false; + + return true; +} + +bool BareMetal::handlesTarget(const llvm::Triple &Triple) { + return isARMBareMetal(Triple); +} + +Tool *BareMetal::buildLinker() const { + return new tools::baremetal::Linker(*this); +} + +std::string BareMetal::getThreadModel() const { + return "single"; +} + +bool BareMetal::isThreadModelSupported(const StringRef Model) const { + return Model == "single"; +} + +std::string BareMetal::getRuntimesDir() const { + SmallString<128> Dir(getDriver().ResourceDir); + llvm::sys::path::append(Dir, "lib", "baremetal"); + return Dir.str(); +} + +void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(getDriver().ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { + SmallString<128> Dir(getDriver().SysRoot); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } +} + +void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + CC1Args.push_back("-nostdsysteminc"); +} + +std::string BareMetal::findLibCxxIncludePath(CXXStdlibType LibType) const { + StringRef SysRoot = getDriver().SysRoot; + if (SysRoot.empty()) + return ""; + + switch (LibType) { + case ToolChain::CST_Libcxx: { + SmallString<128> Dir(SysRoot); + llvm::sys::path::append(Dir, "include", "c++", "v1"); + return Dir.str(); + } + case ToolChain::CST_Libstdcxx: { + SmallString<128> Dir(SysRoot); + llvm::sys::path::append(Dir, "include", "c++"); + std::error_code EC; + Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; + // Walk the subdirs, and find the one with the newest gcc version: + for (vfs::directory_iterator LI = + getDriver().getVFS().dir_begin(Dir.str(), EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->getName()); + auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); + if (CandidateVersion.Major == -1) + continue; + if (CandidateVersion <= Version) + continue; + Version = CandidateVersion; + } + if (Version.Major == -1) + return ""; + llvm::sys::path::append(Dir, Version.Text); + return Dir.str(); + } + } + llvm_unreachable("unhandled LibType"); +} + +void BareMetal::AddClangCXXStdlibIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc) || + DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + std::string Path = findLibCxxIncludePath(GetCXXStdlibType(DriverArgs)); + if (!Path.empty()) + addSystemInclude(DriverArgs, CC1Args, Path); +} + +void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + break; + case ToolChain::CST_Libstdcxx: + CmdArgs.push_back("-lstdc++"); + CmdArgs.push_back("-lsupc++"); + break; + } + CmdArgs.push_back("-lunwind"); +} + +void BareMetal::AddLinkRuntimeLib(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.push_back(Args.MakeArgString("-lclang_rt.builtins-" + + getTriple().getArchName() + ".a")); +} + +void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain()); + + AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + + CmdArgs.push_back("-Bstatic"); + + CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir())); + + Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_e, options::OPT_s, options::OPT_t, + options::OPT_Z_Flag, options::OPT_r}); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (C.getDriver().CCCIsCXX()) + TC.AddCXXStdlibLibArgs(Args, CmdArgs); + + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lm"); + + TC.AddLinkRuntimeLib(Args, CmdArgs); + } + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + C.addCommand(llvm::make_unique<Command>(JA, *this, + Args.MakeArgString(TC.GetLinkerPath()), + CmdArgs, Inputs)); +} diff --git a/lib/Driver/ToolChains/BareMetal.h b/lib/Driver/ToolChains/BareMetal.h new file mode 100644 index 000000000000..064c1199735b --- /dev/null +++ b/lib/Driver/ToolChains/BareMetal.h @@ -0,0 +1,90 @@ +//===--- BareMetal.h - Bare Metal Tool and ToolChain -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +#include <string> + +namespace clang { +namespace driver { + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain { +public: + BareMetal(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~BareMetal() override; + + static bool handlesTarget(const llvm::Triple &Triple); +protected: + Tool *buildLinker() const override; + +public: + bool useIntegratedAs() const override { return true; } + bool isCrossCompiling() const override { return true; } + bool isPICDefault() const override { return false; } + bool isPIEDefault() const override { return false; } + bool isPICDefaultForced() const override { return false; } + bool SupportsProfiling() const override { return false; } + bool SupportsObjCGC() const override { return false; } + std::string getThreadModel() const override; + bool isThreadModelSupported(const StringRef Model) const override; + + RuntimeLibType GetDefaultRuntimeLibType() const override { + return ToolChain::RLT_CompilerRT; + } + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } + + const char *getDefaultLinker() const override { return "ld.lld"; } + + std::string getRuntimesDir() const; + void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + std::string findLibCxxIncludePath(ToolChain::CXXStdlibType LibType) const; + 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; + void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; +}; + +} // namespace toolchains + +namespace tools { +namespace baremetal { + +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: + Linker(const ToolChain &TC) : Tool("baremetal::Linker", "ld.lld", TC) {} + bool isLinkJob() const override { return true; } + bool hasIntegratedCPP() const override { return false; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // namespace baremetal +} // namespace tools + +} // namespace driver +} // namespace clang + +#endif diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp index f1015e62eec8..1a398fd8a773 100644 --- a/lib/Driver/ToolChains/Gnu.cpp +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -1598,6 +1598,49 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, return false; } +/// \brief Parse a GCCVersion object out of a string of text. +/// +/// This is the primary means of forming GCCVersion objects. +/*static*/ +Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) { + const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; + std::pair<StringRef, StringRef> First = VersionText.split('.'); + std::pair<StringRef, StringRef> Second = First.second.split('.'); + + GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; + if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) + return BadVersion; + GoodVersion.MajorStr = First.first.str(); + if (First.second.empty()) + return GoodVersion; + if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) + return BadVersion; + GoodVersion.MinorStr = Second.first.str(); + + // First look for a number prefix and parse that if present. Otherwise just + // stash the entire patch string in the suffix, and leave the number + // unspecified. This covers versions strings such as: + // 5 (handled above) + // 4.4 + // 4.4.0 + // 4.4.x + // 4.4.2-rc4 + // 4.4.x-patched + // And retains any patch number it finds. + StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); + if (!PatchText.empty()) { + if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { + // Try to parse the number and any suffix. + if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || + GoodVersion.Patch < 0) + return BadVersion; + GoodVersion.PatchSuffix = PatchText.substr(EndNumber); + } + } + + return GoodVersion; +} + static llvm::StringRef getGCCToolchainDir(const ArgList &Args) { const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain); if (A) diff --git a/lib/Driver/ToolChains/Linux.cpp b/lib/Driver/ToolChains/Linux.cpp index 50443a125244..9da366eb55fe 100644 --- a/lib/Driver/ToolChains/Linux.cpp +++ b/lib/Driver/ToolChains/Linux.cpp @@ -372,49 +372,6 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) addPathIfExists(D, SysRoot + "/usr/lib", Paths); } -/// \brief Parse a GCCVersion object out of a string of text. -/// -/// This is the primary means of forming GCCVersion objects. -/*static*/ -Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { - const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; - std::pair<StringRef, StringRef> First = VersionText.split('.'); - std::pair<StringRef, StringRef> Second = First.second.split('.'); - - GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; - if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) - return BadVersion; - GoodVersion.MajorStr = First.first.str(); - if (First.second.empty()) - return GoodVersion; - if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) - return BadVersion; - GoodVersion.MinorStr = Second.first.str(); - - // First look for a number prefix and parse that if present. Otherwise just - // stash the entire patch string in the suffix, and leave the number - // unspecified. This covers versions strings such as: - // 5 (handled above) - // 4.4 - // 4.4.0 - // 4.4.x - // 4.4.2-rc4 - // 4.4.x-patched - // And retains any patch number it finds. - StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); - if (!PatchText.empty()) { - if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { - // Try to parse the number and any suffix. - if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || - GoodVersion.Patch < 0) - return BadVersion; - GoodVersion.PatchSuffix = PatchText.substr(EndNumber); - } - } - - return GoodVersion; -} - bool Linux::HasNativeLLVMSupport() const { return true; } Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); } diff --git a/lib/Driver/ToolChains/Myriad.cpp b/lib/Driver/ToolChains/Myriad.cpp index f70ce93c45ce..6fdb5a2248dd 100644 --- a/lib/Driver/ToolChains/Myriad.cpp +++ b/lib/Driver/ToolChains/Myriad.cpp @@ -217,6 +217,7 @@ MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, default: D.Diag(clang::diag::err_target_unsupported_arch) << Triple.getArchName() << "myriad"; + LLVM_FALLTHROUGH; case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::shave: diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index 006a9710148f..ae1af753bf46 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -54,13 +54,14 @@ static bool startsNextParameter(const FormatToken &Current, const FormatStyle &Style) { const FormatToken &Previous = *Current.Previous; if (Current.is(TT_CtorInitializerComma) && - Style.BreakConstructorInitializersBeforeComma) + Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma) return true; return Previous.is(tok::comma) && !Current.isTrailingComment() && ((Previous.isNot(TT_CtorInitializerComma) || - !Style.BreakConstructorInitializersBeforeComma) && + Style.BreakConstructorInitializers != + FormatStyle::BCIS_BeforeComma) && (Previous.isNot(TT_InheritanceComma) || - !Style.BreakBeforeInheritanceComma)); + !Style.BreakBeforeInheritanceComma)); } ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, @@ -178,13 +179,20 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { getLengthToMatchingParen(Previous) + State.Column - 1 > getColumnLimit(State)) return true; - if (Current.is(TT_CtorInitializerColon) && - (State.Column + State.Line->Last->TotalLength - Current.TotalLength + 2 > + + const FormatToken &BreakConstructorInitializersToken = + Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon + ? Previous + : Current; + if (BreakConstructorInitializersToken.is(TT_CtorInitializerColon) && + (State.Column + State.Line->Last->TotalLength - Previous.TotalLength > getColumnLimit(State) || State.Stack.back().BreakBeforeParameter) && - ((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) || - Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0)) + (Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All || + Style.BreakConstructorInitializers != FormatStyle::BCIS_BeforeColon || + Style.ColumnLimit != 0)) return true; + if (Current.is(TT_ObjCMethodExpr) && !Previous.is(TT_SelectorName) && State.Line->startsWith(TT_ObjCMethodSpecifier)) return true; @@ -207,7 +215,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { // ... // }.bind(...)); // FIXME: We should find a more generic solution to this problem. - !(State.Column <= NewLineColumn && Previous.isNot(tok::r_paren) && + !(State.Column <= NewLineColumn && Style.Language == FormatStyle::LK_JavaScript)) return true; @@ -455,6 +463,11 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, !Previous.is(TT_OverloadedOperator)) || (Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) { State.Stack.back().LastSpace = State.Column; + } else if (Previous.is(TT_CtorInitializerColon) && + Style.BreakConstructorInitializers == + FormatStyle::BCIS_AfterColon) { + State.Stack.back().Indent = State.Column; + State.Stack.back().LastSpace = State.Column; } else if ((Previous.isOneOf(TT_BinaryOperator, TT_ConditionalExpr, TT_CtorInitializerColon)) && ((Previous.getPrecedence() != prec::Assignment && @@ -614,7 +627,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, State.Stack[i].BreakBeforeParameter = true; if (PreviousNonComment && - !PreviousNonComment->isOneOf(tok::comma, tok::semi) && + !PreviousNonComment->isOneOf(tok::comma, tok::colon, tok::semi) && (PreviousNonComment->isNot(TT_TemplateCloser) || Current.NestingLevel != 0) && !PreviousNonComment->isOneOf( @@ -676,7 +689,18 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return State.Stack[State.Stack.size() - 2].LastSpace; return State.FirstIndent; } - if (Current.is(tok::r_paren) && State.Stack.size() > 1) + // Indent a closing parenthesis at the previous level if followed by a semi or + // opening brace. This allows indentations such as: + // foo( + // a, + // ); + // function foo( + // a, + // ) { + // code(); // + // } + if (Current.is(tok::r_paren) && State.Stack.size() > 1 && + (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace))) return State.Stack[State.Stack.size() - 2].LastSpace; if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope()) return State.Stack[State.Stack.size() - 2].LastSpace; @@ -750,6 +774,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return ContinuationIndent; if (NextNonComment->is(TT_CtorInitializerComma)) return State.Stack.back().Indent; + if (PreviousNonComment && PreviousNonComment->is(TT_CtorInitializerColon) && + Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon) + return State.Stack.back().Indent; if (NextNonComment->isOneOf(TT_CtorInitializerColon, TT_InheritanceColon, TT_InheritanceComma)) return State.FirstIndent + Style.ConstructorInitializerIndentWidth; @@ -810,19 +837,29 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, State.FirstIndent + Style.ContinuationIndentWidth; } } - if (Current.is(TT_CtorInitializerColon)) { + if (Current.is(TT_CtorInitializerColon) && + Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon) { // Indent 2 from the column, so: // SomeClass::SomeClass() // : First(...), ... // Next(...) // ^ line up here. State.Stack.back().Indent = - State.Column + (Style.BreakConstructorInitializersBeforeComma ? 0 : 2); + State.Column + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_BeforeComma ? 0 : 2); State.Stack.back().NestedBlockIndent = State.Stack.back().Indent; if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) State.Stack.back().AvoidBinPacking = true; State.Stack.back().BreakBeforeParameter = false; } + if (Current.is(TT_CtorInitializerColon) && + Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon) { + State.Stack.back().Indent = + State.FirstIndent + Style.ConstructorInitializerIndentWidth; + State.Stack.back().NestedBlockIndent = State.Stack.back().Indent; + if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) + State.Stack.back().AvoidBinPacking = true; + } if (Current.is(TT_InheritanceColon)) State.Stack.back().Indent = State.FirstIndent + Style.ContinuationIndentWidth; diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index ac83379e6b15..2ef6516e02ee 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -123,6 +123,14 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> { } }; +template <> struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> { + static void enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) { + IO.enumCase(Value, "BeforeColon", FormatStyle::BCIS_BeforeColon); + IO.enumCase(Value, "BeforeComma", FormatStyle::BCIS_BeforeComma); + IO.enumCase(Value, "AfterColon", FormatStyle::BCIS_AfterColon); + } +}; + template <> struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> { static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) { @@ -304,8 +312,19 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); IO.mapOptional("BreakBeforeTernaryOperators", Style.BreakBeforeTernaryOperators); + + bool BreakConstructorInitializersBeforeComma = false; IO.mapOptional("BreakConstructorInitializersBeforeComma", - Style.BreakConstructorInitializersBeforeComma); + BreakConstructorInitializersBeforeComma); + IO.mapOptional("BreakConstructorInitializers", + Style.BreakConstructorInitializers); + // If BreakConstructorInitializersBeforeComma was specified but + // BreakConstructorInitializers was not, initialize the latter from the + // former for backwards compatibility. + if (BreakConstructorInitializersBeforeComma && + Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon) + Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; + IO.mapOptional("BreakAfterJavaFieldAnnotations", Style.BreakAfterJavaFieldAnnotations); IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals); @@ -537,7 +556,7 @@ FormatStyle getLLVMStyle() { LLVMStyle.BraceWrapping = {false, false, false, false, false, false, false, false, false, false, false}; LLVMStyle.BreakAfterJavaFieldAnnotations = false; - LLVMStyle.BreakConstructorInitializersBeforeComma = false; + LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakBeforeInheritanceComma = false; LLVMStyle.BreakStringLiterals = true; LLVMStyle.ColumnLimit = 80; @@ -694,7 +713,7 @@ FormatStyle getMozillaStyle() { MozillaStyle.BinPackParameters = false; MozillaStyle.BinPackArguments = false; MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla; - MozillaStyle.BreakConstructorInitializersBeforeComma = true; + MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; MozillaStyle.BreakBeforeInheritanceComma = true; MozillaStyle.ConstructorInitializerIndentWidth = 2; MozillaStyle.ContinuationIndentWidth = 2; @@ -717,7 +736,7 @@ FormatStyle getWebKitStyle() { Style.AlignTrailingComments = false; Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; Style.BreakBeforeBraces = FormatStyle::BS_WebKit; - Style.BreakConstructorInitializersBeforeComma = true; + Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; Style.Cpp11BracedListStyle = false; Style.ColumnLimit = 0; Style.FixNamespaceComments = false; @@ -1891,6 +1910,9 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code, ArrayRef<tooling::Range> Ranges, StringRef FileName) { + // cleanups only apply to C++ (they mostly concern ctor commas etc.) + if (Style.Language != FormatStyle::LK_Cpp) + return tooling::Replacements(); std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges); Cleaner Clean(*Env, Style); diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 79f438eb0f88..2af931cdf1ba 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -1996,7 +1996,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(tok::comment)) return 1000; - if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon)) + if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon, TT_CtorInitializerColon)) return 2; if (Right.isMemberAccess()) { @@ -2514,8 +2514,12 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, Right.Previous->MatchingParen->NestingLevel == 0 && Style.AlwaysBreakTemplateDeclarations) return true; - if ((Right.isOneOf(TT_CtorInitializerComma, TT_CtorInitializerColon)) && - Style.BreakConstructorInitializersBeforeComma && + if (Right.is(TT_CtorInitializerComma) && + Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma && + !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) + return true; + if (Right.is(TT_CtorInitializerColon) && + Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma && !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) return true; // Break only if we have multiple inheritance. @@ -2625,7 +2629,10 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, // The first comment in a braced lists is always interpreted as belonging to // the first list element. Otherwise, it should be placed outside of the // list. - return Left.BlockKind == BK_BracedInit; + return Left.BlockKind == BK_BracedInit || + (Left.is(TT_CtorInitializerColon) && + Style.BreakConstructorInitializers == + FormatStyle::BCIS_AfterColon); if (Left.is(tok::question) && Right.is(tok::colon)) return false; if (Right.is(TT_ConditionalExpr) || Right.is(tok::question)) @@ -2698,11 +2705,15 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral)) return true; + if (Left.is(TT_CtorInitializerColon)) + return Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon; + if (Right.is(TT_CtorInitializerColon)) + return Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon; if (Left.is(TT_CtorInitializerComma) && - Style.BreakConstructorInitializersBeforeComma) + Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma) return false; if (Right.is(TT_CtorInitializerComma) && - Style.BreakConstructorInitializersBeforeComma) + Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma) return true; if (Left.is(TT_InheritanceComma) && Style.BreakBeforeInheritanceComma) return false; diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 6ee211c2de67..d660638a1e8a 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -90,6 +90,21 @@ namespace { /// \brief Erase temporary files and the preamble file. void Cleanup(); }; + + template <class T> + std::unique_ptr<T> valueOrNull(llvm::ErrorOr<std::unique_ptr<T>> Val) { + if (!Val) + return nullptr; + return std::move(*Val); + } + + template <class T> + bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) { + if (!Val) + return false; + Output = std::move(*Val); + return true; + } } static llvm::sys::SmartMutex<false> &getOnDiskMutex() { @@ -1019,7 +1034,8 @@ static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> & /// \returns True if a failure occurred that causes the ASTUnit not to /// contain any translation-unit information, false otherwise. bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, - std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer) { + std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { SavedMainFileBuffer.reset(); if (!Invocation) @@ -1028,6 +1044,12 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, // Create the compiler instance to use for building the AST. std::unique_ptr<CompilerInstance> Clang( new CompilerInstance(std::move(PCHContainerOps))); + if (FileMgr && VFS) { + assert(VFS == FileMgr->getVirtualFileSystem() && + "VFS passed to Parse and VFS in FileMgr are different"); + } else if (VFS) { + Clang->setVirtualFileSystem(VFS); + } // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> @@ -1170,7 +1192,8 @@ static std::string GetPreamblePCHPath() { /// that corresponds to the main file along with a pair (bytes, start-of-line) /// that describes the preamble. ASTUnit::ComputedPreamble -ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) { +ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { FrontendOptions &FrontendOpts = Invocation.getFrontendOpts(); PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts(); @@ -1180,28 +1203,32 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) { llvm::MemoryBuffer *Buffer = nullptr; std::unique_ptr<llvm::MemoryBuffer> BufferOwner; std::string MainFilePath(FrontendOpts.Inputs[0].getFile()); - llvm::sys::fs::UniqueID MainFileID; - if (!llvm::sys::fs::getUniqueID(MainFilePath, MainFileID)) { + auto MainFileStatus = VFS->status(MainFilePath); + if (MainFileStatus) { + llvm::sys::fs::UniqueID MainFileID = MainFileStatus->getUniqueID(); + // Check whether there is a file-file remapping of the main file for (const auto &RF : PreprocessorOpts.RemappedFiles) { std::string MPath(RF.first); - llvm::sys::fs::UniqueID MID; - if (!llvm::sys::fs::getUniqueID(MPath, MID)) { + auto MPathStatus = VFS->status(MPath); + if (MPathStatus) { + llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID(); if (MainFileID == MID) { // We found a remapping. Try to load the resulting, remapped source. - BufferOwner = getBufferForFile(RF.second); + BufferOwner = valueOrNull(VFS->getBufferForFile(RF.second)); if (!BufferOwner) return ComputedPreamble(nullptr, nullptr, 0, true); } } } - + // Check whether there is a file-buffer remapping. It supercedes the // file-file remapping. for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { std::string MPath(RB.first); - llvm::sys::fs::UniqueID MID; - if (!llvm::sys::fs::getUniqueID(MPath, MID)) { + auto MPathStatus = VFS->status(MPath); + if (MPathStatus) { + llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID(); if (MainFileID == MID) { // We found a remapping. BufferOwner.reset(); @@ -1213,7 +1240,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) { // If the main source file was not remapped, load it now. if (!Buffer && !BufferOwner) { - BufferOwner = getBufferForFile(FrontendOpts.Inputs[0].getFile()); + BufferOwner = valueOrNull(VFS->getBufferForFile(FrontendOpts.Inputs[0].getFile())); if (!BufferOwner) return ComputedPreamble(nullptr, nullptr, 0, true); } @@ -1324,8 +1351,10 @@ makeStandaloneDiagnostic(const LangOptions &LangOpts, std::unique_ptr<llvm::MemoryBuffer> ASTUnit::getMainBufferWithPrecompiledPreamble( std::shared_ptr<PCHContainerOperations> PCHContainerOps, - const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild, + const CompilerInvocation &PreambleInvocationIn, + IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild, unsigned MaxLines) { + assert(VFS && "VFS is null"); auto PreambleInvocation = std::make_shared<CompilerInvocation>(PreambleInvocationIn); @@ -1333,7 +1362,8 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( PreprocessorOptions &PreprocessorOpts = PreambleInvocation->getPreprocessorOpts(); - ComputedPreamble NewPreamble = ComputePreamble(*PreambleInvocation, MaxLines); + ComputedPreamble NewPreamble = + ComputePreamble(*PreambleInvocation, MaxLines, VFS); if (!NewPreamble.Size) { // We couldn't find a preamble in the main source. Clear out the current @@ -1369,7 +1399,7 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( break; vfs::Status Status; - if (FileMgr->getNoncachedStatValue(R.second, Status)) { + if (!moveOnNoError(VFS->status(R.second), Status)) { // If we can't stat the file we're remapping to, assume that something // horrible happened. AnyFileChanged = true; @@ -1386,7 +1416,7 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( break; vfs::Status Status; - if (FileMgr->getNoncachedStatValue(RB.first, Status)) { + if (!moveOnNoError(VFS->status(RB.first), Status)) { AnyFileChanged = true; break; } @@ -1401,7 +1431,7 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( !AnyFileChanged && F != FEnd; ++F) { vfs::Status Status; - if (FileMgr->getNoncachedStatValue(F->first(), Status)) { + if (!moveOnNoError(VFS->status(F->first()), Status)) { // If we can't stat the file, assume that something horrible happened. AnyFileChanged = true; break; @@ -1546,14 +1576,14 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( TopLevelDeclsInPreamble.clear(); PreambleDiagnostics.clear(); - IntrusiveRefCntPtr<vfs::FileSystem> VFS = - createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics()); + VFS = createVFSFromCompilerInvocation(Clang->getInvocation(), + getDiagnostics(), VFS); if (!VFS) return nullptr; // Create a file manager object to provide access to and cache the filesystem. Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS)); - + // Create the source manager. Clang->setSourceManager(new SourceManager(getDiagnostics(), Clang->getFileManager())); @@ -1863,10 +1893,13 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( bool ASTUnit::LoadFromCompilerInvocation( std::shared_ptr<PCHContainerOperations> PCHContainerOps, - unsigned PrecompilePreambleAfterNParses) { + unsigned PrecompilePreambleAfterNParses, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { if (!Invocation) return true; - + + assert(VFS && "VFS is null"); + // We'll manage file buffers ourselves. Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true; Invocation->getFrontendOpts().DisableFree = false; @@ -1877,19 +1910,19 @@ bool ASTUnit::LoadFromCompilerInvocation( if (PrecompilePreambleAfterNParses > 0) { PreambleRebuildCounter = PrecompilePreambleAfterNParses; OverrideMainBuffer = - getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation); + getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS); getDiagnostics().Reset(); ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); } - + SimpleTimer ParsingTimer(WantTiming); ParsingTimer.setOutput("Parsing " + getMainFileName()); - + // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer> MemBufferCleanup(OverrideMainBuffer.get()); - return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer)); + return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS); } std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation( @@ -1923,7 +1956,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation( DiagCleanup(Diags.get()); if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), - PrecompilePreambleAfterNParses)) + PrecompilePreambleAfterNParses, + AST->FileMgr->getVirtualFileSystem())) return nullptr; return AST; } @@ -1938,7 +1972,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine( bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies, bool UserFilesAreVolatile, bool ForSerialization, - llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST) { + llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { assert(Diags.get() && "no DiagnosticsEngine was provided"); SmallVector<StoredDiagnostic, 4> StoredDiagnostics; @@ -1979,8 +2014,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine( ConfigureDiags(Diags, *AST, CaptureDiagnostics); AST->Diagnostics = Diags; AST->FileSystemOpts = CI->getFileSystemOpts(); - IntrusiveRefCntPtr<vfs::FileSystem> VFS = - createVFSFromCompilerInvocation(*CI, *Diags); + if (!VFS) + VFS = vfs::getRealFileSystem(); + VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); if (!VFS) return nullptr; AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS); @@ -2006,7 +2042,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine( ASTUnitCleanup(AST.get()); if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), - PrecompilePreambleAfterNParses)) { + PrecompilePreambleAfterNParses, + VFS)) { // Some error occurred, if caller wants to examine diagnostics, pass it the // ASTUnit. if (ErrAST) { @@ -2020,10 +2057,16 @@ ASTUnit *ASTUnit::LoadFromCommandLine( } bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, - ArrayRef<RemappedFile> RemappedFiles) { + ArrayRef<RemappedFile> RemappedFiles, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { if (!Invocation) return true; + if (!VFS) { + assert(FileMgr && "FileMgr is null on Reparse call"); + VFS = FileMgr->getVirtualFileSystem(); + } + clearFileLevelDecls(); SimpleTimer ParsingTimer(WantTiming); @@ -2045,7 +2088,8 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer; if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0) OverrideMainBuffer = - getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation); + getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS); + // Clear out the diagnostics state. FileMgr.reset(); @@ -2056,7 +2100,7 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, // Parse the sources bool Result = - Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer)); + Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS); // If we're caching global code-completion results, and the top-level // declarations have changed, clear out the code-completion cache. @@ -2414,15 +2458,19 @@ void ASTUnit::CodeComplete( std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer; if (!getPreambleFile(this).empty()) { std::string CompleteFilePath(File); - llvm::sys::fs::UniqueID CompleteFileID; - if (!llvm::sys::fs::getUniqueID(CompleteFilePath, CompleteFileID)) { + auto VFS = FileMgr.getVirtualFileSystem(); + auto CompleteFileStatus = VFS->status(CompleteFilePath); + if (CompleteFileStatus) { + llvm::sys::fs::UniqueID CompleteFileID = CompleteFileStatus->getUniqueID(); + std::string MainPath(OriginalSourceFile); - llvm::sys::fs::UniqueID MainID; - if (!llvm::sys::fs::getUniqueID(MainPath, MainID)) { + auto MainStatus = VFS->status(MainPath); + if (MainStatus) { + llvm::sys::fs::UniqueID MainID = MainStatus->getUniqueID(); if (CompleteFileID == MainID && Line > 1) OverrideMainBuffer = getMainBufferWithPrecompiledPreamble( - PCHContainerOps, Inv, false, Line - 1); + PCHContainerOps, Inv, VFS, false, Line - 1); } } } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 51147b6f9499..7d7e7d49e9f0 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -534,6 +534,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DisableLLVMPasses = Args.hasArg(OPT_disable_llvm_passes); Opts.DisableLifetimeMarkers = Args.hasArg(OPT_disable_lifetimemarkers); + Opts.DisableO0ImplyOptNone = Args.hasArg(OPT_disable_O0_optnone); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables); Opts.UseRegisterSizedBitfieldAccess = Args.hasArg( @@ -1087,6 +1088,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.SpellCheckingLimit = getLastArgIntValue( Args, OPT_fspell_checking_limit, DiagnosticOptions::DefaultSpellCheckingLimit, Diags); + Opts.SnippetLineLimit = getLastArgIntValue( + Args, OPT_fcaret_diagnostics_max_lines, + DiagnosticOptions::DefaultSnippetLineLimit, Diags); Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop, DiagnosticOptions::DefaultTabStop, Diags); if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { @@ -2747,15 +2751,22 @@ void BuryPointer(const void *Ptr) { IntrusiveRefCntPtr<vfs::FileSystem> createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags) { + return createVFSFromCompilerInvocation(CI, Diags, vfs::getRealFileSystem()); +} + +IntrusiveRefCntPtr<vfs::FileSystem> +createVFSFromCompilerInvocation(const CompilerInvocation &CI, + DiagnosticsEngine &Diags, + IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) { if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty()) - return vfs::getRealFileSystem(); + return BaseFS; - IntrusiveRefCntPtr<vfs::OverlayFileSystem> - Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem())); + IntrusiveRefCntPtr<vfs::OverlayFileSystem> Overlay( + new vfs::OverlayFileSystem(BaseFS)); // earlier vfs files are on the bottom for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer = - llvm::MemoryBuffer::getFile(File); + BaseFS->getBufferForFile(File); if (!Buffer) { Diags.Report(diag::err_missing_vfs_overlay_file) << File; return IntrusiveRefCntPtr<vfs::FileSystem>(); diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp index 16269064b6e1..49d459e78c45 100644 --- a/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -52,6 +52,8 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine( TheDriver.setCheckInputsExist(false); std::unique_ptr<driver::Compilation> C(TheDriver.BuildCompilation(Args)); + if (!C) + return nullptr; // Just print the cc1 options if -### was present. if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) { diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 1fbb2b054bad..874c1b6be41e 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -252,7 +252,8 @@ static SourceLocation ReadOriginalFileName(CompilerInstance &CI, if (AddLineNote) CI.getSourceManager().AddLineNote( - LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile)); + LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile), false, + false, SrcMgr::C_User); return T.getLocation(); } diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 9257dcae84cd..08befb33c962 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -535,7 +535,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, if (LangOpts.ConceptsTS) Builder.defineMacro("__cpp_experimental_concepts", "1"); if (LangOpts.CoroutinesTS) - Builder.defineMacro("__cpp_coroutines", "1"); + Builder.defineMacro("__cpp_coroutines", "201703L"); } static void InitializePredefinedMacros(const TargetInfo &TI, diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp index a4937386b93f..a24d5768f558 100644 --- a/lib/Frontend/TextDiagnostic.cpp +++ b/lib/Frontend/TextDiagnostic.cpp @@ -928,6 +928,56 @@ void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc, OS << "While building module '" << ModuleName << "':\n"; } +/// \brief Find the suitable set of lines to show to include a set of ranges. +static llvm::Optional<std::pair<unsigned, unsigned>> +findLinesForRange(const CharSourceRange &R, FileID FID, + const SourceManager &SM) { + if (!R.isValid()) return None; + + SourceLocation Begin = R.getBegin(); + SourceLocation End = R.getEnd(); + if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID) + return None; + + return std::make_pair(SM.getExpansionLineNumber(Begin), + SM.getExpansionLineNumber(End)); +} + +/// Add as much of range B into range A as possible without exceeding a maximum +/// size of MaxRange. Ranges are inclusive. +static std::pair<unsigned, unsigned> +maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B, + unsigned MaxRange) { + // If A is already the maximum size, we're done. + unsigned Slack = MaxRange - (A.second - A.first + 1); + if (Slack == 0) + return A; + + // Easy case: merge succeeds within MaxRange. + unsigned Min = std::min(A.first, B.first); + unsigned Max = std::max(A.second, B.second); + if (Max - Min + 1 <= MaxRange) + return {Min, Max}; + + // If we can't reach B from A within MaxRange, there's nothing to do. + // Don't add lines to the range that contain nothing interesting. + if ((B.first > A.first && B.first - A.first + 1 > MaxRange) || + (B.second < A.second && A.second - B.second + 1 > MaxRange)) + return A; + + // Otherwise, expand A towards B to produce a range of size MaxRange. We + // attempt to expand by the same amount in both directions if B strictly + // contains A. + + // Expand downwards by up to half the available amount, then upwards as + // much as possible, then downwards as much as possible. + A.second = std::min(A.second + (Slack + 1) / 2, Max); + Slack = MaxRange - (A.second - A.first + 1); + A.first = std::max(Min + Slack, A.first) - Slack; + A.second = std::min(A.first + MaxRange - 1, Max); + return A; +} + /// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo. static void highlightRange(const CharSourceRange &R, unsigned LineNo, FileID FID, @@ -990,9 +1040,12 @@ static void highlightRange(const CharSourceRange &R, EndColNo = map.startOfPreviousColumn(EndColNo); // If the start/end passed each other, then we are trying to highlight a - // range that just exists in whitespace, which must be some sort of other - // bug. - assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); + // range that just exists in whitespace. That most likely means we have + // a multi-line highlighting range that covers a blank line. + if (StartColNo > EndColNo) { + assert(StartLineNo != EndLineNo && "trying to highlight whitespace"); + StartColNo = EndColNo; + } } assert(StartColNo <= map.getSourceLine().size() && "Invalid range!"); @@ -1103,7 +1156,7 @@ void TextDiagnostic::emitSnippetAndCaret( // Decompose the location into a FID/Offset pair. std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); FileID FID = LocInfo.first; - unsigned FileOffset = LocInfo.second; + unsigned CaretFileOffset = LocInfo.second; // Get information about the buffer it points into. bool Invalid = false; @@ -1111,101 +1164,118 @@ void TextDiagnostic::emitSnippetAndCaret( if (Invalid) return; - const char *BufStart = BufData.data(); - const char *BufEnd = BufStart + BufData.size(); + unsigned CaretLineNo = SM.getLineNumber(FID, CaretFileOffset); + unsigned CaretColNo = SM.getColumnNumber(FID, CaretFileOffset); - unsigned LineNo = SM.getLineNumber(FID, FileOffset); - unsigned ColNo = SM.getColumnNumber(FID, FileOffset); - // Arbitrarily stop showing snippets when the line is too long. static const size_t MaxLineLengthToPrint = 4096; - if (ColNo > MaxLineLengthToPrint) + if (CaretColNo > MaxLineLengthToPrint) return; - // Rewind from the current position to the start of the line. - const char *TokPtr = BufStart+FileOffset; - const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based. - - // Compute the line end. Scan forward from the error position to the end of - // the line. - const char *LineEnd = TokPtr; - while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd) - ++LineEnd; - - // Arbitrarily stop showing snippets when the line is too long. - if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint) - return; - - // Trim trailing null-bytes. - StringRef Line(LineStart, LineEnd - LineStart); - while (Line.size() > ColNo && Line.back() == '\0') - Line = Line.drop_back(); + // Find the set of lines to include. + const unsigned MaxLines = DiagOpts->SnippetLineLimit; + std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo}; + for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) + if (auto OptionalRange = findLinesForRange(*I, FID, SM)) + Lines = maybeAddRange(Lines, *OptionalRange, MaxLines); + + for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) { + const char *BufStart = BufData.data(); + const char *BufEnd = BufStart + BufData.size(); + + // Rewind from the current position to the start of the line. + const char *LineStart = + BufStart + + SM.getDecomposedLoc(SM.translateLineCol(FID, LineNo, 1)).second; + if (LineStart == BufEnd) + break; - // Copy the line of code into an std::string for ease of manipulation. - std::string SourceLine(Line.begin(), Line.end()); + // Compute the line end. + const char *LineEnd = LineStart; + while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd) + ++LineEnd; - // Build the byte to column map. - const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop); + // Arbitrarily stop showing snippets when the line is too long. + // FIXME: Don't print any lines in this case. + if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint) + return; - // Create a line for the caret that is filled with spaces that is the same - // number of columns as the line of source code. - std::string CaretLine(sourceColMap.columns(), ' '); + // Trim trailing null-bytes. + StringRef Line(LineStart, LineEnd - LineStart); + while (!Line.empty() && Line.back() == '\0' && + (LineNo != CaretLineNo || Line.size() > CaretColNo)) + Line = Line.drop_back(); + + // Copy the line of code into an std::string for ease of manipulation. + std::string SourceLine(Line.begin(), Line.end()); + + // Build the byte to column map. + const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop); + + // Create a line for the caret that is filled with spaces that is the same + // number of columns as the line of source code. + std::string CaretLine(sourceColMap.columns(), ' '); + + // Highlight all of the characters covered by Ranges with ~ characters. + for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) + highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts); + + // Next, insert the caret itself. + if (CaretLineNo == LineNo) { + CaretColNo = sourceColMap.byteToContainingColumn(CaretColNo - 1); + if (CaretLine.size() < CaretColNo + 1) + CaretLine.resize(CaretColNo + 1, ' '); + CaretLine[CaretColNo] = '^'; + } - // Highlight all of the characters covered by Ranges with ~ characters. - for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), - E = Ranges.end(); - I != E; ++I) - highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts); - - // Next, insert the caret itself. - ColNo = sourceColMap.byteToContainingColumn(ColNo-1); - if (CaretLine.size()<ColNo+1) - CaretLine.resize(ColNo+1, ' '); - CaretLine[ColNo] = '^'; - - std::string FixItInsertionLine = buildFixItInsertionLine(LineNo, - sourceColMap, - Hints, SM, - DiagOpts.get()); - - // If the source line is too long for our terminal, select only the - // "interesting" source region within that line. - unsigned Columns = DiagOpts->MessageLength; - if (Columns) - selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, - Columns, sourceColMap); - - // If we are in -fdiagnostics-print-source-range-info mode, we are trying - // to produce easily machine parsable output. Add a space before the - // source line and the caret to make it trivial to tell the main diagnostic - // line from what the user is intended to see. - if (DiagOpts->ShowSourceRanges) { - SourceLine = ' ' + SourceLine; - CaretLine = ' ' + CaretLine; - } + std::string FixItInsertionLine = buildFixItInsertionLine( + LineNo, sourceColMap, Hints, SM, DiagOpts.get()); + + // If the source line is too long for our terminal, select only the + // "interesting" source region within that line. + unsigned Columns = DiagOpts->MessageLength; + if (Columns) + selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, + Columns, sourceColMap); + + // If we are in -fdiagnostics-print-source-range-info mode, we are trying + // to produce easily machine parsable output. Add a space before the + // source line and the caret to make it trivial to tell the main diagnostic + // line from what the user is intended to see. + if (DiagOpts->ShowSourceRanges) { + SourceLine = ' ' + SourceLine; + CaretLine = ' ' + CaretLine; + } - // Finally, remove any blank spaces from the end of CaretLine. - while (CaretLine[CaretLine.size()-1] == ' ') - CaretLine.erase(CaretLine.end()-1); + // Finally, remove any blank spaces from the end of CaretLine. + while (!CaretLine.empty() && CaretLine[CaretLine.size() - 1] == ' ') + CaretLine.erase(CaretLine.end() - 1); - // Emit what we have computed. - emitSnippet(SourceLine); + // Emit what we have computed. + emitSnippet(SourceLine); - if (DiagOpts->ShowColors) - OS.changeColor(caretColor, true); - OS << CaretLine << '\n'; - if (DiagOpts->ShowColors) - OS.resetColor(); + if (!CaretLine.empty()) { + if (DiagOpts->ShowColors) + OS.changeColor(caretColor, true); + OS << CaretLine << '\n'; + if (DiagOpts->ShowColors) + OS.resetColor(); + } - if (!FixItInsertionLine.empty()) { - if (DiagOpts->ShowColors) - // Print fixit line in color - OS.changeColor(fixitColor, false); - if (DiagOpts->ShowSourceRanges) - OS << ' '; - OS << FixItInsertionLine << '\n'; - if (DiagOpts->ShowColors) - OS.resetColor(); + if (!FixItInsertionLine.empty()) { + if (DiagOpts->ShowColors) + // Print fixit line in color + OS.changeColor(fixitColor, false); + if (DiagOpts->ShowSourceRanges) + OS << ' '; + OS << FixItInsertionLine << '\n'; + if (DiagOpts->ShowColors) + OS.resetColor(); + } } // Print out any parseable fixit information requested by the options. diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index 6091db08a93b..a621c02644e3 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -7,6 +7,7 @@ set(files avx2intrin.h avx512bwintrin.h avx512cdintrin.h + avx512vpopcntdqintrin.h avx512dqintrin.h avx512erintrin.h avx512fintrin.h diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h index 421e2a7754a5..957fd5f65e26 100644 --- a/lib/Headers/altivec.h +++ b/lib/Headers/altivec.h @@ -12156,6 +12156,11 @@ static __inline__ void __ATTRS_o_ai vec_vsx_st(vector unsigned char __a, #endif +#ifdef __VSX__ +#define vec_xxpermdi __builtin_vsx_xxpermdi +#define vec_xxsldwi __builtin_vsx_xxsldwi +#endif + /* vec_xor */ #define __builtin_altivec_vxor vec_xor diff --git a/lib/Headers/avx512vpopcntdqintrin.h b/lib/Headers/avx512vpopcntdqintrin.h new file mode 100644 index 000000000000..34ab84932e7a --- /dev/null +++ b/lib/Headers/avx512vpopcntdqintrin.h @@ -0,0 +1,70 @@ +/*===------------- avx512vpopcntdqintrin.h - AVX512VPOPCNTDQ 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 __IMMINTRIN_H +#error \ + "Never use <avx512vpopcntdqintrin.h> directly; include <immintrin.h> instead." +#endif + +#ifndef __AVX512VPOPCNTDQINTRIN_H +#define __AVX512VPOPCNTDQINTRIN_H + +/* Define the default attributes for the functions in this file. */ +#define __DEFAULT_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__, __target__("avx512vpopcntd" \ + "q"))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_popcnt_epi64(__m512i __A) { + return (__m512i)__builtin_ia32_vpopcntq_512((__v8di)__A); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS +_mm512_mask_popcnt_epi64(__m512i __W, __mmask8 __U, __m512i __A) { + return (__m512i)__builtin_ia32_selectq_512( + (__mmask8)__U, (__v8di)_mm512_popcnt_epi64(__A), (__v8di)__W); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS +_mm512_maskz_popcnt_epi64(__mmask8 __U, __m512i __A) { + return _mm512_mask_popcnt_epi64((__m512i)_mm512_setzero_si512(), __U, __A); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_popcnt_epi32(__m512i __A) { + return (__m512i)__builtin_ia32_vpopcntd_512((__v16si)__A); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS +_mm512_mask_popcnt_epi32(__m512i __W, __mmask16 __U, __m512i __A) { + return (__m512i)__builtin_ia32_selectd_512( + (__mmask16)__U, (__v16si)_mm512_popcnt_epi32(__A), (__v16si)__W); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS +_mm512_maskz_popcnt_epi32(__mmask16 __U, __m512i __A) { + return _mm512_mask_popcnt_epi32((__m512i)_mm512_setzero_si512(), __U, __A); +} + +#undef __DEFAULT_FN_ATTRS + +#endif diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h index 7f91d49fbcec..e22dd231427d 100644 --- a/lib/Headers/immintrin.h +++ b/lib/Headers/immintrin.h @@ -146,6 +146,10 @@ _mm256_cvtph_ps(__m128i __a) #include <avx512cdintrin.h> #endif +#if !defined(_MSC_VER) || __has_feature(modules) || defined(__AVX512VPOPCNTDQ__) +#include <avx512vpopcntdqintrin.h> +#endif + #if !defined(_MSC_VER) || __has_feature(modules) || defined(__AVX512DQ__) #include <avx512dqintrin.h> #endif diff --git a/lib/Index/IndexBody.cpp b/lib/Index/IndexBody.cpp index efa5ed85d60b..d3632b8b9b15 100644 --- a/lib/Index/IndexBody.cpp +++ b/lib/Index/IndexBody.cpp @@ -254,6 +254,18 @@ public: SymbolRoleSet Roles = getRolesForRef(E, Relations); return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(), Parent, ParentDC, Roles, Relations, E); + } else if (const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter()) { + // Class properties that are explicitly defined using @property + // declarations are represented implicitly as there is no ivar for class + // properties. + if (Getter->isClassMethod()) { + if (const auto *PD = Getter->getCanonicalDecl()->findPropertyDecl()) { + SmallVector<SymbolRelation, 2> Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); + return IndexCtx.handleReference(PD, E->getLocation(), Parent, + ParentDC, Roles, Relations, E); + } + } } // No need to do a handleReference for the objc method, because there will diff --git a/lib/Index/IndexingContext.cpp b/lib/Index/IndexingContext.cpp index 5cebb198460f..754bc84ff4b2 100644 --- a/lib/Index/IndexingContext.cpp +++ b/lib/Index/IndexingContext.cpp @@ -124,10 +124,16 @@ bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) { TKind = FD->getTemplateSpecializationKind(); } else if (auto *VD = dyn_cast<VarDecl>(D)) { TKind = VD->getTemplateSpecializationKind(); - } else if (isa<FieldDecl>(D)) { - if (const auto *Parent = - dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext())) - TKind = Parent->getSpecializationKind(); + } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) { + if (RD->getInstantiatedFromMemberClass()) + TKind = RD->getTemplateSpecializationKind(); + } else if (const auto *ED = dyn_cast<EnumDecl>(D)) { + if (ED->getInstantiatedFromMemberEnum()) + TKind = ED->getTemplateSpecializationKind(); + } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) || + isa<EnumConstantDecl>(D)) { + if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext())) + return isTemplateImplicitInstantiation(Parent); } switch (TKind) { case TSK_Undeclared: @@ -155,6 +161,16 @@ bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) { return true; } +static const CXXRecordDecl * +getDeclContextForTemplateInstationPattern(const Decl *D) { + if (const auto *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext())) + return CTSD->getTemplateInstantiationPattern(); + else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext())) + return RD->getInstantiatedFromMemberClass(); + return nullptr; +} + static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) { if (const ClassTemplateSpecializationDecl * SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { @@ -163,15 +179,26 @@ static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) { return FD->getTemplateInstantiationPattern(); } else if (auto *VD = dyn_cast<VarDecl>(D)) { return VD->getTemplateInstantiationPattern(); - } else if (const auto *FD = dyn_cast<FieldDecl>(D)) { - if (const auto *Parent = - dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext())) { - const CXXRecordDecl *Pattern = Parent->getTemplateInstantiationPattern(); - for (const NamedDecl *ND : Pattern->lookup(FD->getDeclName())) { - if (ND->isImplicit()) + } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) { + return RD->getInstantiatedFromMemberClass(); + } else if (const auto *ED = dyn_cast<EnumDecl>(D)) { + return ED->getInstantiatedFromMemberEnum(); + } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) { + const auto *ND = cast<NamedDecl>(D); + if (const CXXRecordDecl *Pattern = + getDeclContextForTemplateInstationPattern(ND)) { + for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) { + if (BaseND->isImplicit()) continue; - if (isa<FieldDecl>(ND)) - return ND; + if (BaseND->getKind() == ND->getKind()) + return BaseND; + } + } + } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) { + if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) { + if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) { + for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName())) + return BaseECD; } } } diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index fbfd3fe5cce0..1e2cbde825f5 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -563,7 +563,6 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, // Parse the suffix. At this point we can classify whether we have an FP or // integer constant. bool isFPConstant = isFloatingLiteral(); - const char *ImaginarySuffixLoc = nullptr; // Loop over all of the characters of the suffix. If we see something bad, // we break out of the loop. @@ -660,7 +659,6 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, case 'J': if (isImaginary) break; // Cannot be repeated. isImaginary = true; - ImaginarySuffixLoc = s; continue; // Success. } // If we reached here, there was an error or a ud-suffix. @@ -694,8 +692,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, } if (isImaginary) { - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, - ImaginarySuffixLoc - ThisTokBegin), + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin), diag::ext_imaginary_constant); } } diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index 1f7003a2a4a7..8c57931e47b7 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -84,6 +84,90 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod, return Context; } +/// \brief Append to \p Paths the set of paths needed to get to the +/// subframework in which the given module lives. +static void appendSubframeworkPaths(Module *Mod, + SmallVectorImpl<char> &Path) { + // Collect the framework names from the given module to the top-level module. + SmallVector<StringRef, 2> Paths; + for (; Mod; Mod = Mod->Parent) { + if (Mod->IsFramework) + Paths.push_back(Mod->Name); + } + + if (Paths.empty()) + return; + + // Add Frameworks/Name.framework for each subframework. + for (unsigned I = Paths.size() - 1; I != 0; --I) + llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework"); +} + +const FileEntry * +ModuleMap::resolveHeader(Module *M, Module::UnresolvedHeaderDirective Header, + SmallVectorImpl<char> &RelativePathName) { + if (llvm::sys::path::is_absolute(Header.FileName)) { + RelativePathName.clear(); + RelativePathName.append(Header.FileName.begin(), Header.FileName.end()); + return SourceMgr.getFileManager().getFile(Header.FileName); + } + + // Search for the header file within the module's home directory. + auto *Directory = M->Directory; + SmallString<128> FullPathName(Directory->getName()); + unsigned FullPathLength = FullPathName.size(); + + if (M->isPartOfFramework()) { + appendSubframeworkPaths(M, RelativePathName); + unsigned RelativePathLength = RelativePathName.size(); + + // Check whether this file is in the public headers. + llvm::sys::path::append(RelativePathName, "Headers", Header.FileName); + llvm::sys::path::append(FullPathName, RelativePathName); + if (auto *File = SourceMgr.getFileManager().getFile(FullPathName)) + return File; + + // Check whether this file is in the private headers. + // Ideally, private modules in the form 'FrameworkName.Private' should + // be defined as 'module FrameworkName.Private', and not as + // 'framework module FrameworkName.Private', since a 'Private.Framework' + // does not usually exist. However, since both are currently widely used + // for private modules, make sure we find the right path in both cases. + if (M->IsFramework && M->Name == "Private") + RelativePathName.clear(); + else + RelativePathName.resize(RelativePathLength); + FullPathName.resize(FullPathLength); + llvm::sys::path::append(RelativePathName, "PrivateHeaders", + Header.FileName); + llvm::sys::path::append(FullPathName, RelativePathName); + return SourceMgr.getFileManager().getFile(FullPathName); + } + + // Lookup for normal headers. + llvm::sys::path::append(RelativePathName, Header.FileName); + llvm::sys::path::append(FullPathName, RelativePathName); + return SourceMgr.getFileManager().getFile(FullPathName); +} + +const FileEntry * +ModuleMap::resolveAsBuiltinHeader(Module *M, + Module::UnresolvedHeaderDirective Header, + SmallVectorImpl<char> &BuiltinPathName) { + if (llvm::sys::path::is_absolute(Header.FileName) || M->isPartOfFramework() || + !M->IsSystem || Header.IsUmbrella || !BuiltinIncludeDir || + BuiltinIncludeDir == M->Directory || !isBuiltinHeader(Header.FileName)) + return nullptr; + + // This is a system module with a top-level header. This header + // may have a counterpart (or replacement) in the set of headers + // supplied by Clang. Find that builtin header. + llvm::sys::path::append(BuiltinPathName, BuiltinIncludeDir->getName(), + Header.FileName); + return SourceMgr.getFileManager().getFile( + StringRef(BuiltinPathName.data(), BuiltinPathName.size())); +} + ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags, const LangOptions &LangOpts, const TargetInfo *Target, HeaderSearch &HeaderInfo) @@ -1026,9 +1110,6 @@ namespace clang { /// be resolved relative to. const DirectoryEntry *Directory; - /// \brief The directory containing Clang-supplied headers. - const DirectoryEntry *BuiltinIncludeDir; - /// \brief Whether this module map is in a system header directory. bool IsSystem; @@ -1087,12 +1168,10 @@ namespace clang { ModuleMap &Map, const FileEntry *ModuleMapFile, const DirectoryEntry *Directory, - const DirectoryEntry *BuiltinIncludeDir, bool IsSystem) : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map), ModuleMapFile(ModuleMapFile), Directory(Directory), - BuiltinIncludeDir(BuiltinIncludeDir), IsSystem(IsSystem), - HadError(false), ActiveModule(nullptr) + IsSystem(IsSystem), HadError(false), ActiveModule(nullptr) { Tok.clear(); consumeToken(); @@ -1772,25 +1851,6 @@ void ModuleMapParser::parseRequiresDecl() { } while (true); } -/// \brief Append to \p Paths the set of paths needed to get to the -/// subframework in which the given module lives. -static void appendSubframeworkPaths(Module *Mod, - SmallVectorImpl<char> &Path) { - // Collect the framework names from the given module to the top-level module. - SmallVector<StringRef, 2> Paths; - for (; Mod; Mod = Mod->Parent) { - if (Mod->IsFramework) - Paths.push_back(Mod->Name); - } - - if (Paths.empty()) - return; - - // Add Frameworks/Name.framework for each subframework. - for (unsigned I = Paths.size() - 1; I != 0; --I) - llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework"); -} - /// \brief Parse a header declaration. /// /// header-declaration: @@ -1843,85 +1903,36 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, Module::UnresolvedHeaderDirective Header; Header.FileName = Tok.getString(); Header.FileNameLoc = consumeToken(); + Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword; // Check whether we already have an umbrella. - if (LeadingToken == MMToken::UmbrellaKeyword && ActiveModule->Umbrella) { + if (Header.IsUmbrella && ActiveModule->Umbrella) { Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash) << ActiveModule->getFullModuleName(); HadError = true; return; } - // Look for this file. - const FileEntry *File = nullptr; - const FileEntry *BuiltinFile = nullptr; - SmallString<128> RelativePathName; - if (llvm::sys::path::is_absolute(Header.FileName)) { - RelativePathName = Header.FileName; - File = SourceMgr.getFileManager().getFile(RelativePathName); - } else { - // Search for the header file within the search directory. - SmallString<128> FullPathName(Directory->getName()); - unsigned FullPathLength = FullPathName.size(); - - if (ActiveModule->isPartOfFramework()) { - appendSubframeworkPaths(ActiveModule, RelativePathName); - unsigned RelativePathLength = RelativePathName.size(); - - // Check whether this file is in the public headers. - llvm::sys::path::append(RelativePathName, "Headers", Header.FileName); - llvm::sys::path::append(FullPathName, RelativePathName); - File = SourceMgr.getFileManager().getFile(FullPathName); - - // Check whether this file is in the private headers. - if (!File) { - // Ideally, private modules in the form 'FrameworkName.Private' should - // be defined as 'module FrameworkName.Private', and not as - // 'framework module FrameworkName.Private', since a 'Private.Framework' - // does not usually exist. However, since both are currently widely used - // for private modules, make sure we find the right path in both cases. - if (ActiveModule->IsFramework && ActiveModule->Name == "Private") - RelativePathName.clear(); - else - RelativePathName.resize(RelativePathLength); - FullPathName.resize(FullPathLength); - llvm::sys::path::append(RelativePathName, "PrivateHeaders", - Header.FileName); - 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); - File = SourceMgr.getFileManager().getFile(FullPathName); - - // If this is a system module with a top-level header, this header - // may have a counterpart (or replacement) in the set of headers - // supplied by Clang. Find that builtin header. - if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword && - BuiltinIncludeDir && BuiltinIncludeDir != Directory && - ModuleMap::isBuiltinHeader(Header.FileName)) { - SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName()); - llvm::sys::path::append(BuiltinPathName, Header.FileName); - BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName); - - // If Clang supplies this header but the underlying system does not, - // just silently swap in our builtin version. Otherwise, we'll end - // up adding both (later). - if (BuiltinFile && !File) { - File = BuiltinFile; - RelativePathName = BuiltinPathName; - BuiltinFile = nullptr; - } - } - } + // Look for this file by name if we don't have any stat information. + SmallString<128> RelativePathName, BuiltinPathName; + const FileEntry *File = + Map.resolveHeader(ActiveModule, Header, RelativePathName); + const FileEntry *BuiltinFile = + Map.resolveAsBuiltinHeader(ActiveModule, Header, BuiltinPathName); + + // If Clang supplies this header but the underlying system does not, + // just silently swap in our builtin version. Otherwise, we'll end + // up adding both (later). + if (BuiltinFile && !File) { + RelativePathName = BuiltinPathName; + File = BuiltinFile; + BuiltinFile = nullptr; } // FIXME: We shouldn't be eagerly stat'ing every file named in a module map. // Come up with a lazy way to do this. if (File) { - if (LeadingToken == MMToken::UmbrellaKeyword) { + if (Header.IsUmbrella) { const DirectoryEntry *UmbrellaDir = File->getDir(); if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) { Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash) @@ -1938,10 +1949,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, // If there is a builtin counterpart to this file, add it now so it can // wrap the system header. if (BuiltinFile) { - // FIXME: Taking the name from the FileEntry is unstable and can give - // different results depending on how we've previously named that file - // in this build. - Module::Header H = { BuiltinFile->getName(), BuiltinFile }; + Module::Header H = { BuiltinPathName.str(), BuiltinFile }; Map.addHeader(ActiveModule, H, Role); // If we have both a builtin and system version of the file, the @@ -1960,7 +1968,6 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, // If we find a module that has a missing header, we mark this module as // unavailable and store the header directive for displaying diagnostics. - Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword; ActiveModule->markUnavailable(); ActiveModule->MissingHeaders.push_back(Header); } @@ -2555,7 +2562,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem, Buffer->getBufferEnd()); SourceLocation Start = L.getSourceLocation(); ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir, - BuiltinIncludeDir, IsSystem); + IsSystem); bool Result = Parser.parseModuleMapFile(); ParsedModuleMap[File] = Result; diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 0534aeb10ccb..030717b8bd5c 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -1171,18 +1171,26 @@ void Preprocessor::HandleLineDirective() { CheckEndOfDirective("line", true); } - SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID); + // Take the file kind of the file containing the #line directive. #line + // directives are often used for generated sources from the same codebase, so + // the new file should generally be classified the same way as the current + // file. This is visible in GCC's pre-processed output, which rewrites #line + // to GNU line markers. + SrcMgr::CharacteristicKind FileKind = + SourceMgr.getFileCharacteristic(DigitTok.getLocation()); + + SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID, false, + false, FileKind); if (Callbacks) Callbacks->FileChanged(CurPPLexer->getSourceLocation(), - PPCallbacks::RenameFile, - SrcMgr::C_User); + PPCallbacks::RenameFile, FileKind); } /// ReadLineMarkerFlags - Parse and validate any flags at the end of a GNU line /// marker directive. static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, - bool &IsSystemHeader, bool &IsExternCHeader, + SrcMgr::CharacteristicKind &FileKind, Preprocessor &PP) { unsigned FlagVal; Token FlagTok; @@ -1233,7 +1241,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, return true; } - IsSystemHeader = true; + FileKind = SrcMgr::C_System; PP.Lex(FlagTok); if (FlagTok.is(tok::eod)) return false; @@ -1247,7 +1255,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, return true; } - IsExternCHeader = true; + FileKind = SrcMgr::C_ExternCSystem; PP.Lex(FlagTok); if (FlagTok.is(tok::eod)) return false; @@ -1277,14 +1285,15 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) { Lex(StrTok); bool IsFileEntry = false, IsFileExit = false; - bool IsSystemHeader = false, IsExternCHeader = false; int FilenameID = -1; + SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User; // If the StrTok is "eod", then it wasn't present. Otherwise, it must be a // string followed by eod. - if (StrTok.is(tok::eod)) - ; // ok - else if (StrTok.isNot(tok::string_literal)) { + if (StrTok.is(tok::eod)) { + // Treat this like "#line NN", which doesn't change file characteristics. + FileKind = SourceMgr.getFileCharacteristic(DigitTok.getLocation()); + } else if (StrTok.isNot(tok::string_literal)) { Diag(StrTok, diag::err_pp_linemarker_invalid_filename); return DiscardUntilEndOfDirective(); } else if (StrTok.hasUDSuffix()) { @@ -1303,15 +1312,13 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) { FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString()); // If a filename was present, read any flags that are present. - if (ReadLineMarkerFlags(IsFileEntry, IsFileExit, - IsSystemHeader, IsExternCHeader, *this)) + if (ReadLineMarkerFlags(IsFileEntry, IsFileExit, FileKind, *this)) return; } // Create a line note with this information. - SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID, - IsFileEntry, IsFileExit, - IsSystemHeader, IsExternCHeader); + SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID, IsFileEntry, + IsFileExit, FileKind); // If the preprocessor has callbacks installed, notify them of the #line // change. This is used so that the line marker comes out in -E mode for @@ -1322,11 +1329,6 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) { Reason = PPCallbacks::EnterFile; else if (IsFileExit) Reason = PPCallbacks::ExitFile; - SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User; - if (IsExternCHeader) - FileKind = SrcMgr::C_ExternCSystem; - else if (IsSystemHeader) - FileKind = SrcMgr::C_System; Callbacks->FileChanged(CurPPLexer->getSourceLocation(), Reason, FileKind); } diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 6c7663994a49..a6bfc32e2213 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -1125,6 +1125,7 @@ static bool HasFeature(const Preprocessor &PP, StringRef Feature) { .Case("attribute_overloadable", true) .Case("attribute_unavailable_with_message", true) .Case("attribute_unused_on_fields", true) + .Case("attribute_diagnose_if_objc", true) .Case("blocks", LangOpts.Blocks) .Case("c_thread_safety_attributes", true) .Case("cxx_exceptions", LangOpts.CXXExceptions) diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index 99d56182c1bb..2d078a4e7603 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -475,9 +475,9 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { // Emit a line marker. This will change any source locations from this point // forward to realize they are in a system header. // Create a line note with this information. - SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine()+1, + SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine() + 1, FilenameID, /*IsEntry=*/false, /*IsExit=*/false, - /*IsSystem=*/true, /*IsExternC=*/false); + SrcMgr::C_System); } /// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah. diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 0b210e0360a1..dcafbadae5c0 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -2120,31 +2120,18 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) { // Form a parsed representation of the template-id to be stored in the // UnqualifiedId. - TemplateIdAnnotation *TemplateId - = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds); // FIXME: Store name for literal operator too. - if (Id.getKind() == UnqualifiedId::IK_Identifier) { - TemplateId->Name = Id.Identifier; - TemplateId->Operator = OO_None; - TemplateId->TemplateNameLoc = Id.StartLocation; - } else { - TemplateId->Name = nullptr; - TemplateId->Operator = Id.OperatorFunctionId.Operator; - TemplateId->TemplateNameLoc = Id.StartLocation; - } + IdentifierInfo *TemplateII = + Id.getKind() == UnqualifiedId::IK_Identifier ? Id.Identifier : nullptr; + OverloadedOperatorKind OpKind = Id.getKind() == UnqualifiedId::IK_Identifier + ? OO_None + : Id.OperatorFunctionId.Operator; + + TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create( + SS, TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK, + LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds); - TemplateId->SS = SS; - TemplateId->TemplateKWLoc = TemplateKWLoc; - TemplateId->Template = Template; - TemplateId->Kind = TNK; - TemplateId->LAngleLoc = LAngleLoc; - TemplateId->RAngleLoc = RAngleLoc; - ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); - for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); - Arg != ArgEnd; ++Arg) - Args[Arg] = TemplateArgs[Arg]; - Id.setTemplateId(TemplateId); return false; } diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index a919d870810a..37c80fe5e520 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -1011,25 +1011,21 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Build a template-id annotation token that can be processed // later. Tok.setKind(tok::annot_template_id); - TemplateIdAnnotation *TemplateId - = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds); - TemplateId->TemplateNameLoc = TemplateNameLoc; - if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) { - TemplateId->Name = TemplateName.Identifier; - TemplateId->Operator = OO_None; - } else { - TemplateId->Name = nullptr; - TemplateId->Operator = TemplateName.OperatorFunctionId.Operator; - } - TemplateId->SS = SS; - TemplateId->TemplateKWLoc = TemplateKWLoc; - TemplateId->Template = Template; - TemplateId->Kind = TNK; - TemplateId->LAngleLoc = LAngleLoc; - TemplateId->RAngleLoc = RAngleLoc; - ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); - for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) - Args[Arg] = ParsedTemplateArgument(TemplateArgs[Arg]); + + IdentifierInfo *TemplateII = + TemplateName.getKind() == UnqualifiedId::IK_Identifier + ? TemplateName.Identifier + : nullptr; + + OverloadedOperatorKind OpKind = + TemplateName.getKind() == UnqualifiedId::IK_Identifier + ? OO_None + : TemplateName.OperatorFunctionId.Operator; + + TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
+ SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
+ LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds); + Tok.setAnnotationValue(TemplateId); if (TemplateKWLoc.isValid()) Tok.setLocation(TemplateKWLoc); diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 50ad113fc880..db688b12cbcf 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -542,6 +542,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, bool ReturnsVoid = false; bool HasNoReturn = false; + bool IsCoroutine = S.getCurFunction() && S.getCurFunction()->isCoroutine(); if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body)) @@ -570,8 +571,13 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // Short circuit for compilation speed. if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) return; - SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd(); + auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) { + if (IsCoroutine) + S.Diag(Loc, DiagID) << S.getCurFunction()->CoroutinePromise->getType(); + else + S.Diag(Loc, DiagID); + }; // Either in a function body compound statement, or a function-try-block. switch (CheckFallThrough(AC)) { case UnknownFallThrough: @@ -579,15 +585,15 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, case MaybeFallThrough: if (HasNoReturn) - S.Diag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); + EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); else if (!ReturnsVoid) - S.Diag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); + EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); break; case AlwaysFallThrough: if (HasNoReturn) - S.Diag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); + EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); else if (!ReturnsVoid) - S.Diag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); + EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); break; case NeverFallThroughOrReturn: if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { @@ -2027,12 +2033,6 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Warning: check missing 'return' if (P.enableCheckFallThrough) { - auto IsCoro = [&]() { - if (auto *FD = dyn_cast<FunctionDecl>(D)) - if (FD->getBody() && isa<CoroutineBodyStmt>(FD->getBody())) - return true; - return false; - }; const CheckFallThroughDiagnostics &CD = (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() @@ -2040,7 +2040,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call && cast<CXXMethodDecl>(D)->getParent()->isLambda()) ? CheckFallThroughDiagnostics::MakeForLambda() - : (IsCoro() + : (fscope->isCoroutine() ? CheckFallThroughDiagnostics::MakeForCoroutine(D) : CheckFallThroughDiagnostics::MakeForFunction(D))); CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC); diff --git a/lib/Sema/CoroutineStmtBuilder.h b/lib/Sema/CoroutineStmtBuilder.h index 4958576219e5..954a0f100ebb 100644 --- a/lib/Sema/CoroutineStmtBuilder.h +++ b/lib/Sema/CoroutineStmtBuilder.h @@ -28,7 +28,6 @@ class CoroutineStmtBuilder : public CoroutineBodyStmt::CtorArgs { sema::FunctionScopeInfo &Fn; bool IsValid = true; SourceLocation Loc; - QualType RetType; SmallVector<Stmt *, 4> ParamMovesVector; const bool IsPromiseDependentType; CXXRecordDecl *PromiseRecordDecl = nullptr; @@ -61,6 +60,7 @@ private: bool makeOnFallthrough(); bool makeOnException(); bool makeReturnObject(); + bool makeGroDeclAndReturnStmt(); bool makeReturnOnAllocFailure(); bool makeParamMoves(); }; diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 14dd6267b854..b794628db738 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1696,6 +1696,9 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case PPC::BI__builtin_tabortdci: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + case PPC::BI__builtin_vsx_xxpermdi: + case PPC::BI__builtin_vsx_xxsldwi: + return SemaBuiltinVSX(TheCall); } return SemaBuiltinConstantArgRange(TheCall, i, l, u); } @@ -3892,6 +3895,65 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { return false; } +// Customized Sema Checking for VSX builtins that have the following signature: +// vector [...] builtinName(vector [...], vector [...], const int); +// Which takes the same type of vectors (any legal vector type) for the first +// two arguments and takes compile time constant for the third argument. +// Example builtins are : +// vector double vec_xxpermdi(vector double, vector double, int); +// vector short vec_xxsldwi(vector short, vector short, int); +bool Sema::SemaBuiltinVSX(CallExpr *TheCall) { + unsigned ExpectedNumArgs = 3; + if (TheCall->getNumArgs() < ExpectedNumArgs) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs() + << TheCall->getSourceRange(); + + if (TheCall->getNumArgs() > ExpectedNumArgs) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs() + << TheCall->getSourceRange(); + + // Check the third argument is a compile time constant + llvm::APSInt Value; + if(!TheCall->getArg(2)->isIntegerConstantExpr(Value, Context)) + return Diag(TheCall->getLocStart(), + diag::err_vsx_builtin_nonconstant_argument) + << 3 /* argument index */ << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(2)->getLocStart(), + TheCall->getArg(2)->getLocEnd()); + + QualType Arg1Ty = TheCall->getArg(0)->getType(); + QualType Arg2Ty = TheCall->getArg(1)->getType(); + + // Check the type of argument 1 and argument 2 are vectors. + SourceLocation BuiltinLoc = TheCall->getLocStart(); + if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) || + (!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) { + return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd()); + } + + // Check the first two arguments are the same type. + if (!Context.hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) { + return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd()); + } + + // When default clang type checking is turned off and the customized type + // checking is used, the returning type of the function must be explicitly + // set. Otherwise it is _Bool by default. + TheCall->setType(Arg1Ty); + + return false; +} + /// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { @@ -3914,7 +3976,8 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { if (!LHSType->isVectorType() || !RHSType->isVectorType()) return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_non_vector) + diag::err_vec_builtin_non_vector) + << TheCall->getDirectCallee() << SourceRange(TheCall->getArg(0)->getLocStart(), TheCall->getArg(1)->getLocEnd())); @@ -3928,12 +3991,14 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { if (!RHSType->hasIntegerRepresentation() || RHSType->getAs<VectorType>()->getNumElements() != numElements) return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_incompatible_vector) + diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() << SourceRange(TheCall->getArg(1)->getLocStart(), TheCall->getArg(1)->getLocEnd())); } else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) { return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_incompatible_vector) + diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() << SourceRange(TheCall->getArg(0)->getLocStart(), TheCall->getArg(1)->getLocEnd())); } else if (numElements != numResElements) { diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp index c709a1a723d0..ae6c35f22065 100644 --- a/lib/Sema/SemaCoroutine.cpp +++ b/lib/Sema/SemaCoroutine.cpp @@ -23,14 +23,22 @@ using namespace clang; using namespace sema; -static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD, - SourceLocation Loc) { +static LookupResult lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD, + SourceLocation Loc, bool &Res) { DeclarationName DN = S.PP.getIdentifierInfo(Name); LookupResult LR(S, DN, Loc, Sema::LookupMemberName); // Suppress diagnostics when a private member is selected. The same warnings // will be produced again when building the call. LR.suppressDiagnostics(); - return S.LookupQualifiedName(LR, RD); + Res = S.LookupQualifiedName(LR, RD); + return LR; +} + +static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD, + SourceLocation Loc) { + bool Res; + lookupMember(S, Name, RD, Loc, Res); + return Res; } /// Look up the std::coroutine_traits<...>::promise_type for the given @@ -120,8 +128,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, return PromiseType; } -/// Look up the std::coroutine_traits<...>::promise_type for the given -/// function type. +/// Look up the std::experimental::coroutine_handle<PromiseType>. static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType, SourceLocation Loc) { if (PromiseType.isNull()) @@ -314,6 +321,7 @@ static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType, } struct ReadySuspendResumeResult { + enum AwaitCallType { ACT_Ready, ACT_Suspend, ACT_Resume }; Expr *Results[3]; OpaqueValueExpr *OpaqueValue; bool IsInvalid; @@ -359,7 +367,41 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise, Calls.Results[I] = Result.get(); } + // Assume the calls are valid; all further checking should make them invalid. Calls.IsInvalid = false; + + using ACT = ReadySuspendResumeResult::AwaitCallType; + CallExpr *AwaitReady = cast<CallExpr>(Calls.Results[ACT::ACT_Ready]); + if (!AwaitReady->getType()->isDependentType()) { + // [expr.await]p3 [...] + // — await-ready is the expression e.await_ready(), contextually converted + // to bool. + ExprResult Conv = S.PerformContextuallyConvertToBool(AwaitReady); + if (Conv.isInvalid()) { + S.Diag(AwaitReady->getDirectCallee()->getLocStart(), + diag::note_await_ready_no_bool_conversion); + S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required) + << AwaitReady->getDirectCallee() << E->getSourceRange(); + Calls.IsInvalid = true; + } + Calls.Results[ACT::ACT_Ready] = Conv.get(); + } + CallExpr *AwaitSuspend = cast<CallExpr>(Calls.Results[ACT::ACT_Suspend]); + if (!AwaitSuspend->getType()->isDependentType()) { + // [expr.await]p3 [...] + // - await-suspend is the expression e.await_suspend(h), which shall be + // a prvalue of type void or bool. + QualType RetType = AwaitSuspend->getType(); + if (RetType != S.Context.BoolTy && RetType != S.Context.VoidTy) { + S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(), + diag::err_await_suspend_invalid_return_type) + << RetType; + S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required) + << AwaitSuspend->getDirectCallee(); + Calls.IsInvalid = true; + } + } + return Calls; } @@ -373,7 +415,6 @@ static ExprResult buildPromiseCall(Sema &S, VarDecl *Promise, if (PromiseRef.isInvalid()) return ExprError(); - // Call 'yield_value', passing in E. return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args); } @@ -721,17 +762,19 @@ static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc, void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { FunctionScopeInfo *Fn = getCurFunction(); - assert(Fn && Fn->CoroutinePromise && "not a coroutine"); - + assert(Fn && Fn->isCoroutine() && "not a coroutine"); if (!Body) { assert(FD->isInvalidDecl() && "a null body is only allowed for invalid declarations"); return; } + // We have a function that uses coroutine keywords, but we failed to build + // the promise type. + if (!Fn->CoroutinePromise) + return FD->setInvalidDecl(); if (isa<CoroutineBodyStmt>(Body)) { - // FIXME(EricWF): Nothing todo. the body is already a transformed coroutine - // body statement. + // Nothing todo. the body is already a transformed coroutine body statement. return; } @@ -780,7 +823,8 @@ bool CoroutineStmtBuilder::buildDependentStatements() { assert(!this->IsPromiseDependentType && "coroutine cannot have a dependent promise type"); this->IsValid = makeOnException() && makeOnFallthrough() && - makeReturnOnAllocFailure() && makeNewAndDeleteExpr(); + makeGroDeclAndReturnStmt() && makeReturnOnAllocFailure() && + makeNewAndDeleteExpr(); return this->IsValid; } @@ -857,15 +901,15 @@ bool CoroutineStmtBuilder::makeReturnOnAllocFailure() { if (ReturnObjectOnAllocationFailure.isInvalid()) return false; - // FIXME: ActOnReturnStmt expects a scope that is inside of the function, due - // to CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent()); - // S.getCurScope()->getFnParent() == nullptr at ActOnFinishFunctionBody when - // CoroutineBodyStmt is built. Figure it out and fix it. - // Use BuildReturnStmt here to unbreak sanitized tests. (Gor:3/27/2017) StmtResult ReturnStmt = S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get()); - if (ReturnStmt.isInvalid()) + if (ReturnStmt.isInvalid()) { + S.Diag(Found.getFoundDecl()->getLocation(), diag::note_member_declared_here) + << DN; + S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) + << Fn.getFirstCoroutineStmtKeyword(); return false; + } this->ReturnStmtOnAllocFailure = ReturnStmt.get(); return true; @@ -991,13 +1035,32 @@ bool CoroutineStmtBuilder::makeOnFallthrough() { // [dcl.fct.def.coroutine]/4 // The unqualified-ids 'return_void' and 'return_value' are looked up in // the scope of class P. If both are found, the program is ill-formed. - const bool HasRVoid = lookupMember(S, "return_void", PromiseRecordDecl, Loc); - const bool HasRValue = lookupMember(S, "return_value", PromiseRecordDecl, Loc); + bool HasRVoid, HasRValue; + LookupResult LRVoid = + lookupMember(S, "return_void", PromiseRecordDecl, Loc, HasRVoid); + LookupResult LRValue = + lookupMember(S, "return_value", PromiseRecordDecl, Loc, HasRValue); StmtResult Fallthrough; if (HasRVoid && HasRValue) { // FIXME Improve this diagnostic - S.Diag(FD.getLocation(), diag::err_coroutine_promise_return_ill_formed) + S.Diag(FD.getLocation(), + diag::err_coroutine_promise_incompatible_return_functions) + << PromiseRecordDecl; + S.Diag(LRVoid.getRepresentativeDecl()->getLocation(), + diag::note_member_first_declared_here) + << LRVoid.getLookupName(); + S.Diag(LRValue.getRepresentativeDecl()->getLocation(), + diag::note_member_first_declared_here) + << LRValue.getLookupName(); + return false; + } else if (!HasRVoid && !HasRValue) { + // FIXME: The PDTS currently specifies this case as UB, not ill-formed. + // However we still diagnose this as an error since until the PDTS is fixed. + S.Diag(FD.getLocation(), + diag::err_coroutine_promise_requires_return_function) + << PromiseRecordDecl; + S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here) << PromiseRecordDecl; return false; } else if (HasRVoid) { @@ -1029,6 +1092,8 @@ bool CoroutineStmtBuilder::makeOnException() { : diag:: warn_coroutine_promise_unhandled_exception_required_with_exceptions; S.Diag(Loc, DiagID) << PromiseRecordDecl; + S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here) + << PromiseRecordDecl; return !RequireUnhandledException; } @@ -1042,37 +1107,185 @@ bool CoroutineStmtBuilder::makeOnException() { if (UnhandledException.isInvalid()) return false; + // Since the body of the coroutine will be wrapped in try-catch, it will + // be incompatible with SEH __try if present in a function. + if (!S.getLangOpts().Borland && Fn.FirstSEHTryLoc.isValid()) { + S.Diag(Fn.FirstSEHTryLoc, diag::err_seh_in_a_coroutine_with_cxx_exceptions); + S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) + << Fn.getFirstCoroutineStmtKeyword(); + return false; + } + this->OnException = UnhandledException.get(); return true; } bool CoroutineStmtBuilder::makeReturnObject() { - // Build implicit 'p.get_return_object()' expression and form initialization // of return type from it. ExprResult ReturnObject = buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", None); if (ReturnObject.isInvalid()) return false; - QualType RetType = FD.getReturnType(); - if (!RetType->isDependentType()) { - InitializedEntity Entity = - InitializedEntity::InitializeResult(Loc, RetType, false); - ReturnObject = S.PerformMoveOrCopyInitialization(Entity, nullptr, RetType, - ReturnObject.get()); - if (ReturnObject.isInvalid()) + + this->ReturnValue = ReturnObject.get(); + return true; +} + +static void noteMemberDeclaredHere(Sema &S, Expr *E, FunctionScopeInfo &Fn) { + if (auto *MbrRef = dyn_cast<CXXMemberCallExpr>(E)) { + auto *MethodDecl = MbrRef->getMethodDecl(); + S.Diag(MethodDecl->getLocation(), diag::note_member_declared_here) + << MethodDecl; + } + S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) + << Fn.getFirstCoroutineStmtKeyword(); +} + +bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() { + assert(!IsPromiseDependentType && + "cannot make statement while the promise type is dependent"); + assert(this->ReturnValue && "ReturnValue must be already formed"); + + QualType const GroType = this->ReturnValue->getType(); + assert(!GroType->isDependentType() && + "get_return_object type must no longer be dependent"); + + QualType const FnRetType = FD.getReturnType(); + assert(!FnRetType->isDependentType() && + "get_return_object type must no longer be dependent"); + + if (FnRetType->isVoidType()) { + ExprResult Res = S.ActOnFinishFullExpr(this->ReturnValue, Loc); + if (Res.isInvalid()) return false; + + this->ResultDecl = Res.get(); + return true; } - ReturnObject = S.ActOnFinishFullExpr(ReturnObject.get(), Loc); - if (ReturnObject.isInvalid()) + + if (GroType->isVoidType()) { + // Trigger a nice error message. + InitializedEntity Entity = + InitializedEntity::InitializeResult(Loc, FnRetType, false); + S.PerformMoveOrCopyInitialization(Entity, nullptr, FnRetType, ReturnValue); + noteMemberDeclaredHere(S, ReturnValue, Fn); return false; + } - this->ReturnValue = ReturnObject.get(); + auto *GroDecl = VarDecl::Create( + S.Context, &FD, FD.getLocation(), FD.getLocation(), + &S.PP.getIdentifierTable().get("__coro_gro"), GroType, + S.Context.getTrivialTypeSourceInfo(GroType, Loc), SC_None); + + S.CheckVariableDeclarationType(GroDecl); + if (GroDecl->isInvalidDecl()) + return false; + + InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl); + ExprResult Res = S.PerformMoveOrCopyInitialization(Entity, nullptr, GroType, + this->ReturnValue); + if (Res.isInvalid()) + return false; + + Res = S.ActOnFinishFullExpr(Res.get()); + if (Res.isInvalid()) + return false; + + if (GroType == FnRetType) { + GroDecl->setNRVOVariable(true); + } + + S.AddInitializerToDecl(GroDecl, Res.get(), + /*DirectInit=*/false); + + S.FinalizeDeclaration(GroDecl); + + // Form a declaration statement for the return declaration, so that AST + // visitors can more easily find it. + StmtResult GroDeclStmt = + S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(GroDecl), Loc, Loc); + if (GroDeclStmt.isInvalid()) + return false; + + this->ResultDecl = GroDeclStmt.get(); + + ExprResult declRef = S.BuildDeclRefExpr(GroDecl, GroType, VK_LValue, Loc); + if (declRef.isInvalid()) + return false; + + StmtResult ReturnStmt = S.BuildReturnStmt(Loc, declRef.get()); + if (ReturnStmt.isInvalid()) { + noteMemberDeclaredHere(S, ReturnValue, Fn); + return false; + } + + this->ReturnStmt = ReturnStmt.get(); return true; } +// Create a static_cast\<T&&>(expr). +static Expr *castForMoving(Sema &S, Expr *E, QualType T = QualType()) { + if (T.isNull()) + T = E->getType(); + QualType TargetType = S.BuildReferenceType( + T, /*SpelledAsLValue*/ false, SourceLocation(), DeclarationName()); + SourceLocation ExprLoc = E->getLocStart(); + TypeSourceInfo *TargetLoc = + S.Context.getTrivialTypeSourceInfo(TargetType, ExprLoc); + + return S + .BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E, + SourceRange(ExprLoc, ExprLoc), E->getSourceRange()) + .get(); +} + +/// \brief Build a variable declaration for move parameter. +static VarDecl *buildVarDecl(Sema &S, SourceLocation Loc, QualType Type, + StringRef Name) { + DeclContext *DC = S.CurContext; + IdentifierInfo *II = &S.PP.getIdentifierTable().get(Name); + TypeSourceInfo *TInfo = S.Context.getTrivialTypeSourceInfo(Type, Loc); + VarDecl *Decl = + VarDecl::Create(S.Context, DC, Loc, Loc, II, Type, TInfo, SC_None); + Decl->setImplicit(); + return Decl; +} + bool CoroutineStmtBuilder::makeParamMoves() { - // FIXME: Perform move-initialization of parameters into frame-local copies. + for (auto *paramDecl : FD.parameters()) { + auto Ty = paramDecl->getType(); + if (Ty->isDependentType()) + continue; + + // No need to copy scalars, llvm will take care of them. + if (Ty->getAsCXXRecordDecl()) { + if (!paramDecl->getIdentifier()) + continue; + + ExprResult ParamRef = + S.BuildDeclRefExpr(paramDecl, paramDecl->getType(), + ExprValueKind::VK_LValue, Loc); // FIXME: scope? + if (ParamRef.isInvalid()) + return false; + + Expr *RCast = castForMoving(S, ParamRef.get()); + + auto D = buildVarDecl(S, Loc, Ty, paramDecl->getIdentifier()->getName()); + + S.AddInitializerToDecl(D, RCast, /*DirectInit=*/true); + + // Convert decl to a statement. + StmtResult Stmt = S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(D), Loc, Loc); + if (Stmt.isInvalid()) + return false; + + ParamMovesVector.push_back(Stmt.get()); + } + } + + // Convert to ArrayRef in CtorArgs structure that builder inherits from. + ParamMoves = ParamMovesVector; return true; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5e937aa69963..96fd952c81c7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6516,7 +6516,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( diag::err_thread_non_global) << DeclSpec::getSpecifierName(TSCS); else if (!Context.getTargetInfo().isTLSSupported()) { - if (getLangOpts().CUDA) { + if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) { // Postpone error emission until we've collected attributes required to // figure out whether it's a host or device variable and whether the // error should be ignored. @@ -6578,8 +6578,11 @@ NamedDecl *Sema::ActOnVariableDeclarator( // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); - if (getLangOpts().CUDA) { - if (EmitTLSUnsupportedError && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) + if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) { + if (EmitTLSUnsupportedError && + ((getLangOpts().CUDA && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) || + (getLangOpts().OpenMPIsDevice && + NewVD->hasAttr<OMPDeclareTargetDeclAttr>()))) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_thread_unsupported); // CUDA B.2.5: "__shared__ and __constant__ variables have implied static @@ -7917,10 +7920,7 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { if (PT->isImageType()) return PtrKernelParam; - if (PT->isBooleanType()) - return InvalidKernelParam; - - if (PT->isEventT()) + if (PT->isBooleanType() || PT->isEventT() || PT->isReserveIDT()) return InvalidKernelParam; // OpenCL extension spec v1.2 s9.5: @@ -12176,7 +12176,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - if (getLangOpts().CoroutinesTS && getCurFunction()->CoroutinePromise) + if (getLangOpts().CoroutinesTS && getCurFunction()->isCoroutine()) CheckCompletedCoroutineBody(FD, Body); if (FD) { @@ -16097,7 +16097,8 @@ void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) { void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc, Module *Mod) { // Bail if we're not allowed to implicitly import a module here. - if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery) + if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery || + VisibleModules.isVisible(Mod)) return; // Create the implicit import declaration. diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 32be26efa14f..6c492fac9eb9 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -238,7 +238,7 @@ static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, getAttrName(const AttrInfo &Attr) { return &Attr; } -const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) { +static const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) { return Attr.getName(); } @@ -949,7 +949,7 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, Msg = "<no message provided>"; SmallVector<PartialDiagnosticAt, 8> Diags; - if (!Cond->isValueDependent() && + if (isa<FunctionDecl>(D) && !Cond->isValueDependent() && !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D), Diags)) { S.Diag(Attr.getLoc(), diag::err_attr_cond_never_constant_expr) @@ -1037,10 +1037,11 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - auto *FD = cast<FunctionDecl>(D); - bool ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond); + bool ArgDependent = false; + if (const auto *FD = dyn_cast<FunctionDecl>(D)) + ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond); D->addAttr(::new (S.Context) DiagnoseIfAttr( - Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, FD, + Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D), Attr.getAttributeSpellingListIndex())); } @@ -7283,6 +7284,12 @@ public: return true; } + bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) { + SemaRef.Diag(E->getLocStart(), diag::warn_at_available_unchecked_use) + << (!SemaRef.getLangOpts().ObjC1); + return true; + } + bool VisitTypeLoc(TypeLoc Ty); }; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b543a731641f..d9528be2d383 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -10348,32 +10348,33 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, !Constructor->doesThisDeclarationHaveABody() && !Constructor->isDeleted()) && "DefineImplicitDefaultConstructor - call it for implicit default ctor"); + if (Constructor->willHaveBody() || Constructor->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = Constructor->getParent(); assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); SynthesizedFunctionScope Scope(*this, Constructor); - DiagnosticErrorTrap Trap(Diags); - if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) || - Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); - Constructor->setInvalidDecl(); - return; - } // The exception specification is needed because we are defining the // function. ResolveExceptionSpec(CurrentLocation, Constructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + + if (SetCtorInitializers(Constructor, /*AnyErrors=*/false)) { + Constructor->setInvalidDecl(); + return; + } SourceLocation Loc = Constructor->getLocEnd().isValid() ? Constructor->getLocEnd() : Constructor->getLocation(); Constructor->setBody(new (Context) CompoundStmt(Loc)); - Constructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -10483,9 +10484,22 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, assert(Constructor->getInheritedConstructor() && !Constructor->doesThisDeclarationHaveABody() && !Constructor->isDeleted()); - if (Constructor->isInvalidDecl()) + if (Constructor->willHaveBody() || Constructor->isInvalidDecl()) return; + // Initializations are performed "as if by a defaulted default constructor", + // so enter the appropriate scope. + SynthesizedFunctionScope Scope(*this, Constructor); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + Constructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + ConstructorUsingShadowDecl *Shadow = Constructor->getInheritedConstructor().getShadowDecl(); CXXConstructorDecl *InheritedCtor = @@ -10500,11 +10514,6 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, CXXRecordDecl *RD = Shadow->getParent(); SourceLocation InitLoc = Shadow->getLocation(); - // Initializations are performed "as if by a defaulted default constructor", - // so enter the appropriate scope. - SynthesizedFunctionScope Scope(*this, Constructor); - DiagnosticErrorTrap Trap(Diags); - // Build explicit initializers for all base classes from which the // constructor was inherited. SmallVector<CXXCtorInitializer*, 8> Inits; @@ -10535,22 +10544,13 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, // We now proceed as if for a defaulted default constructor, with the relevant // initializers replaced. - bool HadError = SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits); - if (HadError || Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_inhctor_synthesized_at) << RD; + if (SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits)) { Constructor->setInvalidDecl(); return; } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - Constructor->getType()->castAs<FunctionProtoType>()); - Constructor->setBody(new (Context) CompoundStmt(InitLoc)); - Constructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -10626,37 +10626,36 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, !Destructor->doesThisDeclarationHaveABody() && !Destructor->isDeleted()) && "DefineImplicitDestructor - call it for implicit default dtor"); + if (Destructor->willHaveBody() || Destructor->isInvalidDecl()) + return; + CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); - if (Destructor->isInvalidDecl()) - return; - SynthesizedFunctionScope Scope(*this, Destructor); - DiagnosticErrorTrap Trap(Diags); + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + Destructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); - if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXDestructor << Context.getTagDeclType(ClassDecl); - + if (CheckDestructor(Destructor)) { Destructor->setInvalidDecl(); return; } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - Destructor->getType()->castAs<FunctionProtoType>()); - SourceLocation Loc = Destructor->getLocEnd().isValid() ? Destructor->getLocEnd() : Destructor->getLocation(); Destructor->setBody(new (Context) CompoundStmt(Loc)); Destructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Destructor); @@ -11224,8 +11223,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { /// Diagnose an implicit copy operation for a class which is odr-used, but /// which is deprecated because the class has a user-declared copy constructor, /// copy assignment operator, or destructor. -static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp, - SourceLocation UseLoc) { +static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) { assert(CopyOp->isImplicit()); CXXRecordDecl *RD = CopyOp->getParent(); @@ -11264,10 +11262,6 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp, diag::warn_deprecated_copy_operation) << RD << /*copy assignment*/!isa<CXXConstructorDecl>(CopyOp) << /*destructor*/isa<CXXDestructorDecl>(UserDeclaredOperation); - S.Diag(UseLoc, diag::note_member_synthesized_at) - << (isa<CXXConstructorDecl>(CopyOp) ? Sema::CXXCopyConstructor - : Sema::CXXCopyAssignment) - << RD; } } @@ -11279,25 +11273,31 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, !CopyAssignOperator->doesThisDeclarationHaveABody() && !CopyAssignOperator->isDeleted()) && "DefineImplicitCopyAssignment called for wrong function"); + if (CopyAssignOperator->willHaveBody() || CopyAssignOperator->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent(); - - if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) { + if (ClassDecl->isInvalidDecl()) { CopyAssignOperator->setInvalidDecl(); return; } + SynthesizedFunctionScope Scope(*this, CopyAssignOperator); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + CopyAssignOperator->getType()->castAs<FunctionProtoType>()); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + // C++11 [class.copy]p18: // The [definition of an implicitly declared copy assignment operator] is // deprecated if the class has a user-declared copy constructor or a // user-declared destructor. if (getLangOpts().CPlusPlus11 && CopyAssignOperator->isImplicit()) - diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator, CurrentLocation); - - CopyAssignOperator->markUsed(Context); - - SynthesizedFunctionScope Scope(*this, CopyAssignOperator); - DiagnosticErrorTrap Trap(Diags); + diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator); // C++0x [class.copy]p30: // The implicitly-defined or explicitly-defaulted copy assignment operator @@ -11363,8 +11363,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/true, /*Copying=*/true); if (Copy.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); CopyAssignOperator->setInvalidDecl(); return; } @@ -11390,8 +11388,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11402,8 +11398,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11436,8 +11430,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/false, /*Copying=*/true); if (Copy.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); CopyAssignOperator->setInvalidDecl(); return; } @@ -11453,22 +11445,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; - else { + else Statements.push_back(Return.getAs<Stmt>()); - - if (Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); - Invalid = true; - } - } } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - CopyAssignOperator->getType()->castAs<FunctionProtoType>()); - if (Invalid) { CopyAssignOperator->setInvalidDecl(); return; @@ -11482,6 +11462,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } CopyAssignOperator->setBody(Body.getAs<Stmt>()); + CopyAssignOperator->markUsed(Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyAssignOperator); @@ -11654,19 +11635,15 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, !MoveAssignOperator->doesThisDeclarationHaveABody() && !MoveAssignOperator->isDeleted()) && "DefineImplicitMoveAssignment called for wrong function"); + if (MoveAssignOperator->willHaveBody() || MoveAssignOperator->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = MoveAssignOperator->getParent(); - - if (ClassDecl->isInvalidDecl() || MoveAssignOperator->isInvalidDecl()) { + if (ClassDecl->isInvalidDecl()) { MoveAssignOperator->setInvalidDecl(); return; } - MoveAssignOperator->markUsed(Context); - - SynthesizedFunctionScope Scope(*this, MoveAssignOperator); - DiagnosticErrorTrap Trap(Diags); - // C++0x [class.copy]p28: // The implicitly-defined or move assignment operator for a non-union class // X performs memberwise move assignment of its subobjects. The direct base @@ -11679,6 +11656,16 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, // from a virtual base more than once. checkMoveAssignmentForRepeatedMove(*this, ClassDecl, CurrentLocation); + SynthesizedFunctionScope Scope(*this, MoveAssignOperator); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + MoveAssignOperator->getType()->castAs<FunctionProtoType>()); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + // The statements that form the synthesized function body. SmallVector<Stmt*, 8> Statements; @@ -11743,8 +11730,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/true, /*Copying=*/false); if (Move.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); MoveAssignOperator->setInvalidDecl(); return; } @@ -11770,8 +11755,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11782,8 +11765,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -11819,8 +11800,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, /*CopyingBaseSubobject=*/false, /*Copying=*/false); if (Move.isInvalid()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); MoveAssignOperator->setInvalidDecl(); return; } @@ -11837,22 +11816,10 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; - else { + else Statements.push_back(Return.getAs<Stmt>()); - - if (Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); - Invalid = true; - } - } } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - MoveAssignOperator->getType()->castAs<FunctionProtoType>()); - if (Invalid) { MoveAssignOperator->setInvalidDecl(); return; @@ -11866,6 +11833,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } MoveAssignOperator->setBody(Body.getAs<Stmt>()); + MoveAssignOperator->markUsed(Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(MoveAssignOperator); @@ -11952,30 +11920,37 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( } void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, - CXXConstructorDecl *CopyConstructor) { + CXXConstructorDecl *CopyConstructor) { assert((CopyConstructor->isDefaulted() && CopyConstructor->isCopyConstructor() && !CopyConstructor->doesThisDeclarationHaveABody() && !CopyConstructor->isDeleted()) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); + if (CopyConstructor->willHaveBody() || CopyConstructor->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); + SynthesizedFunctionScope Scope(*this, CopyConstructor); + + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + CopyConstructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + // C++11 [class.copy]p7: // The [definition of an implicitly declared copy constructor] is // deprecated if the class has a user-declared copy assignment operator // or a user-declared destructor. if (getLangOpts().CPlusPlus11 && CopyConstructor->isImplicit()) - diagnoseDeprecatedCopyOperation(*this, CopyConstructor, CurrentLocation); - - SynthesizedFunctionScope Scope(*this, CopyConstructor); - DiagnosticErrorTrap Trap(Diags); + diagnoseDeprecatedCopyOperation(*this, CopyConstructor); - if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false) || - Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); + if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false)) { CopyConstructor->setInvalidDecl(); } else { SourceLocation Loc = CopyConstructor->getLocEnd().isValid() @@ -11984,16 +11959,9 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, Sema::CompoundScopeRAII CompoundScope(*this); CopyConstructor->setBody( ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>()); + CopyConstructor->markUsed(Context); } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - CopyConstructor->getType()->castAs<FunctionProtoType>()); - - CopyConstructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); - if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyConstructor); } @@ -12075,41 +12043,41 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( } void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, - CXXConstructorDecl *MoveConstructor) { + CXXConstructorDecl *MoveConstructor) { assert((MoveConstructor->isDefaulted() && MoveConstructor->isMoveConstructor() && !MoveConstructor->doesThisDeclarationHaveABody() && !MoveConstructor->isDeleted()) && "DefineImplicitMoveConstructor - call it for implicit move ctor"); + if (MoveConstructor->willHaveBody() || MoveConstructor->isInvalidDecl()) + return; CXXRecordDecl *ClassDecl = MoveConstructor->getParent(); assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor"); SynthesizedFunctionScope Scope(*this, MoveConstructor); - DiagnosticErrorTrap Trap(Diags); - if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false) || - Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXMoveConstructor << Context.getTagDeclType(ClassDecl); + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + MoveConstructor->getType()->castAs<FunctionProtoType>()); + MarkVTableUsed(CurrentLocation, ClassDecl); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + + if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false)) { MoveConstructor->setInvalidDecl(); - } else { + } else { SourceLocation Loc = MoveConstructor->getLocEnd().isValid() ? MoveConstructor->getLocEnd() : MoveConstructor->getLocation(); Sema::CompoundScopeRAII CompoundScope(*this); MoveConstructor->setBody(ActOnCompoundStmt( Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>()); + MoveConstructor->markUsed(Context); } - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(CurrentLocation, - MoveConstructor->getType()->castAs<FunctionProtoType>()); - - MoveConstructor->markUsed(Context); - MarkVTableUsed(CurrentLocation, ClassDecl); - if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(MoveConstructor); } @@ -12122,6 +12090,8 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) { void Sema::DefineImplicitLambdaToFunctionPointerConversion( SourceLocation CurrentLocation, CXXConversionDecl *Conv) { + SynthesizedFunctionScope Scope(*this, Conv); + CXXRecordDecl *Lambda = Conv->getParent(); CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator(); // If we are defining a specialization of a conversion to function-ptr @@ -12144,6 +12114,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( "Conversion operator must have a corresponding call operator"); CallOp = cast<CXXMethodDecl>(CallOpSpec); } + // Mark the call operator referenced (and add to pending instantiations // if necessary). // For both the conversion and static-invoker template specializations @@ -12151,9 +12122,6 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( // to the PendingInstantiations. MarkFunctionReferenced(CurrentLocation, CallOp); - SynthesizedFunctionScope Scope(*this, Conv); - DiagnosticErrorTrap Trap(Diags); - // Retrieve the static invoker... CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker(); // ... and get the corresponding specialization for a generic lambda. @@ -12191,7 +12159,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); L->CompletedImplicitDefinition(Invoker); - } + } } @@ -12202,10 +12170,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( { assert(!Conv->getParent()->isGenericLambda()); - Conv->markUsed(Context); - SynthesizedFunctionScope Scope(*this, Conv); - DiagnosticErrorTrap Trap(Diags); // Copy-initialize the lambda object as needed to capture it. Expr *This = ActOnCXXThis(CurrentLocation).get(); @@ -12244,6 +12209,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( Conv->setBody(new (Context) CompoundStmt(Context, ReturnS, Conv->getLocation(), Conv->getLocation())); + Conv->markUsed(Context); // We're done; notify the mutation listener, if any. if (ASTMutationListener *L = getASTMutationListener()) { @@ -13971,6 +13937,11 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { MD->setDefaulted(); MD->setExplicitlyDefaulted(); + // Unset that we will have a body for this function. We might not, + // if it turns out to be trivial, and we don't need this marking now + // that we've marked it as defaulted. + MD->setWillHaveBody(false); + // If this definition appears within the record, do the checking when // the record is complete. const FunctionDecl *Primary = MD; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 14efc9672061..759c82eeaa07 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -366,8 +366,18 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) return true; + } - if (diagnoseArgIndependentDiagnoseIfAttrs(FD, Loc)) + auto getReferencedObjCProp = [](const NamedDecl *D) -> + const ObjCPropertyDecl * { + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->findPropertyDecl(); + return nullptr; + }; + if (const ObjCPropertyDecl *ObjCPDecl = getReferencedObjCProp(D)) { + if (diagnoseArgIndependentDiagnoseIfAttrs(ObjCPDecl, Loc)) + return true; + } else if (diagnoseArgIndependentDiagnoseIfAttrs(D, Loc)) { return true; } @@ -15742,6 +15752,13 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( if (Spec != AvailSpecs.end()) Version = Spec->getVersion(); + // The use of `@available` in the enclosing function should be analyzed to + // warn when it's used inappropriately (i.e. not if(@available)). + if (getCurFunctionOrMethodDecl()) + getEnclosingFunction()->HasPotentialAvailabilityViolations = true; + else if (getCurBlock() || getCurLambda()) + getCurFunction()->HasPotentialAvailabilityViolations = true; + return new (Context) ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); } diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 7a9a8ff911aa..4b1d7fd3cf23 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -1591,6 +1591,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, // its constexpr-ness, supressing diagnostics while doing so. if (getLangOpts().CPlusPlus1z && !CallOperator->isInvalidDecl() && !CallOperator->isConstexpr() && + !isa<CoroutineBodyStmt>(CallOperator->getBody()) && !Class->getDeclContext()->isDependentContext()) { TentativeAnalysisScope DiagnosticScopeGuard(*this); CallOperator->setConstexpr( diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 678817f02996..c97da740e4d2 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -4929,8 +4929,6 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) { void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, MissingImportKind MIK, bool Recover) { - assert(!isVisible(Decl) && "missing import for non-hidden decl?"); - // Suggest importing a module providing the definition of this entity, if // possible. NamedDecl *Def = getDefinitionToImport(Decl); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 51794160278c..1ba84034fa47 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -6242,11 +6242,11 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, } template <typename CheckFn> -static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const FunctionDecl *FD, +static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const NamedDecl *ND, bool ArgDependent, SourceLocation Loc, CheckFn &&IsSuccessful) { SmallVector<const DiagnoseIfAttr *, 8> Attrs; - for (const auto *DIA : FD->specific_attrs<DiagnoseIfAttr>()) { + for (const auto *DIA : ND->specific_attrs<DiagnoseIfAttr>()) { if (ArgDependent == DIA->getArgDependent()) Attrs.push_back(DIA); } @@ -6293,16 +6293,16 @@ bool Sema::diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function, // EvaluateWithSubstitution only cares about the position of each // argument in the arg list, not the ParmVarDecl* it maps to. if (!DIA->getCond()->EvaluateWithSubstitution( - Result, Context, DIA->getParent(), Args, ThisArg)) + Result, Context, cast<FunctionDecl>(DIA->getParent()), Args, ThisArg)) return false; return Result.isInt() && Result.getInt().getBoolValue(); }); } -bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function, +bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND, SourceLocation Loc) { return diagnoseDiagnoseIfAttrsWith( - *this, Function, /*ArgDependent=*/false, Loc, + *this, ND, /*ArgDependent=*/false, Loc, [&](const DiagnoseIfAttr *DIA) { bool Result; return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) && diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 2d44489023ef..a654ca800b05 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -197,6 +197,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case DefaultTemplateArgumentChecking: case DeclaringSpecialMember: + case DefiningSynthesizedFunction: return false; } @@ -624,6 +625,17 @@ void Sema::PrintInstantiationStack() { diag::note_in_declaration_of_implicit_special_member) << cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember; break; + + case CodeSynthesisContext::DefiningSynthesizedFunction: + // FIXME: For synthesized members other than special members, produce a note. + auto *MD = dyn_cast<CXXMethodDecl>(Active->Entity); + auto CSM = MD ? getSpecialMember(MD) : CXXInvalid; + if (CSM != CXXInvalid) { + Diags.Report(Active->PointOfInstantiation, + diag::note_member_synthesized_at) + << CSM << Context.getTagDeclType(MD->getParent()); + } + break; } } } @@ -666,6 +678,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { return Active->DeductionInfo; case CodeSynthesisContext::DeclaringSpecialMember: + case CodeSynthesisContext::DefiningSynthesizedFunction: // This happens in a context unrelated to template instantiation, so // there is no SFINAE. return None; diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index f4a97f55789e..a65584e3c912 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -6945,6 +6945,19 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { if (DeallocRes.isInvalid()) return StmtError(); Builder.Deallocate = DeallocRes.get(); + + assert(S->getResultDecl() && "ResultDecl must already be built"); + StmtResult ResultDecl = getDerived().TransformStmt(S->getResultDecl()); + if (ResultDecl.isInvalid()) + return StmtError(); + Builder.ResultDecl = ResultDecl.get(); + + if (auto *ReturnStmt = S->getReturnStmt()) { + StmtResult Res = getDerived().TransformStmt(ReturnStmt); + if (Res.isInvalid()) + return StmtError(); + Builder.ReturnStmt = Res.get(); + } } return getDerived().RebuildCoroutineBodyStmt(Builder); diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp index 5a44061cbd4c..9e9689e6b252 100644 --- a/lib/Tooling/CommonOptionsParser.cpp +++ b/lib/Tooling/CommonOptionsParser.cpp @@ -116,7 +116,11 @@ CommonOptionsParser::CommonOptionsParser( cl::HideUnrelatedOptions(Category); - Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv)); + std::string ErrorMessage; + Compilations = + FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage); + if (!Compilations && !ErrorMessage.empty()) + llvm::errs() << ErrorMessage; cl::ParseCommandLineOptions(argc, argv, Overview); cl::PrintOptionValues(); @@ -125,7 +129,6 @@ CommonOptionsParser::CommonOptionsParser( SourcePathList.empty()) return; if (!Compilations) { - std::string ErrorMessage; if (!BuildPath.empty()) { Compilations = CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage); diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp index 8ca0b2df7013..77c5b547ca09 100644 --- a/lib/Tooling/CompilationDatabase.cpp +++ b/lib/Tooling/CompilationDatabase.cpp @@ -27,6 +27,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" #include <sstream> #include <system_error> using namespace clang; @@ -150,23 +151,21 @@ private: // options. class UnusedInputDiagConsumer : public DiagnosticConsumer { public: - UnusedInputDiagConsumer() : Other(nullptr) {} - - // Useful for debugging, chain diagnostics to another consumer after - // recording for our own purposes. - UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {} + UnusedInputDiagConsumer(DiagnosticConsumer &Other) : Other(Other) {} void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override { if (Info.getID() == clang::diag::warn_drv_input_file_unused) { // Arg 1 for this diagnostic is the option that didn't get used. UnusedInputs.push_back(Info.getArgStdStr(0)); + } else if (DiagLevel >= DiagnosticsEngine::Error) { + // If driver failed to create compilation object, show the diagnostics + // to user. + Other.HandleDiagnostic(DiagLevel, Info); } - if (Other) - Other->HandleDiagnostic(DiagLevel, Info); } - DiagnosticConsumer *Other; + DiagnosticConsumer &Other; SmallVector<std::string, 2> UnusedInputs; }; @@ -205,9 +204,12 @@ private: /// \li false if \c Args cannot be used for compilation jobs (e.g. /// contains an option like -E or -version). static bool stripPositionalArgs(std::vector<const char *> Args, - std::vector<std::string> &Result) { + std::vector<std::string> &Result, + std::string &ErrorMsg) { IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); - UnusedInputDiagConsumer DiagClient; + llvm::raw_string_ostream Output(ErrorMsg); + TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts); + UnusedInputDiagConsumer DiagClient(DiagnosticPrinter); DiagnosticsEngine Diagnostics( IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts, &DiagClient, false); @@ -245,6 +247,8 @@ static bool stripPositionalArgs(std::vector<const char *> Args, const std::unique_ptr<driver::Compilation> Compilation( NewDriver->BuildCompilation(Args)); + if (!Compilation) + return false; const driver::JobList &Jobs = Compilation->getJobs(); @@ -258,8 +262,7 @@ static bool stripPositionalArgs(std::vector<const char *> Args, } if (CompileAnalyzer.Inputs.empty()) { - // No compile jobs found. - // FIXME: Emit a warning of some kind? + ErrorMsg = "warning: no compile jobs found\n"; return false; } @@ -280,8 +283,14 @@ static bool stripPositionalArgs(std::vector<const char *> Args, return true; } -FixedCompilationDatabase *FixedCompilationDatabase::loadFromCommandLine( - int &Argc, const char *const *Argv, Twine Directory) { +std::unique_ptr<FixedCompilationDatabase> +FixedCompilationDatabase::loadFromCommandLine(int &Argc, + const char *const *Argv, + std::string &ErrorMsg, + Twine Directory) { + ErrorMsg.clear(); + if (Argc == 0) + return nullptr; const char *const *DoubleDash = std::find(Argv, Argv + Argc, StringRef("--")); if (DoubleDash == Argv + Argc) return nullptr; @@ -289,9 +298,10 @@ FixedCompilationDatabase *FixedCompilationDatabase::loadFromCommandLine( Argc = DoubleDash - Argv; std::vector<std::string> StrippedArgs; - if (!stripPositionalArgs(CommandLine, StrippedArgs)) + if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg)) return nullptr; - return new FixedCompilationDatabase(Directory, StrippedArgs); + return std::unique_ptr<FixedCompilationDatabase>( + new FixedCompilationDatabase(Directory, StrippedArgs)); } FixedCompilationDatabase:: diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp index 9e1181281f13..2e093dd9afc8 100644 --- a/lib/Tooling/Tooling.cpp +++ b/lib/Tooling/Tooling.cpp @@ -260,6 +260,8 @@ bool ToolInvocation::run() { Driver->setCheckInputsExist(false); const std::unique_ptr<clang::driver::Compilation> Compilation( Driver->BuildCompilation(llvm::makeArrayRef(Argv))); + if (!Compilation) + return false; const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments( &Diagnostics, Compilation.get()); if (!CC1Args) { |