diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-05-08 17:13:11 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-05-08 17:13:11 +0000 |
commit | 0a5fb09b599c1bdea3cd11168bb8f4ff4040316e (patch) | |
tree | 5e94367d1a8032322c6871cfe16714c0982fd61a /lib | |
parent | f0c0337bbfb63d1f9edf145aab535bdf82c20454 (diff) | |
download | src-0a5fb09b599c1bdea3cd11168bb8f4ff4040316e.tar.gz src-0a5fb09b599c1bdea3cd11168bb8f4ff4040316e.zip |
Vendor import of clang trunk r302418:vendor/clang/clang-trunk-r302418
Notes
Notes:
svn path=/vendor/clang/dist/; revision=317951
svn path=/vendor/clang/clang-trunk-r302418/; revision=317952; tag=vendor/clang/clang-trunk-r302418
Diffstat (limited to 'lib')
46 files changed, 1349 insertions, 281 deletions
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 6f935620888f..26743d86f5e7 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -153,6 +153,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(cxxRecordDecl); REGISTER_MATCHER(cxxReinterpretCastExpr); REGISTER_MATCHER(cxxStaticCastExpr); + REGISTER_MATCHER(cxxStdInitializerListExpr); REGISTER_MATCHER(cxxTemporaryObjectExpr); REGISTER_MATCHER(cxxThisExpr); REGISTER_MATCHER(cxxThrowExpr); diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 6bdef78c074f..c355445dc1e7 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -146,10 +146,9 @@ void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1, } void DiagnosticsEngine::ReportDelayed() { - Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2; + unsigned ID = DelayedDiagID; DelayedDiagID = 0; - DelayedDiagArg1.clear(); - DelayedDiagArg2.clear(); + Report(ID) << DelayedDiagArg1 << DelayedDiagArg2; } void DiagnosticsEngine::DiagStateMap::appendFirst( @@ -420,11 +419,10 @@ bool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force) { } // Clear out the current diagnostic object. - unsigned DiagID = CurDiagID; Clear(); // If there was a delayed diagnostic, emit it now. - if (!Force && DelayedDiagID && DelayedDiagID != DiagID) + if (!Force && DelayedDiagID) ReportDelayed(); return Emitted; diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp index 2852b40026c2..ce493c1e5cab 100644 --- a/lib/Basic/DiagnosticIDs.cpp +++ b/lib/Basic/DiagnosticIDs.cpp @@ -666,6 +666,10 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const { } } + // Make sure we set FatalErrorOccurred to ensure that the notes from the + // diagnostic that caused `fatal_too_many_errors` won't be emitted. + if (Diag.CurDiagID == diag::fatal_too_many_errors) + Diag.FatalErrorOccurred = true; // Finally, report it. EmitDiag(Diag, DiagLevel); return true; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 78b03b1c314a..33eb0b05ddcd 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -2591,6 +2591,7 @@ class X86TargetInfo : public TargetInfo { bool HasRDSEED = false; bool HasADX = false; bool HasTBM = false; + bool HasLWP = false; bool HasFMA = false; bool HasF16C = false; bool HasAVX512CD = false; @@ -3363,6 +3364,7 @@ bool X86TargetInfo::initFeatureMap( case CK_BDVER1: // xop implies avx, sse4a and fma4. setFeatureEnabledImpl(Features, "xop", true); + setFeatureEnabledImpl(Features, "lwp", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); @@ -3634,6 +3636,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, HasADX = true; } else if (Feature == "+tbm") { HasTBM = true; + } else if (Feature == "+lwp") { + HasLWP = true; } else if (Feature == "+fma") { HasFMA = true; } else if (Feature == "+f16c") { @@ -3949,6 +3953,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasTBM) Builder.defineMacro("__TBM__"); + if (HasLWP) + Builder.defineMacro("__LWP__"); + if (HasMWAITX) Builder.defineMacro("__MWAITX__"); @@ -4132,6 +4139,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("sse4.2", SSELevel >= SSE42) .Case("sse4a", XOPLevel >= SSE4A) .Case("tbm", HasTBM) + .Case("lwp", HasLWP) .Case("x86", true) .Case("x86_32", getTriple().getArch() == llvm::Triple::x86) .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64) @@ -5443,6 +5451,7 @@ public: .Case("softfloat", SoftFloat) .Case("thumb", isThumb()) .Case("neon", (FPU & NeonFPU) && !SoftFloat) + .Case("vfp", FPU && !SoftFloat) .Case("hwdiv", HWDiv & HWDivThumb) .Case("hwdiv-arm", HWDiv & HWDivARM) .Default(false); diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 03883805199f..0d96f2efa60a 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -185,6 +185,7 @@ static void addSanitizerCoveragePass(const PassManagerBuilder &Builder, Opts.Use8bitCounters = CGOpts.SanitizeCoverage8bitCounters; Opts.TracePC = CGOpts.SanitizeCoverageTracePC; Opts.TracePCGuard = CGOpts.SanitizeCoverageTracePCGuard; + Opts.NoPrune = CGOpts.SanitizeCoverageNoPrune; PM.add(createSanitizerCoverageModulePass(Opts)); } @@ -974,10 +975,14 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M, // via a WriteIndexesThinBackend. FunctionImporter::ImportMapTy ImportList; for (auto &GlobalList : *CombinedIndex) { + // Ignore entries for undefined references. + if (GlobalList.second.SummaryList.empty()) + continue; + auto GUID = GlobalList.first; - assert(GlobalList.second.size() == 1 && + assert(GlobalList.second.SummaryList.size() == 1 && "Expected individual combined index to have one summary per GUID"); - auto &Summary = GlobalList.second[0]; + auto &Summary = GlobalList.second.SummaryList[0]; // Skip the summaries for the importing module. These are included to // e.g. record required linkage changes. if (Summary->modulePath() == M->getModuleIdentifier()) diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 791a57e61f53..2b2a92dd6019 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -623,9 +623,13 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) { // For const-qualified captures, emit clang.arc.use to ensure the captured // object doesn't get released while we are still depending on its validity // within the block. - if (VT.isConstQualified() && VT.getObjCLifetime() == Qualifiers::OCL_Strong) + if (VT.isConstQualified() && + VT.getObjCLifetime() == Qualifiers::OCL_Strong && + CGF.CGM.getCodeGenOpts().OptimizationLevel != 0) { + assert(CGF.CGM.getLangOpts().ObjCAutoRefCount && + "expected ObjC ARC to be enabled"); destroyer = CodeGenFunction::emitARCIntrinsicUse; - else if (dtorKind == QualType::DK_objc_strong_lifetime) { + } else if (dtorKind == QualType::DK_objc_strong_lifetime) { destroyer = CodeGenFunction::destroyARCStrongImprecise; } else { destroyer = CGF.getDestroyer(dtorKind); diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 6ea0a325a429..2f05c0e910e5 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -2751,7 +2751,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // Push a clang.arc.use cleanup for each object in RetainableOperands. The // cleanup will cause the use to appear after the final log call, keeping - // the object valid while it’s held in the log buffer. Note that if there’s + // the object valid while it's held in the log buffer. Note that if there's // a release cleanup on the object, it will already be active; since // cleanups are emitted in reverse order, the use will occur before the // object is released. diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 6e6eb7d7f13c..7b42850df968 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -658,34 +658,42 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD, GenOpenCLArgMetadata(FD, Fn, CGM, Context, Builder, getContext()); if (const VecTypeHintAttr *A = FD->getAttr<VecTypeHintAttr>()) { - QualType hintQTy = A->getTypeHint(); - const ExtVectorType *hintEltQTy = hintQTy->getAs<ExtVectorType>(); - bool isSignedInteger = - hintQTy->isSignedIntegerType() || - (hintEltQTy && hintEltQTy->getElementType()->isSignedIntegerType()); - llvm::Metadata *attrMDArgs[] = { + QualType HintQTy = A->getTypeHint(); + const ExtVectorType *HintEltQTy = HintQTy->getAs<ExtVectorType>(); + bool IsSignedInteger = + HintQTy->isSignedIntegerType() || + (HintEltQTy && HintEltQTy->getElementType()->isSignedIntegerType()); + llvm::Metadata *AttrMDArgs[] = { llvm::ConstantAsMetadata::get(llvm::UndefValue::get( CGM.getTypes().ConvertType(A->getTypeHint()))), llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( llvm::IntegerType::get(Context, 32), - llvm::APInt(32, (uint64_t)(isSignedInteger ? 1 : 0))))}; - Fn->setMetadata("vec_type_hint", llvm::MDNode::get(Context, attrMDArgs)); + llvm::APInt(32, (uint64_t)(IsSignedInteger ? 1 : 0))))}; + Fn->setMetadata("vec_type_hint", llvm::MDNode::get(Context, AttrMDArgs)); } if (const WorkGroupSizeHintAttr *A = FD->getAttr<WorkGroupSizeHintAttr>()) { - llvm::Metadata *attrMDArgs[] = { + llvm::Metadata *AttrMDArgs[] = { llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())), llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())), llvm::ConstantAsMetadata::get(Builder.getInt32(A->getZDim()))}; - Fn->setMetadata("work_group_size_hint", llvm::MDNode::get(Context, attrMDArgs)); + Fn->setMetadata("work_group_size_hint", llvm::MDNode::get(Context, AttrMDArgs)); } if (const ReqdWorkGroupSizeAttr *A = FD->getAttr<ReqdWorkGroupSizeAttr>()) { - llvm::Metadata *attrMDArgs[] = { + llvm::Metadata *AttrMDArgs[] = { llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())), llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())), llvm::ConstantAsMetadata::get(Builder.getInt32(A->getZDim()))}; - Fn->setMetadata("reqd_work_group_size", llvm::MDNode::get(Context, attrMDArgs)); + Fn->setMetadata("reqd_work_group_size", llvm::MDNode::get(Context, AttrMDArgs)); + } + + if (const OpenCLIntelReqdSubGroupSizeAttr *A = + FD->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) { + llvm::Metadata *AttrMDArgs[] = { + llvm::ConstantAsMetadata::get(Builder.getInt32(A->getSubGroupSize()))}; + Fn->setMetadata("intel_reqd_sub_group_size", + llvm::MDNode::get(Context, AttrMDArgs)); } } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index b69640894f11..459841aee5a2 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1413,16 +1413,8 @@ private: /// True if we need emit the life-time markers. const bool ShouldEmitLifetimeMarkers; - /// Add a kernel metadata node to the named metadata node 'opencl.kernels'. - /// In the kernel metadata node, reference the kernel function and metadata - /// nodes for its optional attribute qualifiers (OpenCL 1.1 6.7.2): - /// - A node for the vec_type_hint(<type>) qualifier contains string - /// "vec_type_hint", an undefined value of the <type> data type, - /// and a Boolean that is true if the <type> is integer and signed. - /// - A node for the work_group_size_hint(X,Y,Z) qualifier contains string - /// "work_group_size_hint", and three 32-bit integers X, Y and Z. - /// - A node for the reqd_work_group_size(X,Y,Z) qualifier contains string - /// "reqd_work_group_size", and three 32-bit integers X, Y and Z. + /// Add OpenCL kernel arg metadata and the kernel attribute meatadata to + /// the function metadata. void EmitOpenCLKernelMetadata(const FunctionDecl *FD, llvm::Function *Fn); diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index ecd81d84b1fa..4ebbef7dfb5b 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -4890,10 +4890,16 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const { // Empty records are always ignored on Darwin, but actually passed in C++ mode // elsewhere for GNU compatibility. - if (isEmptyRecord(getContext(), Ty, true)) { + uint64_t Size = getContext().getTypeSize(Ty); + bool IsEmpty = isEmptyRecord(getContext(), Ty, true); + if (IsEmpty || Size == 0) { if (!getContext().getLangOpts().CPlusPlus || isDarwinPCS()) return ABIArgInfo::getIgnore(); + // GNU C mode. The only argument that gets ignored is an empty one with size + // 0. + if (IsEmpty && Size == 0) + return ABIArgInfo::getIgnore(); return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); } @@ -4906,7 +4912,6 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const { } // Aggregates <= 16 bytes are passed directly in registers or on the stack. - uint64_t Size = getContext().getTypeSize(Ty); if (Size <= 128) { // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of // same size and alignment. @@ -4946,7 +4951,8 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const { : ABIArgInfo::getDirect()); } - if (isEmptyRecord(getContext(), RetTy, true)) + uint64_t Size = getContext().getTypeSize(RetTy); + if (isEmptyRecord(getContext(), RetTy, true) || Size == 0) return ABIArgInfo::getIgnore(); const Type *Base = nullptr; @@ -4956,7 +4962,6 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const { return ABIArgInfo::getDirect(); // Aggregates <= 16 bytes are returned directly in registers or on the stack. - uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 128) { // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of // same size and alignment. diff --git a/lib/Driver/Distro.cpp b/lib/Driver/Distro.cpp index d305b179449f..2df297f3cfc2 100644 --- a/lib/Driver/Distro.cpp +++ b/lib/Driver/Distro.cpp @@ -47,6 +47,7 @@ static Distro::DistroType DetectDistro(vfs::FileSystem &VFS) { .Case("xenial", Distro::UbuntuXenial) .Case("yakkety", Distro::UbuntuYakkety) .Case("zesty", Distro::UbuntuZesty) + .Case("artful", Distro::UbuntuArtful) .Default(Distro::UnknownDistro); if (Version != Distro::UnknownDistro) return Version; diff --git a/lib/Driver/Multilib.cpp b/lib/Driver/Multilib.cpp index 43b62f7b3612..16a81603b31e 100644 --- a/lib/Driver/Multilib.cpp +++ b/lib/Driver/Multilib.cpp @@ -80,6 +80,10 @@ Multilib &Multilib::includeSuffix(StringRef S) { return *this; } +LLVM_DUMP_METHOD void Multilib::dump() const { + print(llvm::errs()); +} + void Multilib::print(raw_ostream &OS) const { assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/')); if (GCCSuffix.empty()) @@ -270,6 +274,10 @@ bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const { return false; } +LLVM_DUMP_METHOD void MultilibSet::dump() const { + print(llvm::errs()); +} + void MultilibSet::print(raw_ostream &OS) const { for (const Multilib &M : *this) OS << M << "\n"; diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index 4dd4929c9148..c298302c477c 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -55,6 +55,7 @@ enum CoverageFeature { Coverage8bitCounters = 1 << 8, CoverageTracePC = 1 << 9, CoverageTracePCGuard = 1 << 10, + CoverageNoPrune = 1 << 11, }; /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any @@ -629,7 +630,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"), std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"), std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"), - std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard")}; + std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard"), + std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune")}; for (auto F : CoverageFlags) { if (CoverageFeatures & F.first) CmdArgs.push_back(Args.MakeArgString(F.second)); @@ -786,6 +788,7 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) { .Case("8bit-counters", Coverage8bitCounters) .Case("trace-pc", CoverageTracePC) .Case("trace-pc-guard", CoverageTracePCGuard) + .Case("no-prune", CoverageNoPrune) .Default(0); if (F == 0) D.Diag(clang::diag::err_drv_unsupported_option_argument) diff --git a/lib/Driver/ToolChains/CrossWindows.cpp b/lib/Driver/ToolChains/CrossWindows.cpp index b030c636adab..d290c62a056a 100644 --- a/lib/Driver/ToolChains/CrossWindows.cpp +++ b/lib/Driver/ToolChains/CrossWindows.cpp @@ -204,7 +204,7 @@ CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D, const llvm::Triple &T, const llvm::opt::ArgList &Args) : Generic_GCC(D, T, Args) { - if (GetCXXStdlibType(Args) == ToolChain::CST_Libstdcxx) { + if (D.CCCIsCXX() && GetCXXStdlibType(Args) == ToolChain::CST_Libstdcxx) { const std::string &SysRoot = D.SysRoot; // libstdc++ resides in /usr/lib, but depends on libgcc which is placed in diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp index d29d826b5f44..f1015e62eec8 100644 --- a/lib/Driver/ToolChains/Gnu.cpp +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -893,6 +893,8 @@ static bool isSoftFloatABI(const ArgList &Args) { A->getValue() == StringRef("soft")); } +/// \p Flag must be a flag accepted by the driver with its leading '-' removed, +// otherwise '-print-multi-lib' will not emit them correctly. static void addMultilibFlag(bool Enabled, const char *const Flag, std::vector<std::string> &Flags) { if (Enabled) @@ -1437,17 +1439,17 @@ static void findAndroidArmMultilibs(const Driver &D, // Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb. FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); Multilib ArmV7Multilib = makeMultilib("/armv7-a") - .flag("+armv7") - .flag("-thumb"); + .flag("+march=armv7-a") + .flag("-mthumb"); Multilib ThumbMultilib = makeMultilib("/thumb") - .flag("-armv7") - .flag("+thumb"); + .flag("-march=armv7-a") + .flag("+mthumb"); Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb") - .flag("+armv7") - .flag("+thumb"); + .flag("+march=armv7-a") + .flag("+mthumb"); Multilib DefaultMultilib = makeMultilib("") - .flag("-armv7") - .flag("-thumb"); + .flag("-march=armv7-a") + .flag("-mthumb"); MultilibSet AndroidArmMultilibs = MultilibSet() .Either(ThumbMultilib, ArmV7Multilib, @@ -1465,8 +1467,8 @@ static void findAndroidArmMultilibs(const Driver &D, bool IsArmV7Mode = (IsArmArch || IsThumbArch) && (llvm::ARM::parseArchVersion(Arch) == 7 || (IsArmArch && Arch == "" && IsV7SubArch)); - addMultilibFlag(IsArmV7Mode, "armv7", Flags); - addMultilibFlag(IsThumbMode, "thumb", Flags); + addMultilibFlag(IsArmV7Mode, "march=armv7-a", Flags); + addMultilibFlag(IsThumbMode, "mthumb", Flags); if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib)) Result.Multilibs = AndroidArmMultilibs; diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index 3b3600fede97..0c5a5284627c 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -53,6 +53,8 @@ namespace format { TYPE(InlineASMColon) \ TYPE(JavaAnnotation) \ TYPE(JsComputedPropertyName) \ + TYPE(JsExponentiation) \ + TYPE(JsExponentiationEqual) \ TYPE(JsFatArrow) \ TYPE(JsNonNullAssertion) \ TYPE(JsTypeColon) \ diff --git a/lib/Format/FormatTokenLexer.cpp b/lib/Format/FormatTokenLexer.cpp index 1acc0c306512..45c3ae1afe5f 100644 --- a/lib/Format/FormatTokenLexer.cpp +++ b/lib/Format/FormatTokenLexer.cpp @@ -74,6 +74,10 @@ void FormatTokenLexer::tryMergePreviousTokens() { static const tok::TokenKind JSShiftEqual[] = {tok::greater, tok::greater, tok::greaterequal}; static const tok::TokenKind JSRightArrow[] = {tok::equal, tok::greater}; + static const tok::TokenKind JSExponentiation[] = {tok::star, tok::star}; + static const tok::TokenKind JSExponentiationEqual[] = {tok::star, + tok::starequal}; + // FIXME: Investigate what token type gives the correct operator priority. if (tryMergeTokens(JSIdentity, TT_BinaryOperator)) return; @@ -83,6 +87,12 @@ void FormatTokenLexer::tryMergePreviousTokens() { return; if (tryMergeTokens(JSRightArrow, TT_JsFatArrow)) return; + if (tryMergeTokens(JSExponentiation, TT_JsExponentiation)) + return; + if (tryMergeTokens(JSExponentiationEqual, TT_JsExponentiationEqual)) { + Tokens.back()->Tok.setKind(tok::starequal); + return; + } } if (Style.Language == FormatStyle::LK_Java) { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index d3ebf48315e2..96854b8fbc1a 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -766,6 +766,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.SanitizeCoverageTracePC = Args.hasArg(OPT_fsanitize_coverage_trace_pc); Opts.SanitizeCoverageTracePCGuard = Args.hasArg(OPT_fsanitize_coverage_trace_pc_guard); + Opts.SanitizeCoverageNoPrune = Args.hasArg(OPT_fsanitize_coverage_no_prune); Opts.SanitizeMemoryTrackOrigins = getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags); Opts.SanitizeMemoryUseAfterDtor = diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index d26b6937b851..1fbb2b054bad 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -136,6 +136,12 @@ void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput, CurrentASTUnit = std::move(AST); } +Module *FrontendAction::getCurrentModule() const { + CompilerInstance &CI = getCompilerInstance(); + return CI.getPreprocessor().getHeaderSearchInfo().lookupModule( + CI.getLangOpts().CurrentModule, /*AllowSearch*/false); +} + std::unique_ptr<ASTConsumer> FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, StringRef InFile) { @@ -188,16 +194,25 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); } -// For preprocessed files, if the first line is the linemarker and specifies -// the original source file name, use that name as the input file name. -static bool ReadOriginalFileName(CompilerInstance &CI, std::string &InputFile) -{ - bool Invalid = false; +/// For preprocessed files, if the first line is the linemarker and specifies +/// the original source file name, use that name as the input file name. +/// Returns the location of the first token after the line marker directive. +/// +/// \param CI The compiler instance. +/// \param InputFile Populated with the filename from the line marker. +/// \param AddLineNote If \c true, add a line note corresponding to this line +/// directive. Only use this if the directive will not actually be +/// visited by the preprocessor. +static SourceLocation ReadOriginalFileName(CompilerInstance &CI, + std::string &InputFile, + bool AddLineNote = false) { auto &SourceMgr = CI.getSourceManager(); auto MainFileID = SourceMgr.getMainFileID(); + + bool Invalid = false; const auto *MainFileBuf = SourceMgr.getBuffer(MainFileID, &Invalid); if (Invalid) - return false; + return SourceLocation(); std::unique_ptr<Lexer> RawLexer( new Lexer(MainFileID, MainFileBuf, SourceMgr, CI.getLangOpts())); @@ -209,19 +224,37 @@ static bool ReadOriginalFileName(CompilerInstance &CI, std::string &InputFile) // we use FILENAME as the input file name. Token T; if (RawLexer->LexFromRawLexer(T) || T.getKind() != tok::hash) - return false; + return SourceLocation(); if (RawLexer->LexFromRawLexer(T) || T.isAtStartOfLine() || T.getKind() != tok::numeric_constant) - return false; + return SourceLocation(); + + unsigned LineNo; + SourceLocation LineNoLoc = T.getLocation(); + if (AddLineNote) { + llvm::SmallString<16> Buffer; + if (Lexer::getSpelling(LineNoLoc, Buffer, SourceMgr, CI.getLangOpts()) + .getAsInteger(10, LineNo)) + return SourceLocation(); + } + RawLexer->LexFromRawLexer(T); if (T.isAtStartOfLine() || T.getKind() != tok::string_literal) - return false; + return SourceLocation(); StringLiteralParser Literal(T, CI.getPreprocessor()); if (Literal.hadError) - return false; + return SourceLocation(); + RawLexer->LexFromRawLexer(T); + if (T.isNot(tok::eof) && !T.isAtStartOfLine()) + return SourceLocation(); InputFile = Literal.GetString().str(); - return true; + + if (AddLineNote) + CI.getSourceManager().AddLineNote( + LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile)); + + return T.getLocation(); } static SmallVectorImpl<char> & @@ -339,42 +372,44 @@ collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, return std::error_code(); } -/// Parse a module map and compute the corresponding real input buffer that -/// should be used to build the module described by that module map and the -/// current module name. -static std::unique_ptr<llvm::MemoryBuffer> -getInputBufferForModuleMap(CompilerInstance &CI, StringRef Filename, - bool IsSystem) { - // Find the module map file. - const FileEntry *ModuleMap = - CI.getFileManager().getFile(Filename, /*openFile*/true); - if (!ModuleMap) { - CI.getDiagnostics().Report(diag::err_module_map_not_found) - << Filename; - return nullptr; - } +static bool +loadModuleMapForModuleBuild(CompilerInstance &CI, StringRef Filename, + bool IsSystem, bool IsPreprocessed, + unsigned &Offset) { + auto &SrcMgr = CI.getSourceManager(); + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); - // Find the module map file from which it was generated, if different. - const FileEntry *OriginalModuleMap = ModuleMap; - StringRef OriginalModuleMapName = CI.getFrontendOpts().OriginalModuleMap; - if (!OriginalModuleMapName.empty()) { - OriginalModuleMap = CI.getFileManager().getFile(OriginalModuleMapName, - /*openFile*/ true); - if (!OriginalModuleMap) { - CI.getDiagnostics().Report(diag::err_module_map_not_found) - << OriginalModuleMapName; - return nullptr; - } + // Map the current input to a file. + FileID ModuleMapID = SrcMgr.getMainFileID(); + const FileEntry *ModuleMap = SrcMgr.getFileEntryForID(ModuleMapID); + + // If the module map is preprocessed, handle the initial line marker; + // line directives are not part of the module map syntax in general. + Offset = 0; + if (IsPreprocessed) { + std::string PresumedModuleMapFile; + SourceLocation EndOfLineMarker = + ReadOriginalFileName(CI, PresumedModuleMapFile, /*AddLineNote*/true); + if (EndOfLineMarker.isValid()) + Offset = CI.getSourceManager().getDecomposedLoc(EndOfLineMarker).second; + // FIXME: Use PresumedModuleMapFile as the MODULE_MAP_FILE in the PCM. } - - // Parse the module map file. - HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); - if (HS.loadModuleMapFile(ModuleMap, IsSystem)) - return nullptr; - + + // Load the module map file. + if (HS.loadModuleMapFile(ModuleMap, IsSystem, ModuleMapID, &Offset)) + return true; + + if (SrcMgr.getBuffer(ModuleMapID)->getBufferSize() == Offset) + Offset = 0; + + return false; +} + +static Module *prepareToBuildModule(CompilerInstance &CI, + StringRef ModuleMapFilename) { if (CI.getLangOpts().CurrentModule.empty()) { CI.getDiagnostics().Report(diag::err_missing_module_name); - + // FIXME: Eventually, we could consider asking whether there was just // a single module described in the module map, and use that as a // default. Then it would be fairly trivial to just "compile" a module @@ -382,21 +417,14 @@ getInputBufferForModuleMap(CompilerInstance &CI, StringRef Filename, return nullptr; } - // If we're being run from the command-line, the module build stack will not - // have been filled in yet, so complete it now in order to allow us to detect - // module cycles. - SourceManager &SourceMgr = CI.getSourceManager(); - if (SourceMgr.getModuleBuildStack().empty()) - SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule, - FullSourceLoc(SourceLocation(), SourceMgr)); - // Dig out the module definition. + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); Module *M = HS.lookupModule(CI.getLangOpts().CurrentModule, /*AllowSearch=*/false); if (!M) { CI.getDiagnostics().Report(diag::err_missing_module) - << CI.getLangOpts().CurrentModule << Filename; - + << CI.getLangOpts().CurrentModule << ModuleMapFilename; + return nullptr; } @@ -417,11 +445,45 @@ getInputBufferForModuleMap(CompilerInstance &CI, StringRef Filename, return nullptr; } - if (OriginalModuleMap != ModuleMap) { - M->IsInferred = true; - HS.getModuleMap().setInferredModuleAllowedBy(M, OriginalModuleMap); + // Inform the preprocessor that includes from within the input buffer should + // be resolved relative to the build directory of the module map file. + CI.getPreprocessor().setMainFileDir(M->Directory); + + // If the module was inferred from a different module map (via an expanded + // umbrella module definition), track that fact. + // FIXME: It would be preferable to fill this in as part of processing + // the module map, rather than adding it after the fact. + StringRef OriginalModuleMapName = CI.getFrontendOpts().OriginalModuleMap; + if (!OriginalModuleMapName.empty()) { + auto *OriginalModuleMap = + CI.getFileManager().getFile(OriginalModuleMapName, + /*openFile*/ true); + if (!OriginalModuleMap) { + CI.getDiagnostics().Report(diag::err_module_map_not_found) + << OriginalModuleMapName; + return nullptr; + } + if (OriginalModuleMap != CI.getSourceManager().getFileEntryForID( + CI.getSourceManager().getMainFileID())) { + M->IsInferred = true; + CI.getPreprocessor().getHeaderSearchInfo().getModuleMap() + .setInferredModuleAllowedBy(M, OriginalModuleMap); + } } + // If we're being run from the command-line, the module build stack will not + // have been filled in yet, so complete it now in order to allow us to detect + // module cycles. + SourceManager &SourceMgr = CI.getSourceManager(); + if (SourceMgr.getModuleBuildStack().empty()) + SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule, + FullSourceLoc(SourceLocation(), SourceMgr)); + return M; +} + +/// Compute the input buffer that should be used to build the specified module. +static std::unique_ptr<llvm::MemoryBuffer> +getInputBufferForModule(CompilerInstance &CI, Module *M) { FileManager &FileMgr = CI.getFileManager(); // Collect the set of #includes we need to build the module. @@ -441,10 +503,6 @@ getInputBufferForModuleMap(CompilerInstance &CI, StringRef Filename, return nullptr; } - // Inform the preprocessor that includes from within the input buffer should - // be resolved relative to the build directory of the module map file. - CI.getPreprocessor().setMainFileDir(M->Directory); - return llvm::MemoryBuffer::getMemBufferCopy( HeaderContents, Module::getModuleInputBufferName()); } @@ -457,7 +515,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, setCompilerInstance(&CI); StringRef InputFile = Input.getFile(); - FrontendInputFile FileToProcess = Input; bool HasBegunSourceFile = false; if (!BeginInvocation(CI)) goto failure; @@ -597,36 +654,45 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, &CI.getPreprocessor()); HasBegunSourceFile = true; + // Initialize the main file entry. + if (!CI.InitializeSourceManager(Input)) + goto failure; + // For module map files, we first parse the module map and synthesize a // "<module-includes>" buffer before more conventional processing. if (Input.getKind().getFormat() == InputKind::ModuleMap) { CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap); - auto Buffer = getInputBufferForModuleMap(CI, InputFile, Input.isSystem()); - if (!Buffer) + unsigned OffsetToContents; + if (loadModuleMapForModuleBuild(CI, Input.getFile(), Input.isSystem(), + Input.isPreprocessed(), OffsetToContents)) goto failure; - Module *CurrentModule = - CI.getPreprocessor().getHeaderSearchInfo().lookupModule( - CI.getLangOpts().CurrentModule, - /*AllowSearch=*/false); - assert(CurrentModule && "no module info for current module"); + auto *CurrentModule = prepareToBuildModule(CI, Input.getFile()); + if (!CurrentModule) + goto failure; + + if (OffsetToContents) + // If the module contents are in the same file, skip to them. + CI.getPreprocessor().setSkipMainFilePreamble(OffsetToContents, true); + else { + // Otherwise, convert the module description to a suitable input buffer. + auto Buffer = getInputBufferForModule(CI, CurrentModule); + if (!Buffer) + goto failure; - // The input that we end up processing is the generated buffer, not the - // module map file itself. - FileToProcess = FrontendInputFile( - Buffer.release(), Input.getKind().withFormat(InputKind::Source), - CurrentModule->IsSystem); + // Reinitialize the main file entry to refer to the new input. + if (!CI.InitializeSourceManager(FrontendInputFile( + Buffer.release(), Input.getKind().withFormat(InputKind::Source), + CurrentModule->IsSystem))) + goto failure; + } } // Initialize the action. if (!BeginSourceFileAction(CI, InputFile)) goto failure; - // Initialize the main file entry. - if (!CI.InitializeSourceManager(FileToProcess)) - goto failure; - // Create the AST context and consumer unless this is a preprocessor only // action. if (!usesPreprocessorOnly()) { @@ -636,13 +702,12 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // For preprocessed files, check if the first line specifies the original // source file name with a linemarker. - std::string OrigFile; + std::string PresumedInputFile = InputFile; if (Input.isPreprocessed()) - if (ReadOriginalFileName(CI, OrigFile)) - InputFile = OrigFile; + ReadOriginalFileName(CI, PresumedInputFile); std::unique_ptr<ASTConsumer> Consumer = - CreateWrappedASTConsumer(CI, InputFile); + CreateWrappedASTConsumer(CI, PresumedInputFile); if (!Consumer) goto failure; diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index dd7c12f60f0e..baaf93b167bc 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -542,6 +542,18 @@ void PrintPreprocessedAction::ExecuteAction() { CI.createDefaultOutputFile(BinaryMode, getCurrentFile()); if (!OS) return; + // If we're preprocessing a module map, start by dumping the contents of the + // module itself before switching to the input buffer. + auto &Input = getCurrentInput(); + if (Input.getKind().getFormat() == InputKind::ModuleMap) { + if (Input.isFile()) + (*OS) << "# 1 \"" << Input.getFile() << "\"\n"; + // FIXME: Include additional information here so that we don't need the + // original source files to exist on disk. + getCurrentModule()->print(*OS); + (*OS) << "#pragma clang module contents\n"; + } + DoPrintPreprocessedInput(CI.getPreprocessor(), OS.get(), CI.getPreprocessorOutputOpts()); } diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index ffedf3cac847..832eaf2926f0 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -174,6 +174,9 @@ public: void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, const MacroDirective *Undef) override; + + void BeginModule(const Module *M); + void EndModule(const Module *M); }; } // end anonymous namespace @@ -372,6 +375,20 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc, } } +/// Handle entering the scope of a module during a module compilation. +void PrintPPOutputPPCallbacks::BeginModule(const Module *M) { + startNewLineIfNeeded(); + OS << "#pragma clang module begin " << M->getFullModuleName(); + setEmittedDirectiveOnThisLine(); +} + +/// Handle leaving the scope of a module during a module compilation. +void PrintPPOutputPPCallbacks::EndModule(const Module *M) { + startNewLineIfNeeded(); + OS << "#pragma clang module end /*" << M->getFullModuleName() << "*/"; + setEmittedDirectiveOnThisLine(); +} + /// Ident - Handle #ident directives when read by the preprocessor. /// void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) { @@ -685,13 +702,27 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, // -traditional-cpp the lexer keeps /all/ whitespace, including comments. SourceLocation StartLoc = Tok.getLocation(); Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength())); - } else if (Tok.is(tok::annot_module_include) || - Tok.is(tok::annot_module_begin) || - Tok.is(tok::annot_module_end)) { + } else if (Tok.is(tok::annot_module_include)) { // PrintPPOutputPPCallbacks::InclusionDirective handles producing // appropriate output here. Ignore this token entirely. PP.Lex(Tok); continue; + } else if (Tok.is(tok::annot_module_begin)) { + // FIXME: We retrieve this token after the FileChanged callback, and + // retrieve the module_end token before the FileChanged callback, so + // we render this within the file and render the module end outside the + // file, but this is backwards from the token locations: the module_begin + // token is at the include location (outside the file) and the module_end + // token is at the EOF location (within the file). + Callbacks->BeginModule( + reinterpret_cast<Module *>(Tok.getAnnotationValue())); + PP.Lex(Tok); + continue; + } else if (Tok.is(tok::annot_module_end)) { + Callbacks->EndModule( + reinterpret_cast<Module *>(Tok.getAnnotationValue())); + PP.Lex(Tok); + continue; } else if (IdentifierInfo *II = Tok.getIdentifierInfo()) { OS << II->getName(); } else if (Tok.isLiteral() && !Tok.needsCleaning() && diff --git a/lib/Frontend/Rewrite/FrontendActions.cpp b/lib/Frontend/Rewrite/FrontendActions.cpp index 2e76e2e3151e..8c5eb161b5ab 100644 --- a/lib/Frontend/Rewrite/FrontendActions.cpp +++ b/lib/Frontend/Rewrite/FrontendActions.cpp @@ -196,6 +196,18 @@ void RewriteIncludesAction::ExecuteAction() { CI.createDefaultOutputFile(true, getCurrentFile()); if (!OS) return; + // If we're preprocessing a module map, start by dumping the contents of the + // module itself before switching to the input buffer. + auto &Input = getCurrentInput(); + if (Input.getKind().getFormat() == InputKind::ModuleMap) { + if (Input.isFile()) + (*OS) << "# 1 \"" << Input.getFile() << "\"\n"; + // FIXME: Include additional information here so that we don't need the + // original source files to exist on disk. + getCurrentModule()->print(*OS); + (*OS) << "#pragma clang module contents\n"; + } + RewriteIncludesInInput(CI.getPreprocessor(), OS.get(), CI.getPreprocessorOutputOpts()); } diff --git a/lib/Frontend/Rewrite/InclusionRewriter.cpp b/lib/Frontend/Rewrite/InclusionRewriter.cpp index ee61f76d029d..d45cbc01df8c 100644 --- a/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ b/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -46,6 +46,8 @@ class InclusionRewriter : public PPCallbacks { std::map<unsigned, IncludedFile> FileIncludes; /// Tracks where inclusions that import modules are found. std::map<unsigned, const Module *> ModuleIncludes; + /// Tracks where inclusions that enter modules (in a module build) are found. + std::map<unsigned, const Module *> ModuleEntryIncludes; /// Used transitively for building up the FileIncludes mapping over the /// various \c PPCallbacks callbacks. SourceLocation LastInclusionLocation; @@ -57,6 +59,11 @@ public: PredefinesBuffer = Buf; } void detectMainFileEOL(); + void handleModuleBegin(Token &Tok) { + assert(Tok.getKind() == tok::annot_module_begin); + ModuleEntryIncludes.insert({Tok.getLocation().getRawEncoding(), + (Module *)Tok.getAnnotationValue()}); + } private: void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, @@ -84,6 +91,7 @@ private: bool &FileExists); const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const; const Module *FindModuleAtLocation(SourceLocation Loc) const; + const Module *FindEnteredModule(SourceLocation Loc) const; StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); }; @@ -211,6 +219,16 @@ InclusionRewriter::FindModuleAtLocation(SourceLocation Loc) const { return nullptr; } +/// Simple lookup for a SourceLocation (specifically one denoting the hash in +/// an inclusion directive) in the map of module entry information. +const Module * +InclusionRewriter::FindEnteredModule(SourceLocation Loc) const { + const auto I = ModuleEntryIncludes.find(Loc.getRawEncoding()); + if (I != ModuleEntryIncludes.end()) + return I->second; + return nullptr; +} + /// Detect the likely line ending style of \p FromFile by examining the first /// newline found within it. static StringRef DetectEOL(const MemoryBuffer &FromFile) { @@ -452,8 +470,18 @@ void InclusionRewriter::Process(FileID FileId, if (const Module *Mod = FindModuleAtLocation(Loc)) WriteImplicitModuleImport(Mod); else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) { + const Module *Mod = FindEnteredModule(Loc); + if (Mod) + OS << "#pragma clang module begin " << Mod->getFullModuleName() + << "\n"; + // Include and recursively process the file. Process(Inc->Id, Inc->FileType); + + if (Mod) + OS << "#pragma clang module end /*" << Mod->getFullModuleName() + << "*/\n"; + // Add line marker to indicate we're returning from an included // file. LineInfoExtra = " 2"; @@ -590,6 +618,8 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, PP.SetMacroExpansionOnlyInDirectives(); do { PP.Lex(Tok); + if (Tok.is(tok::annot_module_begin)) + Rewrite->handleModuleBegin(Tok); } while (Tok.isNot(tok::eof)); Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID())); Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User); diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index 35aff4017e93..6091db08a93b 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -45,6 +45,7 @@ set(files inttypes.h iso646.h limits.h + lwpintrin.h lzcntintrin.h mm3dnow.h mmintrin.h diff --git a/lib/Headers/arm_acle.h b/lib/Headers/arm_acle.h index 8423e62a381b..ab2589798269 100644 --- a/lib/Headers/arm_acle.h +++ b/lib/Headers/arm_acle.h @@ -225,19 +225,49 @@ __rbitl(unsigned long __t) { } /* + * 9.3 16-bit multiplications + */ +#if __ARM_FEATURE_DSP +static __inline__ int32_t __attribute__((__always_inline__,__nodebug__)) +__smulbb(int32_t __a, int32_t __b) { + return __builtin_arm_smulbb(__a, __b); +} +static __inline__ int32_t __attribute__((__always_inline__,__nodebug__)) +__smulbt(int32_t __a, int32_t __b) { + return __builtin_arm_smulbt(__a, __b); +} +static __inline__ int32_t __attribute__((__always_inline__,__nodebug__)) +__smultb(int32_t __a, int32_t __b) { + return __builtin_arm_smultb(__a, __b); +} +static __inline__ int32_t __attribute__((__always_inline__,__nodebug__)) +__smultt(int32_t __a, int32_t __b) { + return __builtin_arm_smultt(__a, __b); +} +static __inline__ int32_t __attribute__((__always_inline__,__nodebug__)) +__smulwb(int32_t __a, int32_t __b) { + return __builtin_arm_smulwb(__a, __b); +} +static __inline__ int32_t __attribute__((__always_inline__,__nodebug__)) +__smulwt(int32_t __a, int32_t __b) { + return __builtin_arm_smulwt(__a, __b); +} +#endif + +/* * 9.4 Saturating intrinsics * * FIXME: Change guard to their corrosponding __ARM_FEATURE flag when Q flag * intrinsics are implemented and the flag is enabled. */ /* 9.4.1 Width-specified saturation intrinsics */ -#if __ARM_32BIT_STATE +#if __ARM_FEATURE_SAT #define __ssat(x, y) __builtin_arm_ssat(x, y) #define __usat(x, y) __builtin_arm_usat(x, y) #endif /* 9.4.2 Saturating addition and subtraction intrinsics */ -#if __ARM_32BIT_STATE +#if __ARM_FEATURE_DSP static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) __qadd(int32_t __t, int32_t __v) { return __builtin_arm_qadd(__t, __v); @@ -254,6 +284,290 @@ __qdbl(int32_t __t) { } #endif +/* 9.4.3 Accumultating multiplications */ +#if __ARM_FEATURE_DSP +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smlabb(int32_t __a, int32_t __b, int32_t __c) { + return __builtin_arm_smlabb(__a, __b, __c); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smlabt(int32_t __a, int32_t __b, int32_t __c) { + return __builtin_arm_smlabt(__a, __b, __c); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smlatb(int32_t __a, int32_t __b, int32_t __c) { + return __builtin_arm_smlatb(__a, __b, __c); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smlatt(int32_t __a, int32_t __b, int32_t __c) { + return __builtin_arm_smlatt(__a, __b, __c); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smlawb(int32_t __a, int32_t __b, int32_t __c) { + return __builtin_arm_smlawb(__a, __b, __c); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smlawt(int32_t __a, int32_t __b, int32_t __c) { + return __builtin_arm_smlawt(__a, __b, __c); +} +#endif + + +/* 9.5.4 Parallel 16-bit saturation */ +#if __ARM_FEATURE_SIMD32 +#define __ssat16(x, y) __builtin_arm_ssat16(x, y) +#define __usat16(x, y) __builtin_arm_usat16(x, y) +#endif + +/* 9.5.5 Packing and unpacking */ +#if __ARM_FEATURE_SIMD32 +typedef int32_t int8x4_t; +typedef int32_t int16x2_t; +typedef uint32_t uint8x4_t; +typedef uint32_t uint16x2_t; + +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__sxtab16(int16x2_t __a, int8x4_t __b) { + return __builtin_arm_sxtab16(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__sxtb16(int8x4_t __a) { + return __builtin_arm_sxtb16(__a); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__uxtab16(int16x2_t __a, int8x4_t __b) { + return __builtin_arm_uxtab16(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__uxtb16(int8x4_t __a) { + return __builtin_arm_uxtb16(__a); +} +#endif + +/* 9.5.6 Parallel selection */ +#if __ARM_FEATURE_SIMD32 +static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__)) +__sel(uint8x4_t __a, uint8x4_t __b) { + return __builtin_arm_sel(__a, __b); +} +#endif + +/* 9.5.7 Parallel 8-bit addition and subtraction */ +#if __ARM_FEATURE_SIMD32 +static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__)) +__qadd8(int8x4_t __a, int8x4_t __b) { + return __builtin_arm_qadd8(__a, __b); +} +static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__)) +__qsub8(int8x4_t __a, int8x4_t __b) { + return __builtin_arm_qsub8(__a, __b); +} +static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__)) +__sadd8(int8x4_t __a, int8x4_t __b) { + return __builtin_arm_sadd8(__a, __b); +} +static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__)) +__shadd8(int8x4_t __a, int8x4_t __b) { + return __builtin_arm_shadd8(__a, __b); +} +static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__)) +__shsub8(int8x4_t __a, int8x4_t __b) { + return __builtin_arm_shsub8(__a, __b); +} +static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__)) +__ssub8(int8x4_t __a, int8x4_t __b) { + return __builtin_arm_ssub8(__a, __b); +} +static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__)) +__uadd8(uint8x4_t __a, uint8x4_t __b) { + return __builtin_arm_uadd8(__a, __b); +} +static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__)) +__uhadd8(uint8x4_t __a, uint8x4_t __b) { + return __builtin_arm_uhadd8(__a, __b); +} +static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__)) +__uhsub8(uint8x4_t __a, uint8x4_t __b) { + return __builtin_arm_uhsub8(__a, __b); +} +static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__)) +__uqadd8(uint8x4_t __a, uint8x4_t __b) { + return __builtin_arm_uqadd8(__a, __b); +} +static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__)) +__uqsub8(uint8x4_t __a, uint8x4_t __b) { + return __builtin_arm_uqsub8(__a, __b); +} +static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__)) +__usub8(uint8x4_t __a, uint8x4_t __b) { + return __builtin_arm_usub8(__a, __b); +} +#endif + +/* 9.5.8 Sum of 8-bit absolute differences */ +#if __ARM_FEATURE_SIMD32 +static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__)) +__usad8(uint8x4_t __a, uint8x4_t __b) { + return __builtin_arm_usad8(__a, __b); +} +static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__)) +__usada8(uint8x4_t __a, uint8x4_t __b, uint32_t __c) { + return __builtin_arm_usada8(__a, __b, __c); +} +#endif + +/* 9.5.9 Parallel 16-bit addition and subtraction */ +#if __ARM_FEATURE_SIMD32 +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__qadd16(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_qadd16(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__qasx(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_qasx(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__qsax(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_qsax(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__qsub16(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_qsub16(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__sadd16(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_sadd16(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__sasx(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_sasx(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__shadd16(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_shadd16(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__shasx(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_shasx(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__shsax(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_shsax(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__shsub16(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_shsub16(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__ssax(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_ssax(__a, __b); +} +static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__)) +__ssub16(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_ssub16(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__uadd16(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_uadd16(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__uasx(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_uasx(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__uhadd16(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_uhadd16(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__uhasx(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_uhasx(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__uhsax(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_uhsax(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__uhsub16(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_uhsub16(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__uqadd16(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_uqadd16(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__uqasx(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_uqasx(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__uqsax(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_uqsax(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__uqsub16(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_uqsub16(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__usax(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_usax(__a, __b); +} +static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__)) +__usub16(uint16x2_t __a, uint16x2_t __b) { + return __builtin_arm_usub16(__a, __b); +} +#endif + +/* 9.5.10 Parallel 16-bit multiplications */ +#if __ARM_FEATURE_SIMD32 +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smlad(int16x2_t __a, int16x2_t __b, int32_t __c) { + return __builtin_arm_smlad(__a, __b, __c); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smladx(int16x2_t __a, int16x2_t __b, int32_t __c) { + return __builtin_arm_smladx(__a, __b, __c); +} +static __inline__ int64_t __attribute__((__always_inline__, __nodebug__)) +__smlald(int16x2_t __a, int16x2_t __b, int64_t __c) { + return __builtin_arm_smlald(__a, __b, __c); +} +static __inline__ int64_t __attribute__((__always_inline__, __nodebug__)) +__smlaldx(int16x2_t __a, int16x2_t __b, int64_t __c) { + return __builtin_arm_smlaldx(__a, __b, __c); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smlsd(int16x2_t __a, int16x2_t __b, int32_t __c) { + return __builtin_arm_smlsd(__a, __b, __c); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smlsdx(int16x2_t __a, int16x2_t __b, int32_t __c) { + return __builtin_arm_smlsdx(__a, __b, __c); +} +static __inline__ int64_t __attribute__((__always_inline__, __nodebug__)) +__smlsld(int16x2_t __a, int16x2_t __b, int64_t __c) { + return __builtin_arm_smlsld(__a, __b, __c); +} +static __inline__ int64_t __attribute__((__always_inline__, __nodebug__)) +__smlsldx(int16x2_t __a, int16x2_t __b, int64_t __c) { + return __builtin_arm_smlsldx(__a, __b, __c); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smuad(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_smuad(__a, __b); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smuadx(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_smuadx(__a, __b); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smusd(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_smusd(__a, __b); +} +static __inline__ int32_t __attribute__((__always_inline__, __nodebug__)) +__smusdx(int16x2_t __a, int16x2_t __b) { + return __builtin_arm_smusdx(__a, __b); +} +#endif + /* 9.7 CRC32 intrinsics */ #if __ARM_FEATURE_CRC32 static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__)) diff --git a/lib/Headers/lwpintrin.h b/lib/Headers/lwpintrin.h new file mode 100644 index 000000000000..c95fdd9a201a --- /dev/null +++ b/lib/Headers/lwpintrin.h @@ -0,0 +1,150 @@ +/*===---- lwpintrin.h - LWP 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 __X86INTRIN_H +#error "Never use <lwpintrin.h> directly; include <x86intrin.h> instead." +#endif + +#ifndef __LWPINTRIN_H +#define __LWPINTRIN_H + +/* Define the default attributes for the functions in this file. */ +#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("lwp"))) + +/// \brief Parses the LWPCB at the specified address and enables +/// profiling if valid. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the <c> LLWPCB </c> instruction. +/// +/// \param __addr +/// Address to the new Lightweight Profiling Control Block (LWPCB). If the +/// LWPCB is valid, writes the address into the LWP_CBADDR MSR and enables +/// Lightweight Profiling. +static __inline__ void __DEFAULT_FN_ATTRS +__llwpcb (void *__addr) +{ + __builtin_ia32_llwpcb(__addr); +} + +/// \brief Flushes the LWP state to memory and returns the address of the LWPCB. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the <c> SLWPCB </c> instruction. +/// +/// \return +/// Address to the current Lightweight Profiling Control Block (LWPCB). +/// If LWP is not currently enabled, returns NULL. +static __inline__ void* __DEFAULT_FN_ATTRS +__slwpcb () +{ + return __builtin_ia32_slwpcb(); +} + +/// \brief Inserts programmed event record into the LWP event ring buffer +/// and advances the ring buffer pointer. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the <c> LWPINS </c> instruction. +/// +/// \param DATA2 +/// A 32-bit value is zero-extended and inserted into the 64-bit Data2 field. +/// \param DATA1 +/// A 32-bit value is inserted into the 32-bit Data1 field. +/// \param FLAGS +/// A 32-bit immediate value is inserted into the 32-bit Flags field. +/// \returns If the ring buffer is full and LWP is running in Synchronized Mode, +/// the event record overwrites the last record in the buffer, the MissedEvents +/// counter in the LWPCB is incremented, the head pointer is not advanced, and +/// 1 is returned. Otherwise 0 is returned. +#define __lwpins32(DATA2, DATA1, FLAGS) \ + (__builtin_ia32_lwpins32((unsigned int) (DATA2), (unsigned int) (DATA1), \ + (unsigned int) (FLAGS))) + +/// \brief Decrements the LWP programmed value sample event counter. If the result is +/// negative, inserts an event record into the LWP event ring buffer in memory +/// and advances the ring buffer pointer. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the <c> LWPVAL </c> instruction. +/// +/// \param DATA2 +/// A 32-bit value is zero-extended and inserted into the 64-bit Data2 field. +/// \param DATA1 +/// A 32-bit value is inserted into the 32-bit Data1 field. +/// \param FLAGS +/// A 32-bit immediate value is inserted into the 32-bit Flags field. +#define __lwpval32(DATA2, DATA1, FLAGS) \ + (__builtin_ia32_lwpval32((unsigned int) (DATA2), (unsigned int) (DATA1), \ + (unsigned int) (FLAGS))) + +#ifdef __x86_64__ + +/// \brief Inserts programmed event record into the LWP event ring buffer +/// and advances the ring buffer pointer. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the <c> LWPINS </c> instruction. +/// +/// \param DATA2 +/// A 64-bit value is inserted into the 64-bit Data2 field. +/// \param DATA1 +/// A 32-bit value is inserted into the 32-bit Data1 field. +/// \param FLAGS +/// A 32-bit immediate value is inserted into the 32-bit Flags field. +/// \returns If the ring buffer is full and LWP is running in Synchronized Mode, +/// the event record overwrites the last record in the buffer, the MissedEvents +/// counter in the LWPCB is incremented, the head pointer is not advanced, and +/// 1 is returned. Otherwise 0 is returned. +#define __lwpins64(DATA2, DATA1, FLAGS) \ + (__builtin_ia32_lwpins64((unsigned long long) (DATA2), (unsigned int) (DATA1), \ + (unsigned int) (FLAGS))) + +/// \brief Decrements the LWP programmed value sample event counter. If the result is +/// negative, inserts an event record into the LWP event ring buffer in memory +/// and advances the ring buffer pointer. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the <c> LWPVAL </c> instruction. +/// +/// \param DATA2 +/// A 64-bit value is and inserted into the 64-bit Data2 field. +/// \param DATA1 +/// A 32-bit value is inserted into the 32-bit Data1 field. +/// \param FLAGS +/// A 32-bit immediate value is inserted into the 32-bit Flags field. +#define __lwpval64(DATA2, DATA1, FLAGS) \ + (__builtin_ia32_lwpval64((unsigned long long) (DATA2), (unsigned int) (DATA1), \ + (unsigned int) (FLAGS))) + +#endif + +#undef __DEFAULT_FN_ATTRS + +#endif /* __LWPINTRIN_H */ diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h index 2003029cb5a8..ef1d02948c8b 100644 --- a/lib/Headers/x86intrin.h +++ b/lib/Headers/x86intrin.h @@ -72,6 +72,10 @@ #include <tbmintrin.h> #endif +#if !defined(_MSC_VER) || __has_feature(modules) || defined(__LWP__) +#include <lwpintrin.h> +#endif + #if !defined(_MSC_VER) || __has_feature(modules) || defined(__F16C__) #include <f16cintrin.h> #endif diff --git a/lib/Index/IndexDecl.cpp b/lib/Index/IndexDecl.cpp index e8b2f1052d73..7de70a10b692 100644 --- a/lib/Index/IndexDecl.cpp +++ b/lib/Index/IndexDecl.cpp @@ -184,9 +184,7 @@ public: continue; } Relations.emplace_back( - SymbolRoleSet(SymbolRole::RelationOverrideOf) | - SymbolRoleSet(SymbolRole::RelationSpecializationOf), - ND); + SymbolRoleSet(SymbolRole::RelationSpecializationOf), ND); } } } diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index bd425a07c33a..f5b7c59e446f 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -1325,7 +1325,8 @@ static const FileEntry *getPrivateModuleMap(const FileEntry *File, return FileMgr.getFile(PrivateFilename); } -bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) { +bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem, + FileID ID, unsigned *Offset) { // Find the directory for the module. For frameworks, that may require going // up from the 'Modules' directory. const DirectoryEntry *Dir = nullptr; @@ -1344,7 +1345,7 @@ bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) { } } - switch (loadModuleMapFileImpl(File, IsSystem, Dir)) { + switch (loadModuleMapFileImpl(File, IsSystem, Dir, ID, Offset)) { case LMM_AlreadyLoaded: case LMM_NewlyLoaded: return false; @@ -1357,7 +1358,8 @@ bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) { HeaderSearch::LoadModuleMapResult HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem, - const DirectoryEntry *Dir) { + const DirectoryEntry *Dir, FileID ID, + unsigned *Offset) { assert(File && "expected FileEntry"); // Check whether we've already loaded this module map, and mark it as being @@ -1366,7 +1368,7 @@ HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem, if (!AddResult.second) return AddResult.first->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap; - if (ModMap.parseModuleMapFile(File, IsSystem, Dir)) { + if (ModMap.parseModuleMapFile(File, IsSystem, Dir, ID, Offset)) { LoadedModuleMaps[File] = false; return LMM_InvalidModuleMap; } diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 003c9b5eed1b..3d6fe91115a9 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -452,6 +452,29 @@ bool Lexer::getRawToken(SourceLocation Loc, Token &Result, return false; } +/// Returns the pointer that points to the beginning of line that contains +/// the given offset, or null if the offset if invalid. +static const char *findBeginningOfLine(StringRef Buffer, unsigned Offset) { + const char *BufStart = Buffer.data(); + if (Offset >= Buffer.size()) + return nullptr; + const char *StrData = BufStart + Offset; + + if (StrData[0] == '\n' || StrData[0] == '\r') + return StrData; + + const char *LexStart = StrData; + while (LexStart != BufStart) { + if (LexStart[0] == '\n' || LexStart[0] == '\r') { + ++LexStart; + break; + } + + --LexStart; + } + return LexStart; +} + static SourceLocation getBeginningOfFileToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts) { @@ -467,27 +490,15 @@ static SourceLocation getBeginningOfFileToken(SourceLocation Loc, // Back up from the current location until we hit the beginning of a line // (or the buffer). We'll relex from that point. - const char *BufStart = Buffer.data(); - if (LocInfo.second >= Buffer.size()) - return Loc; - - const char *StrData = BufStart+LocInfo.second; - if (StrData[0] == '\n' || StrData[0] == '\r') + const char *StrData = Buffer.data() + LocInfo.second; + const char *LexStart = findBeginningOfLine(Buffer, LocInfo.second); + if (!LexStart || LexStart == StrData) return Loc; - - const char *LexStart = StrData; - while (LexStart != BufStart) { - if (LexStart[0] == '\n' || LexStart[0] == '\r') { - ++LexStart; - break; - } - - --LexStart; - } // Create a lexer starting at the beginning of this token. SourceLocation LexerStartLoc = Loc.getLocWithOffset(-LocInfo.second); - Lexer TheLexer(LexerStartLoc, LangOpts, BufStart, LexStart, Buffer.end()); + Lexer TheLexer(LexerStartLoc, LangOpts, Buffer.data(), LexStart, + Buffer.end()); TheLexer.SetCommentRetentionState(true); // Lex tokens until we find the token that contains the source location. @@ -1038,6 +1049,27 @@ bool Lexer::isIdentifierBodyChar(char c, const LangOptions &LangOpts) { return isIdentifierBody(c, LangOpts.DollarIdents); } +StringRef Lexer::getIndentationForLine(SourceLocation Loc, + const SourceManager &SM) { + if (Loc.isInvalid() || Loc.isMacroID()) + return ""; + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + if (LocInfo.first.isInvalid()) + return ""; + bool Invalid = false; + StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return ""; + const char *Line = findBeginningOfLine(Buffer, LocInfo.second); + if (!Line) + return ""; + StringRef Rest = Buffer.substr(Line - Buffer.data()); + size_t NumWhitespaceChars = Rest.find_first_not_of(" \t"); + return NumWhitespaceChars == StringRef::npos + ? "" + : Rest.take_front(NumWhitespaceChars); +} + //===----------------------------------------------------------------------===// // Diagnostics forwarding code. //===----------------------------------------------------------------------===// diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index 512d7dc5de68..70d37d3d7082 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -1132,14 +1132,17 @@ namespace clang { } bool parseModuleMapFile(); + + bool terminatedByDirective() { return false; } + SourceLocation getLocation() { return Tok.getLocation(); } }; } SourceLocation ModuleMapParser::consumeToken() { -retry: SourceLocation Result = Tok.getLocation(); + +retry: Tok.clear(); - Token LToken; L.LexFromRawLexer(LToken); Tok.Location = LToken.getLocation().getRawEncoding(); @@ -1232,9 +1235,28 @@ retry: case tok::comment: goto retry; - + + case tok::hash: + // A module map can be terminated prematurely by + // #pragma clang module contents + // When building the module, we'll treat the rest of the file as the + // contents of the module. + { + auto NextIsIdent = [&](StringRef Str) -> bool { + L.LexFromRawLexer(LToken); + return !LToken.isAtStartOfLine() && LToken.is(tok::raw_identifier) && + LToken.getRawIdentifier() == Str; + }; + if (NextIsIdent("pragma") && NextIsIdent("clang") && + NextIsIdent("module") && NextIsIdent("contents")) { + Tok.Kind = MMToken::EndOfFile; + break; + } + } + LLVM_FALLTHROUGH; + default: - Diags.Report(LToken.getLocation(), diag::err_mmap_unknown_token); + Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token); HadError = true; goto retry; } @@ -1682,7 +1704,8 @@ void ModuleMapParser::parseExternModuleDecl() { File, /*IsSystem=*/false, Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd ? Directory - : File->getDir(), ExternLoc); + : File->getDir(), + FileID(), nullptr, ExternLoc); } /// Whether to add the requirement \p Feature to the module \p M. @@ -2522,28 +2545,45 @@ bool ModuleMapParser::parseModuleMapFile() { } bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem, - const DirectoryEntry *Dir, + const DirectoryEntry *Dir, FileID ID, + unsigned *Offset, SourceLocation ExternModuleLoc) { + assert(Target && "Missing target information"); llvm::DenseMap<const FileEntry *, bool>::iterator Known = ParsedModuleMap.find(File); if (Known != ParsedModuleMap.end()) return Known->second; + // If the module map file wasn't already entered, do so now. + if (ID.isInvalid()) { + auto FileCharacter = IsSystem ? SrcMgr::C_System : SrcMgr::C_User; + ID = SourceMgr.createFileID(File, ExternModuleLoc, FileCharacter); + } + assert(Target && "Missing target information"); - auto FileCharacter = IsSystem ? SrcMgr::C_System : SrcMgr::C_User; - FileID ID = SourceMgr.createFileID(File, ExternModuleLoc, FileCharacter); const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID); if (!Buffer) return ParsedModuleMap[File] = true; + assert((!Offset || *Offset <= Buffer->getBufferSize()) && + "invalid buffer offset"); // Parse this module map file. - Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts); + Lexer L(SourceMgr.getLocForStartOfFile(ID), MMapLangOpts, + Buffer->getBufferStart(), + Buffer->getBufferStart() + (Offset ? *Offset : 0), + Buffer->getBufferEnd()); SourceLocation Start = L.getSourceLocation(); ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir, BuiltinIncludeDir, IsSystem); bool Result = Parser.parseModuleMapFile(); ParsedModuleMap[File] = Result; + if (Offset) { + auto Loc = SourceMgr.getDecomposedLoc(Parser.getLocation()); + assert(Loc.first == ID && "stopped in a different file?"); + *Offset = Loc.second; + } + // Notify callbacks that we parsed it. for (const auto &Cb : Callbacks) Cb->moduleMapFileRead(Start, *File, IsSystem); diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 4826e399afda..06fee8e5b0a8 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -2049,12 +2049,12 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, M->getTopLevelModuleName() == getLangOpts().CurrentModule) return; - assert(!CurSubmodule && "should not have marked this as a module yet"); - CurSubmodule = M; + assert(!CurLexerSubmodule && "should not have marked this as a module yet"); + CurLexerSubmodule = M; // Let the macro handling code know that any future macros are within // the new submodule. - EnterSubmodule(M, HashLoc); + EnterSubmodule(M, HashLoc, /*ForPragma*/false); // Let the parser know that any future declarations are within the new // submodule. @@ -2082,7 +2082,7 @@ void Preprocessor::HandleIncludeNextDirective(SourceLocation HashLoc, } else if (isInPrimaryFile()) { Lookup = nullptr; Diag(IncludeNextTok, diag::pp_include_next_in_primary); - } else if (CurSubmodule) { + } else if (CurLexerSubmodule) { // Start looking up in the directory *after* the one in which the current // file would be found, if any. assert(CurPPLexer && "#include_next directive in macro?"); diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index fcc49b387034..1938328c904d 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -117,7 +117,7 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer, CurLexer.reset(TheLexer); CurPPLexer = TheLexer; CurDirLookup = CurDir; - CurSubmodule = nullptr; + CurLexerSubmodule = nullptr; if (CurLexerKind != CLK_LexAfterModuleImport) CurLexerKind = CLK_Lexer; @@ -142,7 +142,7 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL, CurDirLookup = CurDir; CurPTHLexer.reset(PL); CurPPLexer = CurPTHLexer.get(); - CurSubmodule = nullptr; + CurLexerSubmodule = nullptr; if (CurLexerKind != CLK_LexAfterModuleImport) CurLexerKind = CLK_PTHLexer; @@ -337,6 +337,26 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { assert(!CurTokenLexer && "Ending a file when currently in a macro!"); + // If we have an unclosed module region from a pragma at the end of a + // module, complain and close it now. + // FIXME: This is not correct if we are building a module from PTH. + const bool LeavingSubmodule = CurLexer && CurLexerSubmodule; + if ((LeavingSubmodule || IncludeMacroStack.empty()) && + !BuildingSubmoduleStack.empty() && + BuildingSubmoduleStack.back().IsPragma) { + Diag(BuildingSubmoduleStack.back().ImportLoc, + diag::err_pp_module_begin_without_module_end); + Module *M = LeaveSubmodule(/*ForPragma*/true); + + Result.startToken(); + const char *EndPos = getCurLexerEndPos(); + CurLexer->BufferPtr = EndPos; + CurLexer->FormTokenWithChars(Result, EndPos, tok::annot_module_end); + Result.setAnnotationEndLoc(Result.getLocation()); + Result.setAnnotationValue(M); + return true; + } + // See if this file had a controlling macro. if (CurPPLexer) { // Not ending a macro, ignore it. if (const IdentifierInfo *ControllingMacro = @@ -442,18 +462,17 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { if (Callbacks && !isEndOfMacro && CurPPLexer) ExitedFID = CurPPLexer->getFileID(); - bool LeavingSubmodule = CurSubmodule && CurLexer; if (LeavingSubmodule) { + // We're done with this submodule. + Module *M = LeaveSubmodule(/*ForPragma*/false); + // Notify the parser that we've left the module. const char *EndPos = getCurLexerEndPos(); Result.startToken(); CurLexer->BufferPtr = EndPos; CurLexer->FormTokenWithChars(Result, EndPos, tok::annot_module_end); Result.setAnnotationEndLoc(Result.getLocation()); - Result.setAnnotationValue(CurSubmodule); - - // We're done with this submodule. - LeaveSubmodule(); + Result.setAnnotationValue(M); } // We're done with the #included file. @@ -628,11 +647,13 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) { assert(!FoundLexer && "Lexer should return EOD before EOF in PP mode"); } -void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc) { +void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc, + bool ForPragma) { if (!getLangOpts().ModulesLocalVisibility) { // Just track that we entered this submodule. - BuildingSubmoduleStack.push_back(BuildingSubmoduleInfo( - M, ImportLoc, CurSubmoduleState, PendingModuleMacroNames.size())); + BuildingSubmoduleStack.push_back( + BuildingSubmoduleInfo(M, ImportLoc, ForPragma, CurSubmoduleState, + PendingModuleMacroNames.size())); return; } @@ -673,8 +694,9 @@ void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc) { } // Track that we entered this module. - BuildingSubmoduleStack.push_back(BuildingSubmoduleInfo( - M, ImportLoc, CurSubmoduleState, PendingModuleMacroNames.size())); + BuildingSubmoduleStack.push_back( + BuildingSubmoduleInfo(M, ImportLoc, ForPragma, CurSubmoduleState, + PendingModuleMacroNames.size())); // Switch to this submodule as the current submodule. CurSubmoduleState = &State; @@ -697,7 +719,13 @@ bool Preprocessor::needModuleMacros() const { return getLangOpts().isCompilingModule(); } -void Preprocessor::LeaveSubmodule() { +Module *Preprocessor::LeaveSubmodule(bool ForPragma) { + if (BuildingSubmoduleStack.empty() || + BuildingSubmoduleStack.back().IsPragma != ForPragma) { + assert(ForPragma && "non-pragma module enter/leave mismatch"); + return nullptr; + } + auto &Info = BuildingSubmoduleStack.back(); Module *LeavingMod = Info.M; @@ -711,7 +739,7 @@ void Preprocessor::LeaveSubmodule() { // of pending names for the surrounding submodule. BuildingSubmoduleStack.pop_back(); makeModuleVisible(LeavingMod, ImportLoc); - return; + return LeavingMod; } // Create ModuleMacros for any macros defined in this submodule. @@ -800,4 +828,5 @@ void Preprocessor::LeaveSubmodule() { // A nested #include makes the included submodule visible. makeModuleVisible(LeavingMod, ImportLoc); + return LeavingMod; } diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 196223981d74..6c7663994a49 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -1453,7 +1453,7 @@ static bool EvaluateHasIncludeNext(Token &Tok, } else if (PP.isInPrimaryFile()) { Lookup = nullptr; PP.Diag(Tok, diag::pp_include_next_in_primary); - } else if (PP.getCurrentSubmodule()) { + } else if (PP.getCurrentLexerSubmodule()) { // Start looking up in the directory *after* the one in which the current // file would be found, if any. assert(PP.getCurrentLexer() && "#include_next directive in macro?"); diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index 576151a98b2c..99d56182c1bb 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -534,47 +534,6 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { } } -void Preprocessor::HandlePragmaModuleImport(Token &ImportTok) { - SourceLocation ImportLoc = ImportTok.getLocation(); - - Token Tok; - - llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8> ModuleName; - while (true) { - LexUnexpandedToken(Tok); - if (Tok.isNot(tok::identifier)) { - Diag(Tok.getLocation(), - diag::err_pragma_module_import_expected_module_name) << 0; - return; - } - - ModuleName.emplace_back(Tok.getIdentifierInfo(), Tok.getLocation()); - - LexUnexpandedToken(Tok); - assert(Tok.isNot(tok::eof)); - if (Tok.is(tok::eod)) - break; - if (Tok.isNot(tok::period)) { - Diag(Tok.getLocation(), - diag::err_pragma_module_import_expected_module_name) << 1; - return; - } - } - - // If we have a non-empty module path, load the named module. - Module *Imported = - TheModuleLoader.loadModule(ImportLoc, ModuleName, Module::Hidden, - /*IsIncludeDirective=*/false); - if (!Imported) - return; - - makeModuleVisible(Imported, ImportLoc); - EnterAnnotationToken(SourceRange(ImportLoc, Tok.getLocation()), - tok::annot_module_include, Imported); - if (Callbacks) - Callbacks->moduleImport(ImportLoc, ModuleName, Imported); -} - /// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro. /// Return the IdentifierInfo* associated with the macro to push or pop. IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) { @@ -1342,6 +1301,26 @@ public: } }; +static bool LexModuleName( + Preprocessor &PP, Token &Tok, + llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> + &ModuleName) { + while (true) { + PP.LexUnexpandedToken(Tok); + if (Tok.isAnnotation() || !Tok.getIdentifierInfo()) { + PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name) + << ModuleName.empty(); + return true; + } + + ModuleName.emplace_back(Tok.getIdentifierInfo(), Tok.getLocation()); + + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::period)) + return false; + } +} + /// Handle the clang \#pragma module import extension. The syntax is: /// \code /// #pragma clang module import some.module.name @@ -1350,8 +1329,108 @@ struct PragmaModuleImportHandler : public PragmaHandler { PragmaModuleImportHandler() : PragmaHandler("import") {} void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, - Token &ImportTok) override { - PP.HandlePragmaModuleImport(ImportTok); + Token &Tok) override { + SourceLocation ImportLoc = Tok.getLocation(); + + // Read the module name. + llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8> + ModuleName; + if (LexModuleName(PP, Tok, ModuleName)) + return; + + if (Tok.isNot(tok::eod)) + PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; + + // If we have a non-empty module path, load the named module. + Module *Imported = + PP.getModuleLoader().loadModule(ImportLoc, ModuleName, Module::Hidden, + /*IsIncludeDirective=*/false); + if (!Imported) + return; + + PP.makeModuleVisible(Imported, ImportLoc); + PP.EnterAnnotationToken(SourceRange(ImportLoc, ModuleName.back().second), + tok::annot_module_include, Imported); + if (auto *CB = PP.getPPCallbacks()) + CB->moduleImport(ImportLoc, ModuleName, Imported); + } +}; + +/// Handle the clang \#pragma module begin extension. The syntax is: +/// \code +/// #pragma clang module begin some.module.name +/// ... +/// #pragma clang module end +/// \endcode +struct PragmaModuleBeginHandler : public PragmaHandler { + PragmaModuleBeginHandler() : PragmaHandler("begin") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &Tok) override { + SourceLocation BeginLoc = Tok.getLocation(); + + // Read the module name. + llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8> + ModuleName; + if (LexModuleName(PP, Tok, ModuleName)) + return; + + if (Tok.isNot(tok::eod)) + PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; + + // We can only enter submodules of the current module. + StringRef Current = PP.getLangOpts().CurrentModule; + if (ModuleName.front().first->getName() != Current) { + PP.Diag(ModuleName.front().second, diag::err_pp_module_begin_wrong_module) + << ModuleName.front().first << (ModuleName.size() > 1) + << Current.empty() << Current; + return; + } + + // Find the module we're entering. We require that a module map for it + // be loaded or implicitly loadable. + // FIXME: We could create the submodule here. We'd need to know whether + // it's supposed to be explicit, but not much else. + Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule(Current); + if (!M) { + PP.Diag(ModuleName.front().second, + diag::err_pp_module_begin_no_module_map) << Current; + return; + } + for (unsigned I = 1; I != ModuleName.size(); ++I) { + auto *NewM = M->findSubmodule(ModuleName[I].first->getName()); + if (!NewM) { + PP.Diag(ModuleName[I].second, diag::err_pp_module_begin_no_submodule) + << M->getFullModuleName() << ModuleName[I].first; + return; + } + M = NewM; + } + + // Enter the scope of the submodule. + PP.EnterSubmodule(M, BeginLoc, /*ForPragma*/true); + PP.EnterAnnotationToken(SourceRange(BeginLoc, ModuleName.back().second), + tok::annot_module_begin, M); + } +}; + +/// Handle the clang \#pragma module end extension. +struct PragmaModuleEndHandler : public PragmaHandler { + PragmaModuleEndHandler() : PragmaHandler("end") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &Tok) override { + SourceLocation Loc = Tok.getLocation(); + + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::eod)) + PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; + + Module *M = PP.LeaveSubmodule(/*ForPragma*/true); + if (M) + PP.EnterAnnotationToken(SourceRange(Loc), tok::annot_module_end, M); + else + PP.Diag(Loc, diag::err_pp_module_end_without_module_begin); } }; @@ -1582,6 +1661,8 @@ void Preprocessor::RegisterBuiltinPragmas() { auto *ModuleHandler = new PragmaNamespace("module"); AddPragmaHandler("clang", ModuleHandler); ModuleHandler->AddPragma(new PragmaModuleImportHandler()); + ModuleHandler->AddPragma(new PragmaModuleBeginHandler()); + ModuleHandler->AddPragma(new PragmaModuleEndHandler()); AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler()); AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler()); diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index babef5dcc7ca..e409ab036535 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -85,10 +85,10 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts, LastTokenWasAt(false), ModuleImportExpectsIdentifier(false), CodeCompletionReached(false), CodeCompletionII(nullptr), MainFileDir(nullptr), SkipMainFilePreamble(0, true), CurPPLexer(nullptr), - CurDirLookup(nullptr), CurLexerKind(CLK_Lexer), CurSubmodule(nullptr), - Callbacks(nullptr), CurSubmoduleState(&NullSubmoduleState), - MacroArgCache(nullptr), Record(nullptr), MIChainHead(nullptr), - DeserialMIChainHead(nullptr) { + CurDirLookup(nullptr), CurLexerKind(CLK_Lexer), + CurLexerSubmodule(nullptr), Callbacks(nullptr), + CurSubmoduleState(&NullSubmoduleState), MacroArgCache(nullptr), + Record(nullptr), MIChainHead(nullptr), DeserialMIChainHead(nullptr) { OwnsHeaderSearch = OwnsHeaders; CounterValue = 0; // __COUNTER__ starts at 0. diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index a53c8014ebaf..049e046cece1 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -183,6 +183,12 @@ void TokenLexer::ExpandFunctionArguments() { // preprocessor already verified that the following token is a macro name // when the #define was parsed. const Token &CurTok = Tokens[i]; + // We don't want a space for the next token after a paste + // operator. In valid code, the token will get smooshed onto the + // preceding one anyway. In assembler-with-cpp mode, invalid + // pastes are allowed through: in this case, we do not want the + // extra whitespace to be added. For example, we want ". ## foo" + // -> ".foo" not ". foo". if (i != 0 && !Tokens[i-1].is(tok::hashhash) && CurTok.hasLeadingSpace()) NextTokGetsSpace = true; @@ -317,6 +323,7 @@ void TokenLexer::ExpandFunctionArguments() { const Token *ArgToks = ActualArgs->getUnexpArgument(ArgNo); unsigned NumToks = MacroArgs::getArgLength(ArgToks); if (NumToks) { // Not an empty argument? + bool VaArgsPseudoPaste = false; // If this is the GNU ", ## __VA_ARGS__" extension, and we just learned // that __VA_ARGS__ expands to multiple tokens, avoid a pasting error when // the expander trys to paste ',' with the first token of the __VA_ARGS__ @@ -325,6 +332,7 @@ void TokenLexer::ExpandFunctionArguments() { ResultToks[ResultToks.size()-2].is(tok::comma) && (unsigned)ArgNo == Macro->getNumArgs()-1 && Macro->isVariadic()) { + VaArgsPseudoPaste = true; // Remove the paste operator, report use of the extension. PP.Diag(ResultToks.pop_back_val().getLocation(), diag::ext_paste_comma); } @@ -344,18 +352,16 @@ void TokenLexer::ExpandFunctionArguments() { ResultToks.end()-NumToks, ResultToks.end()); } - // If this token (the macro argument) was supposed to get leading - // whitespace, transfer this information onto the first token of the - // expansion. - // - // Do not do this if the paste operator occurs before the macro argument, - // as in "A ## MACROARG". In valid code, the first token will get - // smooshed onto the preceding one anyway (forming AMACROARG). In - // assembler-with-cpp mode, invalid pastes are allowed through: in this - // case, we do not want the extra whitespace to be added. For example, - // we want ". ## foo" -> ".foo" not ". foo". - if (NextTokGetsSpace) - ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace); + // Transfer the leading whitespace information from the token + // (the macro argument) onto the first token of the + // expansion. Note that we don't do this for the GNU + // pseudo-paste extension ", ## __VA_ARGS__". + if (!VaArgsPseudoPaste) { + ResultToks[ResultToks.size() - NumToks].setFlagValue(Token::StartOfLine, + false); + ResultToks[ResultToks.size() - NumToks].setFlagValue( + Token::LeadingSpace, NextTokGetsSpace); + } NextTokGetsSpace = false; continue; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index b25152a3183e..ad7b319676e9 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -4151,8 +4151,6 @@ void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) { } if (!T.consumeClose()) { - // FIXME: Warn that this syntax is deprecated, with a Fix-It suggesting - // using __declspec(uuid()) instead. Attrs.addNew(UuidIdent, SourceRange(UuidLoc, T.getCloseLocation()), nullptr, SourceLocation(), ArgExprs.data(), ArgExprs.size(), AttributeList::AS_Microsoft); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 94e792c1d17d..2f493fa5fbef 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -383,6 +383,19 @@ void Sema::diagnoseNullableToNonnullConversion(QualType DstType, Diag(Loc, diag::warn_nullability_lost) << SrcType << DstType; } +void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) { + if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer) + return; + if (E->getType()->isNullPtrType()) + return; + // nullptr only exists from C++11 on, so don't warn on its absence earlier. + if (!getLangOpts().CPlusPlus11) + return; + + Diag(E->getLocStart(), diag::warn_zero_as_null_pointer_constant) + << FixItHint::CreateReplacement(E->getSourceRange(), "nullptr"); +} + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// The result is of the given category. @@ -407,6 +420,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, #endif diagnoseNullableToNonnullConversion(Ty, E->getType(), E->getLocStart()); + diagnoseZeroToNullptrConversion(Kind, E); QualType ExprTy = Context.getCanonicalType(E->getType()); QualType TypeTy = Context.getCanonicalType(Ty); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index a206100b89eb..14dd6267b854 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -3652,22 +3652,29 @@ static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn, // and get its parameter list. bool IsVariadic = false; ArrayRef<ParmVarDecl *> Params; - if (BlockScopeInfo *CurBlock = S.getCurBlock()) { - IsVariadic = CurBlock->TheDecl->isVariadic(); - Params = CurBlock->TheDecl->parameters(); - } else if (FunctionDecl *FD = S.getCurFunctionDecl()) { + DeclContext *Caller = S.CurContext; + if (auto *Block = dyn_cast<BlockDecl>(Caller)) { + IsVariadic = Block->isVariadic(); + Params = Block->parameters(); + } else if (auto *FD = dyn_cast<FunctionDecl>(Caller)) { IsVariadic = FD->isVariadic(); Params = FD->parameters(); - } else if (ObjCMethodDecl *MD = S.getCurMethodDecl()) { + } else if (auto *MD = dyn_cast<ObjCMethodDecl>(Caller)) { IsVariadic = MD->isVariadic(); // FIXME: This isn't correct for methods (results in bogus warning). Params = MD->parameters(); + } else if (isa<CapturedDecl>(Caller)) { + // We don't support va_start in a CapturedDecl. + S.Diag(Fn->getLocStart(), diag::err_va_start_captured_stmt); + return true; } else { - llvm_unreachable("unknown va_start context"); + // This must be some other declcontext that parses exprs. + S.Diag(Fn->getLocStart(), diag::err_va_start_outside_function); + return true; } if (!IsVariadic) { - S.Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function); + S.Diag(Fn->getLocStart(), diag::err_va_start_fixed_function); return true; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d4c0783638d1..2612023f59db 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6070,12 +6070,24 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } - // OpenCL v1.2 s6.9.b p4: - // The sampler type cannot be used with the __local and __global address - // space qualifiers. - if (R->isSamplerT() && (R.getAddressSpace() == LangAS::opencl_local || - R.getAddressSpace() == LangAS::opencl_global)) { - Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace); + if (R->isSamplerT()) { + // OpenCL v1.2 s6.9.b p4: + // The sampler type cannot be used with the __local and __global address + // space qualifiers. + if (R.getAddressSpace() == LangAS::opencl_local || + R.getAddressSpace() == LangAS::opencl_global) { + Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace); + } + + // OpenCL v1.2 s6.12.14.1: + // A global sampler must be declared with either the constant address + // space qualifier or with the const qualifier. + if (DC->isTranslationUnit() && + !(R.getAddressSpace() == LangAS::opencl_constant || + R.isConstQualified())) { + Diag(D.getIdentifierLoc(), diag::err_opencl_nonconst_global_sampler); + D.setInvalidType(); + } } // OpenCL v1.2 s6.9.r: @@ -15902,7 +15914,7 @@ void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) { VisibleModules.setVisible(Mod, DirectiveLoc); } -void Sema::ActOnModuleEnd(SourceLocation EofLoc, Module *Mod) { +void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) { if (getLangOpts().ModulesLocalVisibility) { VisibleModules = std::move(ModuleScopes.back().OuterVisibleModules); // Leaving a module hides namespace names, so our visible namespace cache @@ -15914,12 +15926,19 @@ void Sema::ActOnModuleEnd(SourceLocation EofLoc, Module *Mod) { "left the wrong module scope"); ModuleScopes.pop_back(); - // We got to the end of processing a #include of a local module. Create an + // We got to the end of processing a local module. Create an // ImportDecl as we would for an imported module. - FileID File = getSourceManager().getFileID(EofLoc); - assert(File != getSourceManager().getMainFileID() && - "end of submodule in main source file"); - SourceLocation DirectiveLoc = getSourceManager().getIncludeLoc(File); + FileID File = getSourceManager().getFileID(EomLoc); + SourceLocation DirectiveLoc; + if (EomLoc == getSourceManager().getLocForEndOfFile(File)) { + // We reached the end of a #included module header. Use the #include loc. + assert(File != getSourceManager().getMainFileID() && + "end of submodule in main source file"); + DirectiveLoc = getSourceManager().getIncludeLoc(File); + } else { + // We reached an EOM pragma. Use the pragma location. + DirectiveLoc = EomLoc; + } BuildModuleInclude(DirectiveLoc, Mod); } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index bb5434a03a10..97d273f6ddb6 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -2891,6 +2891,28 @@ static void handleWorkGroupSize(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +// Handles intel_reqd_sub_group_size. +static void handleSubGroupSize(Sema &S, Decl *D, const AttributeList &Attr) { + uint32_t SGSize; + const Expr *E = Attr.getArgAsExpr(0); + if (!checkUInt32Argument(S, Attr, E, SGSize)) + return; + if (SGSize == 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero) + << Attr.getName() << E->getSourceRange(); + return; + } + + OpenCLIntelReqdSubGroupSizeAttr *Existing = + D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>(); + if (Existing && Existing->getSubGroupSize() != SGSize) + S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); + + D->addAttr(::new (S.Context) OpenCLIntelReqdSubGroupSizeAttr( + Attr.getRange(), S.Context, SGSize, + Attr.getAttributeSpellingListIndex())); +} + static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) { if (!Attr.hasParsedType()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) @@ -5057,6 +5079,15 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { } } + // FIXME: It'd be nice to also emit a fixit removing uuid(...) (and, if it's + // the only thing in the [] list, the [] too), and add an insertion of + // __declspec(uuid(...)). But sadly, neither the SourceLocs of the commas + // separating attributes nor of the [ and the ] are in the AST. + // Cf "SourceLocations of attribute list delimiters - [[ ... , ... ]] etc" + // on cfe-dev. + if (Attr.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. + S.Diag(Attr.getLoc(), diag::warn_atl_uuid_deprecated); + UuidAttr *UA = S.mergeUuidAttr(D, Attr.getRange(), Attr.getAttributeSpellingListIndex(), StrRef); if (UA) @@ -6157,6 +6188,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ReqdWorkGroupSize: handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, Attr); break; + case AttributeList::AT_OpenCLIntelReqdSubGroupSize: + handleSubGroupSize(S, D, Attr); + break; case AttributeList::AT_VecTypeHint: handleVecTypeHint(S, D, Attr); break; @@ -6521,6 +6555,9 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) << A << ExpectedKernelFunction; D->setInvalidDecl(); + } else if (Attr *A = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) { + Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; + D->setInvalidDecl(); } } } @@ -7104,6 +7141,69 @@ void Sema::EmitAvailabilityWarning(AvailabilityResult AR, namespace { +/// Returns true if the given statement can be a body-like child of \p Parent. +bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) { + switch (Parent->getStmtClass()) { + case Stmt::IfStmtClass: + return cast<IfStmt>(Parent)->getThen() == S || + cast<IfStmt>(Parent)->getElse() == S; + case Stmt::WhileStmtClass: + return cast<WhileStmt>(Parent)->getBody() == S; + case Stmt::DoStmtClass: + return cast<DoStmt>(Parent)->getBody() == S; + case Stmt::ForStmtClass: + return cast<ForStmt>(Parent)->getBody() == S; + case Stmt::CXXForRangeStmtClass: + return cast<CXXForRangeStmt>(Parent)->getBody() == S; + case Stmt::ObjCForCollectionStmtClass: + return cast<ObjCForCollectionStmt>(Parent)->getBody() == S; + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + return cast<SwitchCase>(Parent)->getSubStmt() == S; + default: + return false; + } +} + +class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> { + const Stmt *Target; + +public: + bool VisitStmt(Stmt *S) { return S != Target; } + + /// Returns true if the given statement is present in the given declaration. + static bool isContained(const Stmt *Target, const Decl *D) { + StmtUSEFinder Visitor; + Visitor.Target = Target; + return !Visitor.TraverseDecl(const_cast<Decl *>(D)); + } +}; + +/// Traverses the AST and finds the last statement that used a given +/// declaration. +class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> { + const Decl *D; + +public: + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + if (DRE->getDecl() == D) + return false; + return true; + } + + static const Stmt *findLastStmtThatUsesDecl(const Decl *D, + const CompoundStmt *Scope) { + LastDeclUSEFinder Visitor; + Visitor.D = D; + for (auto I = Scope->body_rbegin(), E = Scope->body_rend(); I != E; ++I) { + const Stmt *S = *I; + if (!Visitor.TraverseStmt(const_cast<Stmt *>(S))) + return S; + } + return nullptr; + } +}; + /// \brief This class implements -Wunguarded-availability. /// /// This is done with a traversal of the AST of a function that makes reference @@ -7119,6 +7219,7 @@ class DiagnoseUnguardedAvailability /// Stack of potentially nested 'if (@available(...))'s. SmallVector<VersionTuple, 8> AvailabilityStack; + SmallVector<const Stmt *, 16> StmtStack; void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range); @@ -7129,6 +7230,15 @@ public: SemaRef.Context.getTargetInfo().getPlatformMinVersion()); } + bool TraverseStmt(Stmt *S) { + if (!S) + return true; + StmtStack.push_back(S); + bool Result = Base::TraverseStmt(S); + StmtStack.pop_back(); + return Result; + } + void IssueDiagnostics(Stmt *S) { TraverseStmt(S); } bool TraverseIfStmt(IfStmt *If); @@ -7186,9 +7296,73 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( SemaRef.Diag(D->getLocation(), diag::note_availability_specified_here) << D << /* partial */ 3; - // FIXME: Replace this with a fixit diagnostic. - SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) - << Range << D; + auto FixitDiag = + SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) + << Range << D + << (SemaRef.getLangOpts().ObjC1 ? /*@available*/ 0 + : /*__builtin_available*/ 1); + + // Find the statement which should be enclosed in the if @available check. + if (StmtStack.empty()) + return; + const Stmt *StmtOfUse = StmtStack.back(); + const CompoundStmt *Scope = nullptr; + for (const Stmt *S : llvm::reverse(StmtStack)) { + if (const auto *CS = dyn_cast<CompoundStmt>(S)) { + Scope = CS; + break; + } + if (isBodyLikeChildStmt(StmtOfUse, S)) { + // The declaration won't be seen outside of the statement, so we don't + // have to wrap the uses of any declared variables in if (@available). + // Therefore we can avoid setting Scope here. + break; + } + StmtOfUse = S; + } + const Stmt *LastStmtOfUse = nullptr; + if (isa<DeclStmt>(StmtOfUse) && Scope) { + for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) { + if (StmtUSEFinder::isContained(StmtStack.back(), D)) { + LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope); + break; + } + } + } + + const SourceManager &SM = SemaRef.getSourceManager(); + SourceLocation IfInsertionLoc = + SM.getExpansionLoc(StmtOfUse->getLocStart()); + SourceLocation StmtEndLoc = + SM.getExpansionRange( + (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getLocEnd()) + .second; + if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc)) + return; + + StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM); + const char *ExtraIndentation = " "; + std::string FixItString; + llvm::raw_string_ostream FixItOS(FixItString); + FixItOS << "if (" << (SemaRef.getLangOpts().ObjC1 ? "@available" + : "__builtin_available") + << "(" << SemaRef.getASTContext().getTargetInfo().getPlatformName() + << " " << Introduced.getAsString() << ", *)) {\n" + << Indentation << ExtraIndentation; + FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str()); + SourceLocation ElseInsertionLoc = Lexer::findLocationAfterToken( + StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(), + /*SkipTrailingWhitespaceAndNewLine=*/false); + if (ElseInsertionLoc.isInvalid()) + ElseInsertionLoc = + Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts()); + FixItOS.str().clear(); + FixItOS << "\n" + << Indentation << "} else {\n" + << Indentation << ExtraIndentation + << "// Fallback on earlier versions\n" + << Indentation << "}"; + FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str()); } } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index fe9ba6f1f811..370461c4a24e 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -4347,10 +4347,8 @@ static void checkObjCMethodX86VectorTypes(Sema &SemaRef, AcceptedInVersion = VersionTuple(/*Major=*/10, /*Minor=*/11); else return; - VersionTuple MethodVersion = Method->getVersionIntroduced(); if (SemaRef.getASTContext().getTargetInfo().getPlatformMinVersion() >= - AcceptedInVersion && - (MethodVersion.empty() || MethodVersion >= AcceptedInVersion)) + AcceptedInVersion) return; SemaRef.Diag(Loc, diag::err_objc_method_unsupported_param_ret_type) << T << (Method->getReturnType()->isVectorType() ? /*return value*/ 1 diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d63151ef6759..849e978e2d86 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5399,9 +5399,11 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // that the callee might not preserve them. This is easy to diagnose here, // but can be very challenging to debug. if (auto *Caller = getCurFunctionDecl()) - if (Caller->hasAttr<ARMInterruptAttr>()) - if (!FDecl || !FDecl->hasAttr<ARMInterruptAttr>()) + if (Caller->hasAttr<ARMInterruptAttr>()) { + bool VFP = Context.getTargetInfo().hasFeature("vfp"); + if (VFP && (!FDecl || !FDecl->hasAttr<ARMInterruptAttr>())) Diag(Fn->getExprLoc(), diag::warn_arm_interrupt_calling_convention); + } // Promote the function operand. // We special-case function promotion here because we only allow promoting diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 9ffc23b5adba..5d7eada28717 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -2828,7 +2828,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, // [...] If the first overload resolution fails or was not performed, or // if the type of the first parameter of the selected constructor is not - // an rvalue reference to the object’s type (possibly cv-qualified), + // an rvalue reference to the object's type (possibly cv-qualified), // overload resolution is performed again, considering the object as an // lvalue. if (!RRefType || diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp index 738e610ed946..f9a230eb63a0 100644 --- a/lib/Tooling/JSONCompilationDatabase.cpp +++ b/lib/Tooling/JSONCompilationDatabase.cpp @@ -146,12 +146,8 @@ class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin { loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override { SmallString<1024> JSONDatabasePath(Directory); llvm::sys::path::append(JSONDatabasePath, "compile_commands.json"); - std::unique_ptr<CompilationDatabase> Database( - JSONCompilationDatabase::loadFromFile( - JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect)); - if (!Database) - return nullptr; - return Database; + return JSONCompilationDatabase::loadFromFile( + JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect); } }; |